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
27struct 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 */
41struct 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
50static const struct camss_format_info formats_rdi_8x16[] = {
51	{ MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 1,
52	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
53	{ MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_VYUY, 1,
54	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
55	{ MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 1,
56	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
57	{ MEDIA_BUS_FMT_YVYU8_1X16, 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
87static const struct camss_format_info formats_rdi_8x96[] = {
88	{ MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 1,
89	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
90	{ MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_VYUY, 1,
91	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
92	{ MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 1,
93	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
94	{ MEDIA_BUS_FMT_YVYU8_1X16, 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
136static const struct camss_format_info formats_rdi_845[] = {
137	{ MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 1,
138	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
139	{ MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_VYUY, 1,
140	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
141	{ MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 1,
142	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
143	{ MEDIA_BUS_FMT_YVYU8_1X16, 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
187static 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_1X16, V4L2_PIX_FMT_NV16, 1,
205	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
206	{ MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_NV16, 1,
207	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
208	{ MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_NV16, 1,
209	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
210	{ MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_NV16, 1,
211	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
212	{ MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_NV61, 1,
213	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
214	{ MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_NV61, 1,
215	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
216	{ MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_NV61, 1,
217	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
218	{ MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_NV61, 1,
219	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
220};
221
222static 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_1X16, V4L2_PIX_FMT_NV16, 1,
240	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
241	{ MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_NV16, 1,
242	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
243	{ MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_NV16, 1,
244	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
245	{ MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_NV16, 1,
246	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
247	{ MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_NV61, 1,
248	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
249	{ MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_NV61, 1,
250	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
251	{ MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_NV61, 1,
252	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
253	{ MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_NV61, 1,
254	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
255	{ MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 1,
256	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
257	{ MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_VYUY, 1,
258	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
259	{ MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 1,
260	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
261	{ MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_YVYU, 1,
262	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
263};
264
265/* -----------------------------------------------------------------------------
266 * Helper functions
267 */
268
269static 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 */
301static 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
326static 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
342static 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	fmt.pad = pad;
357
358	ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
359	if (ret)
360		return ret;
361
362	ret = video_find_format(fmt.format.code,
363				format->fmt.pix_mp.pixelformat,
364				video->formats, video->nformats);
365	if (ret < 0)
366		return ret;
367
368	format->type = video->type;
369
370	return video_mbus_to_pix_mp(&fmt.format, &format->fmt.pix_mp,
371				    &video->formats[ret], video->bpl_alignment);
372}
373
374/* -----------------------------------------------------------------------------
375 * Video queue operations
376 */
377
378static int video_queue_setup(struct vb2_queue *q,
379	unsigned int *num_buffers, unsigned int *num_planes,
380	unsigned int sizes[], struct device *alloc_devs[])
381{
382	struct camss_video *video = vb2_get_drv_priv(q);
383	const struct v4l2_pix_format_mplane *format =
384						&video->active_fmt.fmt.pix_mp;
385	unsigned int i;
386
387	if (*num_planes) {
388		if (*num_planes != format->num_planes)
389			return -EINVAL;
390
391		for (i = 0; i < *num_planes; i++)
392			if (sizes[i] < format->plane_fmt[i].sizeimage)
393				return -EINVAL;
394
395		return 0;
396	}
397
398	*num_planes = format->num_planes;
399
400	for (i = 0; i < *num_planes; i++)
401		sizes[i] = format->plane_fmt[i].sizeimage;
402
403	return 0;
404}
405
406static int video_buf_init(struct vb2_buffer *vb)
407{
408	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
409	struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue);
410	struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer,
411						   vb);
412	const struct v4l2_pix_format_mplane *format =
413						&video->active_fmt.fmt.pix_mp;
414	struct sg_table *sgt;
415	unsigned int i;
416
417	for (i = 0; i < format->num_planes; i++) {
418		sgt = vb2_dma_sg_plane_desc(vb, i);
419		if (!sgt)
420			return -EFAULT;
421
422		buffer->addr[i] = sg_dma_address(sgt->sgl);
423	}
424
425	if (format->pixelformat == V4L2_PIX_FMT_NV12 ||
426			format->pixelformat == V4L2_PIX_FMT_NV21 ||
427			format->pixelformat == V4L2_PIX_FMT_NV16 ||
428			format->pixelformat == V4L2_PIX_FMT_NV61)
429		buffer->addr[1] = buffer->addr[0] +
430				format->plane_fmt[0].bytesperline *
431				format->height;
432
433	return 0;
434}
435
436static int video_buf_prepare(struct vb2_buffer *vb)
437{
438	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
439	struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue);
440	const struct v4l2_pix_format_mplane *format =
441						&video->active_fmt.fmt.pix_mp;
442	unsigned int i;
443
444	for (i = 0; i < format->num_planes; i++) {
445		if (format->plane_fmt[i].sizeimage > vb2_plane_size(vb, i))
446			return -EINVAL;
447
448		vb2_set_plane_payload(vb, i, format->plane_fmt[i].sizeimage);
449	}
450
451	vbuf->field = V4L2_FIELD_NONE;
452
453	return 0;
454}
455
456static void video_buf_queue(struct vb2_buffer *vb)
457{
458	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
459	struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue);
460	struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer,
461						   vb);
462
463	video->ops->queue_buffer(video, buffer);
464}
465
466static int video_check_format(struct camss_video *video)
467{
468	struct v4l2_pix_format_mplane *pix = &video->active_fmt.fmt.pix_mp;
469	struct v4l2_format format;
470	struct v4l2_pix_format_mplane *sd_pix = &format.fmt.pix_mp;
471	int ret;
472
473	sd_pix->pixelformat = pix->pixelformat;
474	ret = video_get_subdev_format(video, &format);
475	if (ret < 0)
476		return ret;
477
478	if (pix->pixelformat != sd_pix->pixelformat ||
479	    pix->height != sd_pix->height ||
480	    pix->width != sd_pix->width ||
481	    pix->num_planes != sd_pix->num_planes ||
482	    pix->field != format.fmt.pix_mp.field)
483		return -EPIPE;
484
485	return 0;
486}
487
488static int video_start_streaming(struct vb2_queue *q, unsigned int count)
489{
490	struct camss_video *video = vb2_get_drv_priv(q);
491	struct video_device *vdev = &video->vdev;
492	struct media_entity *entity;
493	struct media_pad *pad;
494	struct v4l2_subdev *subdev;
495	int ret;
496
497	ret = video_device_pipeline_alloc_start(vdev);
498	if (ret < 0) {
499		dev_err(video->camss->dev, "Failed to start media pipeline: %d\n", ret);
500		goto flush_buffers;
501	}
502
503	ret = video_check_format(video);
504	if (ret < 0)
505		goto error;
506
507	entity = &vdev->entity;
508	while (1) {
509		pad = &entity->pads[0];
510		if (!(pad->flags & MEDIA_PAD_FL_SINK))
511			break;
512
513		pad = media_pad_remote_pad_first(pad);
514		if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
515			break;
516
517		entity = pad->entity;
518		subdev = media_entity_to_v4l2_subdev(entity);
519
520		ret = v4l2_subdev_call(subdev, video, s_stream, 1);
521		if (ret < 0 && ret != -ENOIOCTLCMD)
522			goto error;
523	}
524
525	return 0;
526
527error:
528	video_device_pipeline_stop(vdev);
529
530flush_buffers:
531	video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED);
532
533	return ret;
534}
535
536static void video_stop_streaming(struct vb2_queue *q)
537{
538	struct camss_video *video = vb2_get_drv_priv(q);
539	struct video_device *vdev = &video->vdev;
540	struct media_entity *entity;
541	struct media_pad *pad;
542	struct v4l2_subdev *subdev;
543	int ret;
544
545	entity = &vdev->entity;
546	while (1) {
547		pad = &entity->pads[0];
548		if (!(pad->flags & MEDIA_PAD_FL_SINK))
549			break;
550
551		pad = media_pad_remote_pad_first(pad);
552		if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
553			break;
554
555		entity = pad->entity;
556		subdev = media_entity_to_v4l2_subdev(entity);
557
558		ret = v4l2_subdev_call(subdev, video, s_stream, 0);
559
560		if (entity->use_count > 1) {
561			/* Don't stop if other instances of the pipeline are still running */
562			dev_dbg(video->camss->dev, "Video pipeline still used, don't stop streaming.\n");
563			return;
564		}
565
566		if (ret) {
567			dev_err(video->camss->dev, "Video pipeline stop failed: %d\n", ret);
568			return;
569		}
570	}
571
572	video_device_pipeline_stop(vdev);
573
574	video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR);
575}
576
577static const struct vb2_ops msm_video_vb2_q_ops = {
578	.queue_setup     = video_queue_setup,
579	.wait_prepare    = vb2_ops_wait_prepare,
580	.wait_finish     = vb2_ops_wait_finish,
581	.buf_init        = video_buf_init,
582	.buf_prepare     = video_buf_prepare,
583	.buf_queue       = video_buf_queue,
584	.start_streaming = video_start_streaming,
585	.stop_streaming  = video_stop_streaming,
586};
587
588/* -----------------------------------------------------------------------------
589 * V4L2 ioctls
590 */
591
592static int video_querycap(struct file *file, void *fh,
593			  struct v4l2_capability *cap)
594{
595	strscpy(cap->driver, "qcom-camss", sizeof(cap->driver));
596	strscpy(cap->card, "Qualcomm Camera Subsystem", sizeof(cap->card));
597
598	return 0;
599}
600
601static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
602{
603	struct camss_video *video = video_drvdata(file);
604	int i, j, k;
605	u32 mcode = f->mbus_code;
606
607	if (f->type != video->type)
608		return -EINVAL;
609
610	if (f->index >= video->nformats)
611		return -EINVAL;
612
613	/*
614	 * Find index "i" of "k"th unique pixelformat in formats array.
615	 *
616	 * If f->mbus_code passed to video_enum_fmt() is not zero, a device
617	 * with V4L2_CAP_IO_MC capability restricts enumeration to only the
618	 * pixel formats that can be produced from that media bus code.
619	 * This is implemented by skipping video->formats[] entries with
620	 * code != f->mbus_code (if f->mbus_code is not zero).
621	 * If the f->mbus_code passed to video_enum_fmt() is not supported,
622	 * -EINVAL is returned.
623	 * If f->mbus_code is zero, all the pixel formats are enumerated.
624	 */
625	k = -1;
626	for (i = 0; i < video->nformats; i++) {
627		if (mcode != 0 && video->formats[i].code != mcode)
628			continue;
629
630		for (j = 0; j < i; j++) {
631			if (mcode != 0 && video->formats[j].code != mcode)
632				continue;
633			if (video->formats[i].pixelformat ==
634					video->formats[j].pixelformat)
635				break;
636		}
637
638		if (j == i)
639			k++;
640
641		if (k == f->index)
642			break;
643	}
644
645	if (k == -1 || k < f->index)
646		/*
647		 * All the unique pixel formats matching the arguments
648		 * have been enumerated (k >= 0 and f->index > 0), or
649		 * no pixel formats match the non-zero f->mbus_code (k == -1).
650		 */
651		return -EINVAL;
652
653	f->pixelformat = video->formats[i].pixelformat;
654
655	return 0;
656}
657
658static int video_enum_framesizes(struct file *file, void *fh,
659				 struct v4l2_frmsizeenum *fsize)
660{
661	struct camss_video *video = video_drvdata(file);
662	int i;
663
664	if (fsize->index)
665		return -EINVAL;
666
667	/* Only accept pixel format present in the formats[] table */
668	for (i = 0; i < video->nformats; i++) {
669		if (video->formats[i].pixelformat == fsize->pixel_format)
670			break;
671	}
672
673	if (i == video->nformats)
674		return -EINVAL;
675
676	fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
677	fsize->stepwise.min_width = CAMSS_FRAME_MIN_WIDTH;
678	fsize->stepwise.max_width = CAMSS_FRAME_MAX_WIDTH;
679	fsize->stepwise.min_height = CAMSS_FRAME_MIN_HEIGHT;
680	fsize->stepwise.max_height = (video->line_based) ?
681		CAMSS_FRAME_MAX_HEIGHT_PIX : CAMSS_FRAME_MAX_HEIGHT_RDI;
682	fsize->stepwise.step_width = 1;
683	fsize->stepwise.step_height = 1;
684
685	return 0;
686}
687
688static int video_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
689{
690	struct camss_video *video = video_drvdata(file);
691
692	*f = video->active_fmt;
693
694	return 0;
695}
696
697static int __video_try_fmt(struct camss_video *video, struct v4l2_format *f)
698{
699	struct v4l2_pix_format_mplane *pix_mp;
700	const struct camss_format_info *fi;
701	struct v4l2_plane_pix_format *p;
702	u32 bytesperline[3] = { 0 };
703	u32 sizeimage[3] = { 0 };
704	u32 width, height;
705	u32 bpl, lines;
706	int i, j;
707
708	pix_mp = &f->fmt.pix_mp;
709
710	if (video->line_based)
711		for (i = 0; i < pix_mp->num_planes && i < 3; i++) {
712			p = &pix_mp->plane_fmt[i];
713			bytesperline[i] = clamp_t(u32, p->bytesperline,
714						  1, 65528);
715			sizeimage[i] = clamp_t(u32, p->sizeimage,
716					       bytesperline[i],
717					       bytesperline[i] * CAMSS_FRAME_MAX_HEIGHT_PIX);
718		}
719
720	for (j = 0; j < video->nformats; j++)
721		if (pix_mp->pixelformat == video->formats[j].pixelformat)
722			break;
723
724	if (j == video->nformats)
725		j = 0; /* default format */
726
727	fi = &video->formats[j];
728	width = pix_mp->width;
729	height = pix_mp->height;
730
731	memset(pix_mp, 0, sizeof(*pix_mp));
732
733	pix_mp->pixelformat = fi->pixelformat;
734	pix_mp->width = clamp_t(u32, width, 1, CAMSS_FRAME_MAX_WIDTH);
735	pix_mp->height = clamp_t(u32, height, 1, CAMSS_FRAME_MAX_HEIGHT_RDI);
736	pix_mp->num_planes = fi->planes;
737	for (i = 0; i < pix_mp->num_planes; i++) {
738		bpl = pix_mp->width / fi->hsub[i].numerator *
739			fi->hsub[i].denominator * fi->bpp[i] / 8;
740		bpl = ALIGN(bpl, video->bpl_alignment);
741		pix_mp->plane_fmt[i].bytesperline = bpl;
742		pix_mp->plane_fmt[i].sizeimage = pix_mp->height /
743			fi->vsub[i].numerator * fi->vsub[i].denominator * bpl;
744	}
745
746	pix_mp->field = V4L2_FIELD_NONE;
747	pix_mp->colorspace = V4L2_COLORSPACE_SRGB;
748	pix_mp->flags = 0;
749	pix_mp->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix_mp->colorspace);
750	pix_mp->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
751					pix_mp->colorspace, pix_mp->ycbcr_enc);
752	pix_mp->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix_mp->colorspace);
753
754	if (video->line_based)
755		for (i = 0; i < pix_mp->num_planes; i++) {
756			p = &pix_mp->plane_fmt[i];
757			p->bytesperline = clamp_t(u32, p->bytesperline,
758						  1, 65528);
759			p->sizeimage = clamp_t(u32, p->sizeimage,
760					       p->bytesperline,
761					       p->bytesperline * CAMSS_FRAME_MAX_HEIGHT_PIX);
762			lines = p->sizeimage / p->bytesperline;
763
764			if (p->bytesperline < bytesperline[i])
765				p->bytesperline = ALIGN(bytesperline[i], 8);
766
767			if (p->sizeimage < p->bytesperline * lines)
768				p->sizeimage = p->bytesperline * lines;
769
770			if (p->sizeimage < sizeimage[i])
771				p->sizeimage = sizeimage[i];
772		}
773
774	return 0;
775}
776
777static int video_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
778{
779	struct camss_video *video = video_drvdata(file);
780
781	return __video_try_fmt(video, f);
782}
783
784static int video_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
785{
786	struct camss_video *video = video_drvdata(file);
787	int ret;
788
789	if (vb2_is_busy(&video->vb2_q))
790		return -EBUSY;
791
792	ret = __video_try_fmt(video, f);
793	if (ret < 0)
794		return ret;
795
796	video->active_fmt = *f;
797
798	return 0;
799}
800
801static int video_enum_input(struct file *file, void *fh,
802			    struct v4l2_input *input)
803{
804	if (input->index > 0)
805		return -EINVAL;
806
807	strscpy(input->name, "camera", sizeof(input->name));
808	input->type = V4L2_INPUT_TYPE_CAMERA;
809
810	return 0;
811}
812
813static int video_g_input(struct file *file, void *fh, unsigned int *input)
814{
815	*input = 0;
816
817	return 0;
818}
819
820static int video_s_input(struct file *file, void *fh, unsigned int input)
821{
822	return input == 0 ? 0 : -EINVAL;
823}
824
825static const struct v4l2_ioctl_ops msm_vid_ioctl_ops = {
826	.vidioc_querycap		= video_querycap,
827	.vidioc_enum_fmt_vid_cap	= video_enum_fmt,
828	.vidioc_enum_framesizes		= video_enum_framesizes,
829	.vidioc_g_fmt_vid_cap_mplane	= video_g_fmt,
830	.vidioc_s_fmt_vid_cap_mplane	= video_s_fmt,
831	.vidioc_try_fmt_vid_cap_mplane	= video_try_fmt,
832	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
833	.vidioc_querybuf		= vb2_ioctl_querybuf,
834	.vidioc_qbuf			= vb2_ioctl_qbuf,
835	.vidioc_expbuf			= vb2_ioctl_expbuf,
836	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
837	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
838	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
839	.vidioc_streamon		= vb2_ioctl_streamon,
840	.vidioc_streamoff		= vb2_ioctl_streamoff,
841	.vidioc_enum_input		= video_enum_input,
842	.vidioc_g_input			= video_g_input,
843	.vidioc_s_input			= video_s_input,
844};
845
846/* -----------------------------------------------------------------------------
847 * V4L2 file operations
848 */
849
850static int video_open(struct file *file)
851{
852	struct video_device *vdev = video_devdata(file);
853	struct camss_video *video = video_drvdata(file);
854	struct v4l2_fh *vfh;
855	int ret;
856
857	mutex_lock(&video->lock);
858
859	vfh = kzalloc(sizeof(*vfh), GFP_KERNEL);
860	if (vfh == NULL) {
861		ret = -ENOMEM;
862		goto error_alloc;
863	}
864
865	v4l2_fh_init(vfh, vdev);
866	v4l2_fh_add(vfh);
867
868	file->private_data = vfh;
869
870	ret = v4l2_pipeline_pm_get(&vdev->entity);
871	if (ret < 0) {
872		dev_err(video->camss->dev, "Failed to power up pipeline: %d\n",
873			ret);
874		goto error_pm_use;
875	}
876
877	mutex_unlock(&video->lock);
878
879	return 0;
880
881error_pm_use:
882	v4l2_fh_release(file);
883
884error_alloc:
885	mutex_unlock(&video->lock);
886
887	return ret;
888}
889
890static int video_release(struct file *file)
891{
892	struct video_device *vdev = video_devdata(file);
893
894	vb2_fop_release(file);
895
896	v4l2_pipeline_pm_put(&vdev->entity);
897
898	file->private_data = NULL;
899
900	return 0;
901}
902
903static const struct v4l2_file_operations msm_vid_fops = {
904	.owner          = THIS_MODULE,
905	.unlocked_ioctl = video_ioctl2,
906	.open           = video_open,
907	.release        = video_release,
908	.poll           = vb2_fop_poll,
909	.mmap		= vb2_fop_mmap,
910	.read		= vb2_fop_read,
911};
912
913/* -----------------------------------------------------------------------------
914 * CAMSS video core
915 */
916
917static void msm_video_release(struct video_device *vdev)
918{
919	struct camss_video *video = video_get_drvdata(vdev);
920
921	media_entity_cleanup(&vdev->entity);
922
923	mutex_destroy(&video->q_lock);
924	mutex_destroy(&video->lock);
925
926	if (atomic_dec_and_test(&video->camss->ref_count))
927		camss_delete(video->camss);
928}
929
930/*
931 * msm_video_init_format - Helper function to initialize format
932 * @video: struct camss_video
933 *
934 * Initialize pad format with default value.
935 *
936 * Return 0 on success or a negative error code otherwise
937 */
938static int msm_video_init_format(struct camss_video *video)
939{
940	int ret;
941	struct v4l2_format format = {
942		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
943		.fmt.pix_mp = {
944			.width = 1920,
945			.height = 1080,
946			.pixelformat = video->formats[0].pixelformat,
947		},
948	};
949
950	ret = __video_try_fmt(video, &format);
951	if (ret < 0)
952		return ret;
953
954	video->active_fmt = format;
955
956	return 0;
957}
958
959/*
960 * msm_video_register - Register a video device node
961 * @video: struct camss_video
962 * @v4l2_dev: V4L2 device
963 * @name: name to be used for the video device node
964 *
965 * Initialize and register a video device node to a V4L2 device. Also
966 * initialize the vb2 queue.
967 *
968 * Return 0 on success or a negative error code otherwise
969 */
970
971int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
972		       const char *name, int is_pix)
973{
974	struct media_pad *pad = &video->pad;
975	struct video_device *vdev;
976	struct vb2_queue *q;
977	int ret;
978
979	vdev = &video->vdev;
980
981	mutex_init(&video->q_lock);
982
983	q = &video->vb2_q;
984	q->drv_priv = video;
985	q->mem_ops = &vb2_dma_sg_memops;
986	q->ops = &msm_video_vb2_q_ops;
987	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
988	q->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ;
989	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
990	q->buf_struct_size = sizeof(struct camss_buffer);
991	q->dev = video->camss->dev;
992	q->lock = &video->q_lock;
993	ret = vb2_queue_init(q);
994	if (ret < 0) {
995		dev_err(v4l2_dev->dev, "Failed to init vb2 queue: %d\n", ret);
996		goto error_vb2_init;
997	}
998
999	pad->flags = MEDIA_PAD_FL_SINK;
1000	ret = media_entity_pads_init(&vdev->entity, 1, pad);
1001	if (ret < 0) {
1002		dev_err(v4l2_dev->dev, "Failed to init video entity: %d\n",
1003			ret);
1004		goto error_vb2_init;
1005	}
1006
1007	mutex_init(&video->lock);
1008
1009	switch (video->camss->res->version) {
1010	case 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		break;
1019	case CAMSS_8x96:
1020	case CAMSS_660:
1021		if (is_pix) {
1022			video->formats = formats_pix_8x96;
1023			video->nformats = ARRAY_SIZE(formats_pix_8x96);
1024		} else {
1025			video->formats = formats_rdi_8x96;
1026			video->nformats = ARRAY_SIZE(formats_rdi_8x96);
1027		}
1028		break;
1029	case CAMSS_845:
1030	case CAMSS_8250:
1031		video->formats = formats_rdi_845;
1032		video->nformats = ARRAY_SIZE(formats_rdi_845);
1033		break;
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
1065error_video_register:
1066	media_entity_cleanup(&vdev->entity);
1067	mutex_destroy(&video->lock);
1068error_vb2_init:
1069	mutex_destroy(&video->q_lock);
1070
1071	return ret;
1072}
1073
1074void 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