1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * TI Camera Access Layer (CAL) - Video Device
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2015-2020 Texas Instruments Inc.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Authors:
8*4882a593Smuzhiyun * Benoit Parrot <bparrot@ti.com>
9*4882a593Smuzhiyun * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/delay.h>
13*4882a593Smuzhiyun #include <linux/ioctl.h>
14*4882a593Smuzhiyun #include <linux/pm_runtime.h>
15*4882a593Smuzhiyun #include <linux/videodev2.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <media/media-device.h>
18*4882a593Smuzhiyun #include <media/v4l2-common.h>
19*4882a593Smuzhiyun #include <media/v4l2-ctrls.h>
20*4882a593Smuzhiyun #include <media/v4l2-device.h>
21*4882a593Smuzhiyun #include <media/v4l2-event.h>
22*4882a593Smuzhiyun #include <media/v4l2-fh.h>
23*4882a593Smuzhiyun #include <media/v4l2-ioctl.h>
24*4882a593Smuzhiyun #include <media/videobuf2-core.h>
25*4882a593Smuzhiyun #include <media/videobuf2-dma-contig.h>
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include "cal.h"
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun /* ------------------------------------------------------------------
30*4882a593Smuzhiyun * Format Handling
31*4882a593Smuzhiyun * ------------------------------------------------------------------
32*4882a593Smuzhiyun */
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun static const struct cal_fmt cal_formats[] = {
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_YUYV,
37*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_YUYV8_2X8,
38*4882a593Smuzhiyun .bpp = 16,
39*4882a593Smuzhiyun }, {
40*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_UYVY,
41*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_UYVY8_2X8,
42*4882a593Smuzhiyun .bpp = 16,
43*4882a593Smuzhiyun }, {
44*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_YVYU,
45*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_YVYU8_2X8,
46*4882a593Smuzhiyun .bpp = 16,
47*4882a593Smuzhiyun }, {
48*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_VYUY,
49*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_VYUY8_2X8,
50*4882a593Smuzhiyun .bpp = 16,
51*4882a593Smuzhiyun }, {
52*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
53*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
54*4882a593Smuzhiyun .bpp = 16,
55*4882a593Smuzhiyun }, {
56*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
57*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
58*4882a593Smuzhiyun .bpp = 16,
59*4882a593Smuzhiyun }, {
60*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
61*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
62*4882a593Smuzhiyun .bpp = 16,
63*4882a593Smuzhiyun }, {
64*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
65*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
66*4882a593Smuzhiyun .bpp = 16,
67*4882a593Smuzhiyun }, {
68*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */
69*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_RGB888_2X12_LE,
70*4882a593Smuzhiyun .bpp = 24,
71*4882a593Smuzhiyun }, {
72*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */
73*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_RGB888_2X12_BE,
74*4882a593Smuzhiyun .bpp = 24,
75*4882a593Smuzhiyun }, {
76*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_RGB32, /* argb */
77*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_ARGB8888_1X32,
78*4882a593Smuzhiyun .bpp = 32,
79*4882a593Smuzhiyun }, {
80*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_SBGGR8,
81*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_SBGGR8_1X8,
82*4882a593Smuzhiyun .bpp = 8,
83*4882a593Smuzhiyun }, {
84*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_SGBRG8,
85*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_SGBRG8_1X8,
86*4882a593Smuzhiyun .bpp = 8,
87*4882a593Smuzhiyun }, {
88*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_SGRBG8,
89*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_SGRBG8_1X8,
90*4882a593Smuzhiyun .bpp = 8,
91*4882a593Smuzhiyun }, {
92*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_SRGGB8,
93*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_SRGGB8_1X8,
94*4882a593Smuzhiyun .bpp = 8,
95*4882a593Smuzhiyun }, {
96*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_SBGGR10,
97*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_SBGGR10_1X10,
98*4882a593Smuzhiyun .bpp = 10,
99*4882a593Smuzhiyun }, {
100*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_SGBRG10,
101*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_SGBRG10_1X10,
102*4882a593Smuzhiyun .bpp = 10,
103*4882a593Smuzhiyun }, {
104*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_SGRBG10,
105*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_SGRBG10_1X10,
106*4882a593Smuzhiyun .bpp = 10,
107*4882a593Smuzhiyun }, {
108*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_SRGGB10,
109*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_SRGGB10_1X10,
110*4882a593Smuzhiyun .bpp = 10,
111*4882a593Smuzhiyun }, {
112*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_SBGGR12,
113*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_SBGGR12_1X12,
114*4882a593Smuzhiyun .bpp = 12,
115*4882a593Smuzhiyun }, {
116*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_SGBRG12,
117*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_SGBRG12_1X12,
118*4882a593Smuzhiyun .bpp = 12,
119*4882a593Smuzhiyun }, {
120*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_SGRBG12,
121*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_SGRBG12_1X12,
122*4882a593Smuzhiyun .bpp = 12,
123*4882a593Smuzhiyun }, {
124*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_SRGGB12,
125*4882a593Smuzhiyun .code = MEDIA_BUS_FMT_SRGGB12_1X12,
126*4882a593Smuzhiyun .bpp = 12,
127*4882a593Smuzhiyun },
128*4882a593Smuzhiyun };
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /* Print Four-character-code (FOURCC) */
fourcc_to_str(u32 fmt)131*4882a593Smuzhiyun static char *fourcc_to_str(u32 fmt)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun static char code[5];
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun code[0] = (unsigned char)(fmt & 0xff);
136*4882a593Smuzhiyun code[1] = (unsigned char)((fmt >> 8) & 0xff);
137*4882a593Smuzhiyun code[2] = (unsigned char)((fmt >> 16) & 0xff);
138*4882a593Smuzhiyun code[3] = (unsigned char)((fmt >> 24) & 0xff);
139*4882a593Smuzhiyun code[4] = '\0';
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun return code;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun /* ------------------------------------------------------------------
145*4882a593Smuzhiyun * V4L2 Video IOCTLs
146*4882a593Smuzhiyun * ------------------------------------------------------------------
147*4882a593Smuzhiyun */
148*4882a593Smuzhiyun
find_format_by_pix(struct cal_ctx * ctx,u32 pixelformat)149*4882a593Smuzhiyun static const struct cal_fmt *find_format_by_pix(struct cal_ctx *ctx,
150*4882a593Smuzhiyun u32 pixelformat)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun const struct cal_fmt *fmt;
153*4882a593Smuzhiyun unsigned int k;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun for (k = 0; k < ctx->num_active_fmt; k++) {
156*4882a593Smuzhiyun fmt = ctx->active_fmt[k];
157*4882a593Smuzhiyun if (fmt->fourcc == pixelformat)
158*4882a593Smuzhiyun return fmt;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun return NULL;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
find_format_by_code(struct cal_ctx * ctx,u32 code)164*4882a593Smuzhiyun static const struct cal_fmt *find_format_by_code(struct cal_ctx *ctx,
165*4882a593Smuzhiyun u32 code)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun const struct cal_fmt *fmt;
168*4882a593Smuzhiyun unsigned int k;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun for (k = 0; k < ctx->num_active_fmt; k++) {
171*4882a593Smuzhiyun fmt = ctx->active_fmt[k];
172*4882a593Smuzhiyun if (fmt->code == code)
173*4882a593Smuzhiyun return fmt;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun return NULL;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
cal_querycap(struct file * file,void * priv,struct v4l2_capability * cap)179*4882a593Smuzhiyun static int cal_querycap(struct file *file, void *priv,
180*4882a593Smuzhiyun struct v4l2_capability *cap)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun struct cal_ctx *ctx = video_drvdata(file);
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun strscpy(cap->driver, CAL_MODULE_NAME, sizeof(cap->driver));
185*4882a593Smuzhiyun strscpy(cap->card, CAL_MODULE_NAME, sizeof(cap->card));
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun snprintf(cap->bus_info, sizeof(cap->bus_info),
188*4882a593Smuzhiyun "platform:%s", dev_name(ctx->cal->dev));
189*4882a593Smuzhiyun return 0;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
cal_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)192*4882a593Smuzhiyun static int cal_enum_fmt_vid_cap(struct file *file, void *priv,
193*4882a593Smuzhiyun struct v4l2_fmtdesc *f)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun struct cal_ctx *ctx = video_drvdata(file);
196*4882a593Smuzhiyun const struct cal_fmt *fmt;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun if (f->index >= ctx->num_active_fmt)
199*4882a593Smuzhiyun return -EINVAL;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun fmt = ctx->active_fmt[f->index];
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun f->pixelformat = fmt->fourcc;
204*4882a593Smuzhiyun f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
205*4882a593Smuzhiyun return 0;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun
__subdev_get_format(struct cal_ctx * ctx,struct v4l2_mbus_framefmt * fmt)208*4882a593Smuzhiyun static int __subdev_get_format(struct cal_ctx *ctx,
209*4882a593Smuzhiyun struct v4l2_mbus_framefmt *fmt)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun struct v4l2_subdev_format sd_fmt;
212*4882a593Smuzhiyun struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
213*4882a593Smuzhiyun int ret;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
216*4882a593Smuzhiyun sd_fmt.pad = 0;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun ret = v4l2_subdev_call(ctx->phy->sensor, pad, get_fmt, NULL, &sd_fmt);
219*4882a593Smuzhiyun if (ret)
220*4882a593Smuzhiyun return ret;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun *fmt = *mbus_fmt;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun ctx_dbg(1, ctx, "%s %dx%d code:%04X\n", __func__,
225*4882a593Smuzhiyun fmt->width, fmt->height, fmt->code);
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun return 0;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
__subdev_set_format(struct cal_ctx * ctx,struct v4l2_mbus_framefmt * fmt)230*4882a593Smuzhiyun static int __subdev_set_format(struct cal_ctx *ctx,
231*4882a593Smuzhiyun struct v4l2_mbus_framefmt *fmt)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun struct v4l2_subdev_format sd_fmt;
234*4882a593Smuzhiyun struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
235*4882a593Smuzhiyun int ret;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
238*4882a593Smuzhiyun sd_fmt.pad = 0;
239*4882a593Smuzhiyun *mbus_fmt = *fmt;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun ret = v4l2_subdev_call(ctx->phy->sensor, pad, set_fmt, NULL, &sd_fmt);
242*4882a593Smuzhiyun if (ret)
243*4882a593Smuzhiyun return ret;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun ctx_dbg(1, ctx, "%s %dx%d code:%04X\n", __func__,
246*4882a593Smuzhiyun fmt->width, fmt->height, fmt->code);
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun return 0;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
cal_calc_format_size(struct cal_ctx * ctx,const struct cal_fmt * fmt,struct v4l2_format * f)251*4882a593Smuzhiyun static int cal_calc_format_size(struct cal_ctx *ctx,
252*4882a593Smuzhiyun const struct cal_fmt *fmt,
253*4882a593Smuzhiyun struct v4l2_format *f)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun u32 bpl, max_width;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun if (!fmt) {
258*4882a593Smuzhiyun ctx_dbg(3, ctx, "No cal_fmt provided!\n");
259*4882a593Smuzhiyun return -EINVAL;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun /*
263*4882a593Smuzhiyun * Maximum width is bound by the DMA max width in bytes.
264*4882a593Smuzhiyun * We need to recalculate the actual maxi width depending on the
265*4882a593Smuzhiyun * number of bytes per pixels required.
266*4882a593Smuzhiyun */
267*4882a593Smuzhiyun max_width = MAX_WIDTH_BYTES / (ALIGN(fmt->bpp, 8) >> 3);
268*4882a593Smuzhiyun v4l_bound_align_image(&f->fmt.pix.width, 48, max_width, 2,
269*4882a593Smuzhiyun &f->fmt.pix.height, 32, MAX_HEIGHT_LINES, 0, 0);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun bpl = (f->fmt.pix.width * ALIGN(fmt->bpp, 8)) >> 3;
272*4882a593Smuzhiyun f->fmt.pix.bytesperline = ALIGN(bpl, 16);
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun f->fmt.pix.sizeimage = f->fmt.pix.height *
275*4882a593Smuzhiyun f->fmt.pix.bytesperline;
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun ctx_dbg(3, ctx, "%s: fourcc: %s size: %dx%d bpl:%d img_size:%d\n",
278*4882a593Smuzhiyun __func__, fourcc_to_str(f->fmt.pix.pixelformat),
279*4882a593Smuzhiyun f->fmt.pix.width, f->fmt.pix.height,
280*4882a593Smuzhiyun f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun return 0;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
cal_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)285*4882a593Smuzhiyun static int cal_g_fmt_vid_cap(struct file *file, void *priv,
286*4882a593Smuzhiyun struct v4l2_format *f)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun struct cal_ctx *ctx = video_drvdata(file);
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun *f = ctx->v_fmt;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun return 0;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
cal_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)295*4882a593Smuzhiyun static int cal_try_fmt_vid_cap(struct file *file, void *priv,
296*4882a593Smuzhiyun struct v4l2_format *f)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun struct cal_ctx *ctx = video_drvdata(file);
299*4882a593Smuzhiyun const struct cal_fmt *fmt;
300*4882a593Smuzhiyun struct v4l2_subdev_frame_size_enum fse;
301*4882a593Smuzhiyun int ret, found;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun fmt = find_format_by_pix(ctx, f->fmt.pix.pixelformat);
304*4882a593Smuzhiyun if (!fmt) {
305*4882a593Smuzhiyun ctx_dbg(3, ctx, "Fourcc format (0x%08x) not found.\n",
306*4882a593Smuzhiyun f->fmt.pix.pixelformat);
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun /* Just get the first one enumerated */
309*4882a593Smuzhiyun fmt = ctx->active_fmt[0];
310*4882a593Smuzhiyun f->fmt.pix.pixelformat = fmt->fourcc;
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun f->fmt.pix.field = ctx->v_fmt.fmt.pix.field;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun /* check for/find a valid width/height */
316*4882a593Smuzhiyun ret = 0;
317*4882a593Smuzhiyun found = false;
318*4882a593Smuzhiyun fse.pad = 0;
319*4882a593Smuzhiyun fse.code = fmt->code;
320*4882a593Smuzhiyun fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
321*4882a593Smuzhiyun for (fse.index = 0; ; fse.index++) {
322*4882a593Smuzhiyun ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_size,
323*4882a593Smuzhiyun NULL, &fse);
324*4882a593Smuzhiyun if (ret)
325*4882a593Smuzhiyun break;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun if ((f->fmt.pix.width == fse.max_width) &&
328*4882a593Smuzhiyun (f->fmt.pix.height == fse.max_height)) {
329*4882a593Smuzhiyun found = true;
330*4882a593Smuzhiyun break;
331*4882a593Smuzhiyun } else if ((f->fmt.pix.width >= fse.min_width) &&
332*4882a593Smuzhiyun (f->fmt.pix.width <= fse.max_width) &&
333*4882a593Smuzhiyun (f->fmt.pix.height >= fse.min_height) &&
334*4882a593Smuzhiyun (f->fmt.pix.height <= fse.max_height)) {
335*4882a593Smuzhiyun found = true;
336*4882a593Smuzhiyun break;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun if (!found) {
341*4882a593Smuzhiyun /* use existing values as default */
342*4882a593Smuzhiyun f->fmt.pix.width = ctx->v_fmt.fmt.pix.width;
343*4882a593Smuzhiyun f->fmt.pix.height = ctx->v_fmt.fmt.pix.height;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun /*
347*4882a593Smuzhiyun * Use current colorspace for now, it will get
348*4882a593Smuzhiyun * updated properly during s_fmt
349*4882a593Smuzhiyun */
350*4882a593Smuzhiyun f->fmt.pix.colorspace = ctx->v_fmt.fmt.pix.colorspace;
351*4882a593Smuzhiyun return cal_calc_format_size(ctx, fmt, f);
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
cal_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)354*4882a593Smuzhiyun static int cal_s_fmt_vid_cap(struct file *file, void *priv,
355*4882a593Smuzhiyun struct v4l2_format *f)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun struct cal_ctx *ctx = video_drvdata(file);
358*4882a593Smuzhiyun struct vb2_queue *q = &ctx->vb_vidq;
359*4882a593Smuzhiyun const struct cal_fmt *fmt;
360*4882a593Smuzhiyun struct v4l2_mbus_framefmt mbus_fmt;
361*4882a593Smuzhiyun int ret;
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun if (vb2_is_busy(q)) {
364*4882a593Smuzhiyun ctx_dbg(3, ctx, "%s device busy\n", __func__);
365*4882a593Smuzhiyun return -EBUSY;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun ret = cal_try_fmt_vid_cap(file, priv, f);
369*4882a593Smuzhiyun if (ret < 0)
370*4882a593Smuzhiyun return ret;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun fmt = find_format_by_pix(ctx, f->fmt.pix.pixelformat);
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, fmt->code);
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun ret = __subdev_set_format(ctx, &mbus_fmt);
377*4882a593Smuzhiyun if (ret)
378*4882a593Smuzhiyun return ret;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun /* Just double check nothing has gone wrong */
381*4882a593Smuzhiyun if (mbus_fmt.code != fmt->code) {
382*4882a593Smuzhiyun ctx_dbg(3, ctx,
383*4882a593Smuzhiyun "%s subdev changed format on us, this should not happen\n",
384*4882a593Smuzhiyun __func__);
385*4882a593Smuzhiyun return -EINVAL;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &mbus_fmt);
389*4882a593Smuzhiyun ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
390*4882a593Smuzhiyun ctx->v_fmt.fmt.pix.pixelformat = fmt->fourcc;
391*4882a593Smuzhiyun cal_calc_format_size(ctx, fmt, &ctx->v_fmt);
392*4882a593Smuzhiyun ctx->fmt = fmt;
393*4882a593Smuzhiyun ctx->m_fmt = mbus_fmt;
394*4882a593Smuzhiyun *f = ctx->v_fmt;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun return 0;
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun
cal_enum_framesizes(struct file * file,void * fh,struct v4l2_frmsizeenum * fsize)399*4882a593Smuzhiyun static int cal_enum_framesizes(struct file *file, void *fh,
400*4882a593Smuzhiyun struct v4l2_frmsizeenum *fsize)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun struct cal_ctx *ctx = video_drvdata(file);
403*4882a593Smuzhiyun const struct cal_fmt *fmt;
404*4882a593Smuzhiyun struct v4l2_subdev_frame_size_enum fse;
405*4882a593Smuzhiyun int ret;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun /* check for valid format */
408*4882a593Smuzhiyun fmt = find_format_by_pix(ctx, fsize->pixel_format);
409*4882a593Smuzhiyun if (!fmt) {
410*4882a593Smuzhiyun ctx_dbg(3, ctx, "Invalid pixel code: %x\n",
411*4882a593Smuzhiyun fsize->pixel_format);
412*4882a593Smuzhiyun return -EINVAL;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun fse.index = fsize->index;
416*4882a593Smuzhiyun fse.pad = 0;
417*4882a593Smuzhiyun fse.code = fmt->code;
418*4882a593Smuzhiyun fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_size, NULL,
421*4882a593Smuzhiyun &fse);
422*4882a593Smuzhiyun if (ret)
423*4882a593Smuzhiyun return ret;
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun ctx_dbg(1, ctx, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n",
426*4882a593Smuzhiyun __func__, fse.index, fse.code, fse.min_width, fse.max_width,
427*4882a593Smuzhiyun fse.min_height, fse.max_height);
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
430*4882a593Smuzhiyun fsize->discrete.width = fse.max_width;
431*4882a593Smuzhiyun fsize->discrete.height = fse.max_height;
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun return 0;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun
cal_enum_input(struct file * file,void * priv,struct v4l2_input * inp)436*4882a593Smuzhiyun static int cal_enum_input(struct file *file, void *priv,
437*4882a593Smuzhiyun struct v4l2_input *inp)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun if (inp->index > 0)
440*4882a593Smuzhiyun return -EINVAL;
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun inp->type = V4L2_INPUT_TYPE_CAMERA;
443*4882a593Smuzhiyun sprintf(inp->name, "Camera %u", inp->index);
444*4882a593Smuzhiyun return 0;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
cal_g_input(struct file * file,void * priv,unsigned int * i)447*4882a593Smuzhiyun static int cal_g_input(struct file *file, void *priv, unsigned int *i)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun *i = 0;
450*4882a593Smuzhiyun return 0;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun
cal_s_input(struct file * file,void * priv,unsigned int i)453*4882a593Smuzhiyun static int cal_s_input(struct file *file, void *priv, unsigned int i)
454*4882a593Smuzhiyun {
455*4882a593Smuzhiyun return i > 0 ? -EINVAL : 0;
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun /* timeperframe is arbitrary and continuous */
cal_enum_frameintervals(struct file * file,void * priv,struct v4l2_frmivalenum * fival)459*4882a593Smuzhiyun static int cal_enum_frameintervals(struct file *file, void *priv,
460*4882a593Smuzhiyun struct v4l2_frmivalenum *fival)
461*4882a593Smuzhiyun {
462*4882a593Smuzhiyun struct cal_ctx *ctx = video_drvdata(file);
463*4882a593Smuzhiyun const struct cal_fmt *fmt;
464*4882a593Smuzhiyun struct v4l2_subdev_frame_interval_enum fie = {
465*4882a593Smuzhiyun .index = fival->index,
466*4882a593Smuzhiyun .width = fival->width,
467*4882a593Smuzhiyun .height = fival->height,
468*4882a593Smuzhiyun .which = V4L2_SUBDEV_FORMAT_ACTIVE,
469*4882a593Smuzhiyun };
470*4882a593Smuzhiyun int ret;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun fmt = find_format_by_pix(ctx, fival->pixel_format);
473*4882a593Smuzhiyun if (!fmt)
474*4882a593Smuzhiyun return -EINVAL;
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun fie.code = fmt->code;
477*4882a593Smuzhiyun ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_interval,
478*4882a593Smuzhiyun NULL, &fie);
479*4882a593Smuzhiyun if (ret)
480*4882a593Smuzhiyun return ret;
481*4882a593Smuzhiyun fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
482*4882a593Smuzhiyun fival->discrete = fie.interval;
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun return 0;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun static const struct v4l2_file_operations cal_fops = {
488*4882a593Smuzhiyun .owner = THIS_MODULE,
489*4882a593Smuzhiyun .open = v4l2_fh_open,
490*4882a593Smuzhiyun .release = vb2_fop_release,
491*4882a593Smuzhiyun .read = vb2_fop_read,
492*4882a593Smuzhiyun .poll = vb2_fop_poll,
493*4882a593Smuzhiyun .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
494*4882a593Smuzhiyun .mmap = vb2_fop_mmap,
495*4882a593Smuzhiyun };
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun static const struct v4l2_ioctl_ops cal_ioctl_ops = {
498*4882a593Smuzhiyun .vidioc_querycap = cal_querycap,
499*4882a593Smuzhiyun .vidioc_enum_fmt_vid_cap = cal_enum_fmt_vid_cap,
500*4882a593Smuzhiyun .vidioc_g_fmt_vid_cap = cal_g_fmt_vid_cap,
501*4882a593Smuzhiyun .vidioc_try_fmt_vid_cap = cal_try_fmt_vid_cap,
502*4882a593Smuzhiyun .vidioc_s_fmt_vid_cap = cal_s_fmt_vid_cap,
503*4882a593Smuzhiyun .vidioc_enum_framesizes = cal_enum_framesizes,
504*4882a593Smuzhiyun .vidioc_reqbufs = vb2_ioctl_reqbufs,
505*4882a593Smuzhiyun .vidioc_create_bufs = vb2_ioctl_create_bufs,
506*4882a593Smuzhiyun .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
507*4882a593Smuzhiyun .vidioc_querybuf = vb2_ioctl_querybuf,
508*4882a593Smuzhiyun .vidioc_qbuf = vb2_ioctl_qbuf,
509*4882a593Smuzhiyun .vidioc_dqbuf = vb2_ioctl_dqbuf,
510*4882a593Smuzhiyun .vidioc_expbuf = vb2_ioctl_expbuf,
511*4882a593Smuzhiyun .vidioc_enum_input = cal_enum_input,
512*4882a593Smuzhiyun .vidioc_g_input = cal_g_input,
513*4882a593Smuzhiyun .vidioc_s_input = cal_s_input,
514*4882a593Smuzhiyun .vidioc_enum_frameintervals = cal_enum_frameintervals,
515*4882a593Smuzhiyun .vidioc_streamon = vb2_ioctl_streamon,
516*4882a593Smuzhiyun .vidioc_streamoff = vb2_ioctl_streamoff,
517*4882a593Smuzhiyun .vidioc_log_status = v4l2_ctrl_log_status,
518*4882a593Smuzhiyun .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
519*4882a593Smuzhiyun .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
520*4882a593Smuzhiyun };
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun /* ------------------------------------------------------------------
523*4882a593Smuzhiyun * videobuf2 Operations
524*4882a593Smuzhiyun * ------------------------------------------------------------------
525*4882a593Smuzhiyun */
526*4882a593Smuzhiyun
cal_queue_setup(struct vb2_queue * vq,unsigned int * nbuffers,unsigned int * nplanes,unsigned int sizes[],struct device * alloc_devs[])527*4882a593Smuzhiyun static int cal_queue_setup(struct vb2_queue *vq,
528*4882a593Smuzhiyun unsigned int *nbuffers, unsigned int *nplanes,
529*4882a593Smuzhiyun unsigned int sizes[], struct device *alloc_devs[])
530*4882a593Smuzhiyun {
531*4882a593Smuzhiyun struct cal_ctx *ctx = vb2_get_drv_priv(vq);
532*4882a593Smuzhiyun unsigned int size = ctx->v_fmt.fmt.pix.sizeimage;
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun if (vq->num_buffers + *nbuffers < 3)
535*4882a593Smuzhiyun *nbuffers = 3 - vq->num_buffers;
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun if (*nplanes) {
538*4882a593Smuzhiyun if (sizes[0] < size)
539*4882a593Smuzhiyun return -EINVAL;
540*4882a593Smuzhiyun size = sizes[0];
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun *nplanes = 1;
544*4882a593Smuzhiyun sizes[0] = size;
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun ctx_dbg(3, ctx, "nbuffers=%d, size=%d\n", *nbuffers, sizes[0]);
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun return 0;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun
cal_buffer_prepare(struct vb2_buffer * vb)551*4882a593Smuzhiyun static int cal_buffer_prepare(struct vb2_buffer *vb)
552*4882a593Smuzhiyun {
553*4882a593Smuzhiyun struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
554*4882a593Smuzhiyun struct cal_buffer *buf = container_of(vb, struct cal_buffer,
555*4882a593Smuzhiyun vb.vb2_buf);
556*4882a593Smuzhiyun unsigned long size;
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun if (WARN_ON(!ctx->fmt))
559*4882a593Smuzhiyun return -EINVAL;
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun size = ctx->v_fmt.fmt.pix.sizeimage;
562*4882a593Smuzhiyun if (vb2_plane_size(vb, 0) < size) {
563*4882a593Smuzhiyun ctx_err(ctx,
564*4882a593Smuzhiyun "data will not fit into plane (%lu < %lu)\n",
565*4882a593Smuzhiyun vb2_plane_size(vb, 0), size);
566*4882a593Smuzhiyun return -EINVAL;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size);
570*4882a593Smuzhiyun return 0;
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun
cal_buffer_queue(struct vb2_buffer * vb)573*4882a593Smuzhiyun static void cal_buffer_queue(struct vb2_buffer *vb)
574*4882a593Smuzhiyun {
575*4882a593Smuzhiyun struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
576*4882a593Smuzhiyun struct cal_buffer *buf = container_of(vb, struct cal_buffer,
577*4882a593Smuzhiyun vb.vb2_buf);
578*4882a593Smuzhiyun struct cal_dmaqueue *vidq = &ctx->vidq;
579*4882a593Smuzhiyun unsigned long flags;
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun /* recheck locking */
582*4882a593Smuzhiyun spin_lock_irqsave(&ctx->slock, flags);
583*4882a593Smuzhiyun list_add_tail(&buf->list, &vidq->active);
584*4882a593Smuzhiyun spin_unlock_irqrestore(&ctx->slock, flags);
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun
cal_start_streaming(struct vb2_queue * vq,unsigned int count)587*4882a593Smuzhiyun static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun struct cal_ctx *ctx = vb2_get_drv_priv(vq);
590*4882a593Smuzhiyun struct cal_dmaqueue *dma_q = &ctx->vidq;
591*4882a593Smuzhiyun struct cal_buffer *buf, *tmp;
592*4882a593Smuzhiyun unsigned long addr;
593*4882a593Smuzhiyun unsigned long flags;
594*4882a593Smuzhiyun int ret;
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun spin_lock_irqsave(&ctx->slock, flags);
597*4882a593Smuzhiyun if (list_empty(&dma_q->active)) {
598*4882a593Smuzhiyun spin_unlock_irqrestore(&ctx->slock, flags);
599*4882a593Smuzhiyun ctx_dbg(3, ctx, "buffer queue is empty\n");
600*4882a593Smuzhiyun return -EIO;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun buf = list_entry(dma_q->active.next, struct cal_buffer, list);
604*4882a593Smuzhiyun ctx->cur_frm = buf;
605*4882a593Smuzhiyun ctx->next_frm = buf;
606*4882a593Smuzhiyun list_del(&buf->list);
607*4882a593Smuzhiyun spin_unlock_irqrestore(&ctx->slock, flags);
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun addr = vb2_dma_contig_plane_dma_addr(&ctx->cur_frm->vb.vb2_buf, 0);
610*4882a593Smuzhiyun ctx->sequence = 0;
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun pm_runtime_get_sync(ctx->cal->dev);
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun cal_ctx_csi2_config(ctx);
615*4882a593Smuzhiyun cal_ctx_pix_proc_config(ctx);
616*4882a593Smuzhiyun cal_ctx_wr_dma_config(ctx, ctx->v_fmt.fmt.pix.bytesperline,
617*4882a593Smuzhiyun ctx->v_fmt.fmt.pix.height);
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun cal_camerarx_enable_irqs(ctx->phy);
620*4882a593Smuzhiyun
621*4882a593Smuzhiyun ret = cal_camerarx_start(ctx->phy, ctx->fmt);
622*4882a593Smuzhiyun if (ret)
623*4882a593Smuzhiyun goto err;
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun cal_ctx_wr_dma_addr(ctx, addr);
626*4882a593Smuzhiyun cal_camerarx_ppi_enable(ctx->phy);
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun if (cal_debug >= 4)
629*4882a593Smuzhiyun cal_quickdump_regs(ctx->cal);
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun return 0;
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun err:
634*4882a593Smuzhiyun spin_lock_irqsave(&ctx->slock, flags);
635*4882a593Smuzhiyun vb2_buffer_done(&ctx->cur_frm->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
636*4882a593Smuzhiyun ctx->cur_frm = NULL;
637*4882a593Smuzhiyun ctx->next_frm = NULL;
638*4882a593Smuzhiyun list_for_each_entry_safe(buf, tmp, &dma_q->active, list) {
639*4882a593Smuzhiyun list_del(&buf->list);
640*4882a593Smuzhiyun vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun spin_unlock_irqrestore(&ctx->slock, flags);
643*4882a593Smuzhiyun return ret;
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun
cal_stop_streaming(struct vb2_queue * vq)646*4882a593Smuzhiyun static void cal_stop_streaming(struct vb2_queue *vq)
647*4882a593Smuzhiyun {
648*4882a593Smuzhiyun struct cal_ctx *ctx = vb2_get_drv_priv(vq);
649*4882a593Smuzhiyun struct cal_dmaqueue *dma_q = &ctx->vidq;
650*4882a593Smuzhiyun struct cal_buffer *buf, *tmp;
651*4882a593Smuzhiyun unsigned long timeout;
652*4882a593Smuzhiyun unsigned long flags;
653*4882a593Smuzhiyun bool dma_act;
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun cal_camerarx_ppi_disable(ctx->phy);
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun /* wait for stream and dma to finish */
658*4882a593Smuzhiyun dma_act = true;
659*4882a593Smuzhiyun timeout = jiffies + msecs_to_jiffies(500);
660*4882a593Smuzhiyun while (dma_act && time_before(jiffies, timeout)) {
661*4882a593Smuzhiyun msleep(50);
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun spin_lock_irqsave(&ctx->slock, flags);
664*4882a593Smuzhiyun dma_act = ctx->dma_act;
665*4882a593Smuzhiyun spin_unlock_irqrestore(&ctx->slock, flags);
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun if (dma_act)
669*4882a593Smuzhiyun ctx_err(ctx, "failed to disable dma cleanly\n");
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun cal_camerarx_disable_irqs(ctx->phy);
672*4882a593Smuzhiyun cal_camerarx_stop(ctx->phy);
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun /* Release all active buffers */
675*4882a593Smuzhiyun spin_lock_irqsave(&ctx->slock, flags);
676*4882a593Smuzhiyun list_for_each_entry_safe(buf, tmp, &dma_q->active, list) {
677*4882a593Smuzhiyun list_del(&buf->list);
678*4882a593Smuzhiyun vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun if (ctx->cur_frm == ctx->next_frm) {
682*4882a593Smuzhiyun vb2_buffer_done(&ctx->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR);
683*4882a593Smuzhiyun } else {
684*4882a593Smuzhiyun vb2_buffer_done(&ctx->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR);
685*4882a593Smuzhiyun vb2_buffer_done(&ctx->next_frm->vb.vb2_buf,
686*4882a593Smuzhiyun VB2_BUF_STATE_ERROR);
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun ctx->cur_frm = NULL;
689*4882a593Smuzhiyun ctx->next_frm = NULL;
690*4882a593Smuzhiyun spin_unlock_irqrestore(&ctx->slock, flags);
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun pm_runtime_put_sync(ctx->cal->dev);
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun static const struct vb2_ops cal_video_qops = {
696*4882a593Smuzhiyun .queue_setup = cal_queue_setup,
697*4882a593Smuzhiyun .buf_prepare = cal_buffer_prepare,
698*4882a593Smuzhiyun .buf_queue = cal_buffer_queue,
699*4882a593Smuzhiyun .start_streaming = cal_start_streaming,
700*4882a593Smuzhiyun .stop_streaming = cal_stop_streaming,
701*4882a593Smuzhiyun .wait_prepare = vb2_ops_wait_prepare,
702*4882a593Smuzhiyun .wait_finish = vb2_ops_wait_finish,
703*4882a593Smuzhiyun };
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun /* ------------------------------------------------------------------
706*4882a593Smuzhiyun * V4L2 Initialization and Registration
707*4882a593Smuzhiyun * ------------------------------------------------------------------
708*4882a593Smuzhiyun */
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun static const struct video_device cal_videodev = {
711*4882a593Smuzhiyun .name = CAL_MODULE_NAME,
712*4882a593Smuzhiyun .fops = &cal_fops,
713*4882a593Smuzhiyun .ioctl_ops = &cal_ioctl_ops,
714*4882a593Smuzhiyun .minor = -1,
715*4882a593Smuzhiyun .release = video_device_release_empty,
716*4882a593Smuzhiyun .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
717*4882a593Smuzhiyun V4L2_CAP_READWRITE,
718*4882a593Smuzhiyun };
719*4882a593Smuzhiyun
cal_ctx_v4l2_init_formats(struct cal_ctx * ctx)720*4882a593Smuzhiyun static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx)
721*4882a593Smuzhiyun {
722*4882a593Smuzhiyun struct v4l2_subdev_mbus_code_enum mbus_code;
723*4882a593Smuzhiyun struct v4l2_mbus_framefmt mbus_fmt;
724*4882a593Smuzhiyun const struct cal_fmt *fmt;
725*4882a593Smuzhiyun unsigned int i, j, k;
726*4882a593Smuzhiyun int ret = 0;
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun /* Enumerate sub device formats and enable all matching local formats */
729*4882a593Smuzhiyun ctx->active_fmt = devm_kcalloc(ctx->cal->dev, ARRAY_SIZE(cal_formats),
730*4882a593Smuzhiyun sizeof(*ctx->active_fmt), GFP_KERNEL);
731*4882a593Smuzhiyun ctx->num_active_fmt = 0;
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun for (j = 0, i = 0; ret != -EINVAL; ++j) {
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun memset(&mbus_code, 0, sizeof(mbus_code));
736*4882a593Smuzhiyun mbus_code.index = j;
737*4882a593Smuzhiyun mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
738*4882a593Smuzhiyun ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_mbus_code,
739*4882a593Smuzhiyun NULL, &mbus_code);
740*4882a593Smuzhiyun if (ret)
741*4882a593Smuzhiyun continue;
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun ctx_dbg(2, ctx,
744*4882a593Smuzhiyun "subdev %s: code: %04x idx: %u\n",
745*4882a593Smuzhiyun ctx->phy->sensor->name, mbus_code.code, j);
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun for (k = 0; k < ARRAY_SIZE(cal_formats); k++) {
748*4882a593Smuzhiyun const struct cal_fmt *fmt = &cal_formats[k];
749*4882a593Smuzhiyun
750*4882a593Smuzhiyun if (mbus_code.code == fmt->code) {
751*4882a593Smuzhiyun ctx->active_fmt[i] = fmt;
752*4882a593Smuzhiyun ctx_dbg(2, ctx,
753*4882a593Smuzhiyun "matched fourcc: %s: code: %04x idx: %u\n",
754*4882a593Smuzhiyun fourcc_to_str(fmt->fourcc),
755*4882a593Smuzhiyun fmt->code, i);
756*4882a593Smuzhiyun ctx->num_active_fmt = ++i;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun }
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun if (i == 0) {
762*4882a593Smuzhiyun ctx_err(ctx, "No suitable format reported by subdev %s\n",
763*4882a593Smuzhiyun ctx->phy->sensor->name);
764*4882a593Smuzhiyun return -EINVAL;
765*4882a593Smuzhiyun }
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun ret = __subdev_get_format(ctx, &mbus_fmt);
768*4882a593Smuzhiyun if (ret)
769*4882a593Smuzhiyun return ret;
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun fmt = find_format_by_code(ctx, mbus_fmt.code);
772*4882a593Smuzhiyun if (!fmt) {
773*4882a593Smuzhiyun ctx_dbg(3, ctx, "mbus code format (0x%08x) not found.\n",
774*4882a593Smuzhiyun mbus_fmt.code);
775*4882a593Smuzhiyun return -EINVAL;
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun /* Save current subdev format */
779*4882a593Smuzhiyun v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &mbus_fmt);
780*4882a593Smuzhiyun ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
781*4882a593Smuzhiyun ctx->v_fmt.fmt.pix.pixelformat = fmt->fourcc;
782*4882a593Smuzhiyun cal_calc_format_size(ctx, fmt, &ctx->v_fmt);
783*4882a593Smuzhiyun ctx->fmt = fmt;
784*4882a593Smuzhiyun ctx->m_fmt = mbus_fmt;
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun return 0;
787*4882a593Smuzhiyun }
788*4882a593Smuzhiyun
cal_ctx_v4l2_register(struct cal_ctx * ctx)789*4882a593Smuzhiyun int cal_ctx_v4l2_register(struct cal_ctx *ctx)
790*4882a593Smuzhiyun {
791*4882a593Smuzhiyun struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler;
792*4882a593Smuzhiyun struct video_device *vfd = &ctx->vdev;
793*4882a593Smuzhiyun int ret;
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun ret = cal_ctx_v4l2_init_formats(ctx);
796*4882a593Smuzhiyun if (ret)
797*4882a593Smuzhiyun return ret;
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun ret = v4l2_ctrl_add_handler(hdl, ctx->phy->sensor->ctrl_handler, NULL,
800*4882a593Smuzhiyun true);
801*4882a593Smuzhiyun if (ret < 0) {
802*4882a593Smuzhiyun ctx_err(ctx, "Failed to add sensor ctrl handler\n");
803*4882a593Smuzhiyun return ret;
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun ret = video_register_device(vfd, VFL_TYPE_VIDEO, cal_video_nr);
807*4882a593Smuzhiyun if (ret < 0) {
808*4882a593Smuzhiyun ctx_err(ctx, "Failed to register video device\n");
809*4882a593Smuzhiyun return ret;
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun ctx_info(ctx, "V4L2 device registered as %s\n",
813*4882a593Smuzhiyun video_device_node_name(vfd));
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun return 0;
816*4882a593Smuzhiyun }
817*4882a593Smuzhiyun
cal_ctx_v4l2_unregister(struct cal_ctx * ctx)818*4882a593Smuzhiyun void cal_ctx_v4l2_unregister(struct cal_ctx *ctx)
819*4882a593Smuzhiyun {
820*4882a593Smuzhiyun ctx_dbg(1, ctx, "unregistering %s\n",
821*4882a593Smuzhiyun video_device_node_name(&ctx->vdev));
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun video_unregister_device(&ctx->vdev);
824*4882a593Smuzhiyun }
825*4882a593Smuzhiyun
cal_ctx_v4l2_init(struct cal_ctx * ctx)826*4882a593Smuzhiyun int cal_ctx_v4l2_init(struct cal_ctx *ctx)
827*4882a593Smuzhiyun {
828*4882a593Smuzhiyun struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler;
829*4882a593Smuzhiyun struct video_device *vfd = &ctx->vdev;
830*4882a593Smuzhiyun struct vb2_queue *q = &ctx->vb_vidq;
831*4882a593Smuzhiyun int ret;
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun INIT_LIST_HEAD(&ctx->vidq.active);
834*4882a593Smuzhiyun spin_lock_init(&ctx->slock);
835*4882a593Smuzhiyun mutex_init(&ctx->mutex);
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun /* Initialize the vb2 queue. */
838*4882a593Smuzhiyun q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
839*4882a593Smuzhiyun q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
840*4882a593Smuzhiyun q->drv_priv = ctx;
841*4882a593Smuzhiyun q->buf_struct_size = sizeof(struct cal_buffer);
842*4882a593Smuzhiyun q->ops = &cal_video_qops;
843*4882a593Smuzhiyun q->mem_ops = &vb2_dma_contig_memops;
844*4882a593Smuzhiyun q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
845*4882a593Smuzhiyun q->lock = &ctx->mutex;
846*4882a593Smuzhiyun q->min_buffers_needed = 3;
847*4882a593Smuzhiyun q->dev = ctx->cal->dev;
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun ret = vb2_queue_init(q);
850*4882a593Smuzhiyun if (ret)
851*4882a593Smuzhiyun return ret;
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun /* Initialize the video device and media entity. */
854*4882a593Smuzhiyun *vfd = cal_videodev;
855*4882a593Smuzhiyun vfd->v4l2_dev = &ctx->cal->v4l2_dev;
856*4882a593Smuzhiyun vfd->queue = q;
857*4882a593Smuzhiyun snprintf(vfd->name, sizeof(vfd->name), "CAL output %u", ctx->index);
858*4882a593Smuzhiyun vfd->lock = &ctx->mutex;
859*4882a593Smuzhiyun video_set_drvdata(vfd, ctx);
860*4882a593Smuzhiyun
861*4882a593Smuzhiyun ctx->pad.flags = MEDIA_PAD_FL_SINK;
862*4882a593Smuzhiyun ret = media_entity_pads_init(&vfd->entity, 1, &ctx->pad);
863*4882a593Smuzhiyun if (ret < 0)
864*4882a593Smuzhiyun return ret;
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun /* Initialize the control handler. */
867*4882a593Smuzhiyun ret = v4l2_ctrl_handler_init(hdl, 11);
868*4882a593Smuzhiyun if (ret < 0) {
869*4882a593Smuzhiyun ctx_err(ctx, "Failed to init ctrl handler\n");
870*4882a593Smuzhiyun goto error;
871*4882a593Smuzhiyun }
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun vfd->ctrl_handler = hdl;
874*4882a593Smuzhiyun
875*4882a593Smuzhiyun return 0;
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun error:
878*4882a593Smuzhiyun media_entity_cleanup(&vfd->entity);
879*4882a593Smuzhiyun return ret;
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun
cal_ctx_v4l2_cleanup(struct cal_ctx * ctx)882*4882a593Smuzhiyun void cal_ctx_v4l2_cleanup(struct cal_ctx *ctx)
883*4882a593Smuzhiyun {
884*4882a593Smuzhiyun v4l2_ctrl_handler_free(&ctx->ctrl_handler);
885*4882a593Smuzhiyun media_entity_cleanup(&ctx->vdev.entity);
886*4882a593Smuzhiyun }
887