selinux: kill 'flags' argument in avc_has_perm_flags() and avc_audit()
[sfrench/cifs-2.6.git] / drivers / media / platform / sunxi / sun4i-csi / sun4i_v4l2.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2016 NextThing Co
4  * Copyright (C) 2016-2019 Bootlin
5  *
6  * Author: Maxime Ripard <maxime.ripard@bootlin.com>
7  */
8
9 #include <linux/device.h>
10 #include <linux/pm_runtime.h>
11
12 #include <media/v4l2-ioctl.h>
13 #include <media/v4l2-mc.h>
14 #include <media/videobuf2-v4l2.h>
15
16 #include "sun4i_csi.h"
17
18 #define CSI_DEFAULT_WIDTH       640
19 #define CSI_DEFAULT_HEIGHT      480
20
21 static const struct sun4i_csi_format sun4i_csi_formats[] = {
22         /* YUV422 inputs */
23         {
24                 .mbus           = MEDIA_BUS_FMT_YUYV8_2X8,
25                 .fourcc         = V4L2_PIX_FMT_YUV420M,
26                 .input          = CSI_INPUT_YUV,
27                 .output         = CSI_OUTPUT_YUV_420_PLANAR,
28                 .num_planes     = 3,
29                 .bpp            = { 8, 8, 8 },
30                 .hsub           = 2,
31                 .vsub           = 2,
32         },
33 };
34
35 const struct sun4i_csi_format *sun4i_csi_find_format(const u32 *fourcc,
36                                                      const u32 *mbus)
37 {
38         unsigned int i;
39
40         for (i = 0; i < ARRAY_SIZE(sun4i_csi_formats); i++) {
41                 if (fourcc && *fourcc != sun4i_csi_formats[i].fourcc)
42                         continue;
43
44                 if (mbus && *mbus != sun4i_csi_formats[i].mbus)
45                         continue;
46
47                 return &sun4i_csi_formats[i];
48         }
49
50         return NULL;
51 }
52
53 static int sun4i_csi_querycap(struct file *file, void *priv,
54                               struct v4l2_capability *cap)
55 {
56         struct sun4i_csi *csi = video_drvdata(file);
57
58         strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
59         strscpy(cap->card, "sun4i-csi", sizeof(cap->card));
60         snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
61                  dev_name(csi->dev));
62
63         return 0;
64 }
65
66 static int sun4i_csi_enum_input(struct file *file, void *priv,
67                                 struct v4l2_input *inp)
68 {
69         if (inp->index != 0)
70                 return -EINVAL;
71
72         inp->type = V4L2_INPUT_TYPE_CAMERA;
73         strscpy(inp->name, "Camera", sizeof(inp->name));
74
75         return 0;
76 }
77
78 static int sun4i_csi_g_input(struct file *file, void *fh,
79                              unsigned int *i)
80 {
81         *i = 0;
82
83         return 0;
84 }
85
86 static int sun4i_csi_s_input(struct file *file, void *fh,
87                              unsigned int i)
88 {
89         if (i != 0)
90                 return -EINVAL;
91
92         return 0;
93 }
94
95 static void _sun4i_csi_try_fmt(struct sun4i_csi *csi,
96                                struct v4l2_pix_format_mplane *pix)
97 {
98         const struct sun4i_csi_format *_fmt;
99         unsigned int height, width;
100         unsigned int i;
101
102         _fmt = sun4i_csi_find_format(&pix->pixelformat, NULL);
103         if (!_fmt)
104                 _fmt = &sun4i_csi_formats[0];
105
106         pix->field = V4L2_FIELD_NONE;
107         pix->colorspace = V4L2_COLORSPACE_SRGB;
108         pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
109         pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
110         pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace,
111                                                           pix->ycbcr_enc);
112
113         pix->num_planes = _fmt->num_planes;
114         pix->pixelformat = _fmt->fourcc;
115
116         /* Align the width and height on the subsampling */
117         width = ALIGN(pix->width, _fmt->hsub);
118         height = ALIGN(pix->height, _fmt->vsub);
119
120         /* Clamp the width and height to our capabilities */
121         pix->width = clamp(width, _fmt->hsub, CSI_MAX_WIDTH);
122         pix->height = clamp(height, _fmt->vsub, CSI_MAX_HEIGHT);
123
124         for (i = 0; i < _fmt->num_planes; i++) {
125                 unsigned int hsub = i > 0 ? _fmt->hsub : 1;
126                 unsigned int vsub = i > 0 ? _fmt->vsub : 1;
127                 unsigned int bpl;
128
129                 bpl = pix->width / hsub * _fmt->bpp[i] / 8;
130                 pix->plane_fmt[i].bytesperline = bpl;
131                 pix->plane_fmt[i].sizeimage = bpl * pix->height / vsub;
132         }
133 }
134
135 static int sun4i_csi_try_fmt_vid_cap(struct file *file, void *priv,
136                                      struct v4l2_format *f)
137 {
138         struct sun4i_csi *csi = video_drvdata(file);
139
140         _sun4i_csi_try_fmt(csi, &f->fmt.pix_mp);
141
142         return 0;
143 }
144
145 static int sun4i_csi_s_fmt_vid_cap(struct file *file, void *priv,
146                                    struct v4l2_format *f)
147 {
148         struct sun4i_csi *csi = video_drvdata(file);
149
150         _sun4i_csi_try_fmt(csi, &f->fmt.pix_mp);
151         csi->fmt = f->fmt.pix_mp;
152
153         return 0;
154 }
155
156 static int sun4i_csi_g_fmt_vid_cap(struct file *file, void *priv,
157                                    struct v4l2_format *f)
158 {
159         struct sun4i_csi *csi = video_drvdata(file);
160
161         f->fmt.pix_mp = csi->fmt;
162
163         return 0;
164 }
165
166 static int sun4i_csi_enum_fmt_vid_cap(struct file *file, void *priv,
167                                       struct v4l2_fmtdesc *f)
168 {
169         if (f->index >= ARRAY_SIZE(sun4i_csi_formats))
170                 return -EINVAL;
171
172         f->pixelformat = sun4i_csi_formats[f->index].fourcc;
173
174         return 0;
175 }
176
177 static const struct v4l2_ioctl_ops sun4i_csi_ioctl_ops = {
178         .vidioc_querycap                = sun4i_csi_querycap,
179
180         .vidioc_enum_fmt_vid_cap        = sun4i_csi_enum_fmt_vid_cap,
181         .vidioc_g_fmt_vid_cap_mplane    = sun4i_csi_g_fmt_vid_cap,
182         .vidioc_s_fmt_vid_cap_mplane    = sun4i_csi_s_fmt_vid_cap,
183         .vidioc_try_fmt_vid_cap_mplane  = sun4i_csi_try_fmt_vid_cap,
184
185         .vidioc_enum_input              = sun4i_csi_enum_input,
186         .vidioc_g_input                 = sun4i_csi_g_input,
187         .vidioc_s_input                 = sun4i_csi_s_input,
188
189         .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
190         .vidioc_create_bufs             = vb2_ioctl_create_bufs,
191         .vidioc_querybuf                = vb2_ioctl_querybuf,
192         .vidioc_qbuf                    = vb2_ioctl_qbuf,
193         .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
194         .vidioc_expbuf                  = vb2_ioctl_expbuf,
195         .vidioc_prepare_buf             = vb2_ioctl_prepare_buf,
196         .vidioc_streamon                = vb2_ioctl_streamon,
197         .vidioc_streamoff               = vb2_ioctl_streamoff,
198 };
199
200 static int sun4i_csi_open(struct file *file)
201 {
202         struct sun4i_csi *csi = video_drvdata(file);
203         int ret;
204
205         ret = mutex_lock_interruptible(&csi->lock);
206         if (ret)
207                 return ret;
208
209         ret = pm_runtime_get_sync(csi->dev);
210         if (ret < 0)
211                 goto err_pm_put;
212
213         ret = v4l2_pipeline_pm_get(&csi->vdev.entity);
214         if (ret)
215                 goto err_pm_put;
216
217         ret = v4l2_fh_open(file);
218         if (ret)
219                 goto err_pipeline_pm_put;
220
221         mutex_unlock(&csi->lock);
222
223         return 0;
224
225 err_pipeline_pm_put:
226         v4l2_pipeline_pm_put(&csi->vdev.entity);
227
228 err_pm_put:
229         pm_runtime_put(csi->dev);
230         mutex_unlock(&csi->lock);
231
232         return ret;
233 }
234
235 static int sun4i_csi_release(struct file *file)
236 {
237         struct sun4i_csi *csi = video_drvdata(file);
238
239         mutex_lock(&csi->lock);
240
241         _vb2_fop_release(file, NULL);
242
243         v4l2_pipeline_pm_put(&csi->vdev.entity);
244         pm_runtime_put(csi->dev);
245
246         mutex_unlock(&csi->lock);
247
248         return 0;
249 }
250
251 static const struct v4l2_file_operations sun4i_csi_fops = {
252         .owner          = THIS_MODULE,
253         .open           = sun4i_csi_open,
254         .release        = sun4i_csi_release,
255         .unlocked_ioctl = video_ioctl2,
256         .poll           = vb2_fop_poll,
257         .mmap           = vb2_fop_mmap,
258 };
259
260 static const struct v4l2_mbus_framefmt sun4i_csi_pad_fmt_default = {
261         .width = CSI_DEFAULT_WIDTH,
262         .height = CSI_DEFAULT_HEIGHT,
263         .code = MEDIA_BUS_FMT_YUYV8_2X8,
264         .field = V4L2_FIELD_NONE,
265         .colorspace = V4L2_COLORSPACE_RAW,
266         .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
267         .quantization = V4L2_QUANTIZATION_DEFAULT,
268         .xfer_func = V4L2_XFER_FUNC_DEFAULT,
269 };
270
271 static int sun4i_csi_subdev_init_cfg(struct v4l2_subdev *subdev,
272                                      struct v4l2_subdev_pad_config *cfg)
273 {
274         struct v4l2_mbus_framefmt *fmt;
275
276         fmt = v4l2_subdev_get_try_format(subdev, cfg, CSI_SUBDEV_SINK);
277         *fmt = sun4i_csi_pad_fmt_default;
278
279         return 0;
280 }
281
282 static int sun4i_csi_subdev_get_fmt(struct v4l2_subdev *subdev,
283                                     struct v4l2_subdev_pad_config *cfg,
284                                     struct v4l2_subdev_format *fmt)
285 {
286         struct sun4i_csi *csi = container_of(subdev, struct sun4i_csi, subdev);
287         struct v4l2_mbus_framefmt *subdev_fmt;
288
289         if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
290                 subdev_fmt = v4l2_subdev_get_try_format(subdev, cfg, fmt->pad);
291         else
292                 subdev_fmt = &csi->subdev_fmt;
293
294         fmt->format = *subdev_fmt;
295
296         return 0;
297 }
298
299 static int sun4i_csi_subdev_set_fmt(struct v4l2_subdev *subdev,
300                                     struct v4l2_subdev_pad_config *cfg,
301                                     struct v4l2_subdev_format *fmt)
302 {
303         struct sun4i_csi *csi = container_of(subdev, struct sun4i_csi, subdev);
304         struct v4l2_mbus_framefmt *subdev_fmt;
305
306         if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
307                 subdev_fmt = v4l2_subdev_get_try_format(subdev, cfg, fmt->pad);
308         else
309                 subdev_fmt = &csi->subdev_fmt;
310
311         /* We can only set the format on the sink pad */
312         if (fmt->pad == CSI_SUBDEV_SINK) {
313                 /* It's the sink, only allow changing the frame size */
314                 subdev_fmt->width = fmt->format.width;
315                 subdev_fmt->height = fmt->format.height;
316                 subdev_fmt->code = fmt->format.code;
317         }
318
319         fmt->format = *subdev_fmt;
320
321         return 0;
322 }
323
324 static int
325 sun4i_csi_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
326                                 struct v4l2_subdev_pad_config *cfg,
327                                 struct v4l2_subdev_mbus_code_enum *mbus)
328 {
329         if (mbus->index >= ARRAY_SIZE(sun4i_csi_formats))
330                 return -EINVAL;
331
332         mbus->code = sun4i_csi_formats[mbus->index].mbus;
333
334         return 0;
335 }
336
337 static const struct v4l2_subdev_pad_ops sun4i_csi_subdev_pad_ops = {
338         .link_validate  = v4l2_subdev_link_validate_default,
339         .init_cfg       = sun4i_csi_subdev_init_cfg,
340         .get_fmt        = sun4i_csi_subdev_get_fmt,
341         .set_fmt        = sun4i_csi_subdev_set_fmt,
342         .enum_mbus_code = sun4i_csi_subdev_enum_mbus_code,
343 };
344
345 const struct v4l2_subdev_ops sun4i_csi_subdev_ops = {
346         .pad = &sun4i_csi_subdev_pad_ops,
347 };
348
349 int sun4i_csi_v4l2_register(struct sun4i_csi *csi)
350 {
351         struct video_device *vdev = &csi->vdev;
352         int ret;
353
354         vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING;
355         vdev->v4l2_dev = &csi->v4l;
356         vdev->queue = &csi->queue;
357         strscpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name));
358         vdev->release = video_device_release_empty;
359         vdev->lock = &csi->lock;
360
361         /* Set a default format */
362         csi->fmt.pixelformat = sun4i_csi_formats[0].fourcc;
363         csi->fmt.width = CSI_DEFAULT_WIDTH;
364         csi->fmt.height = CSI_DEFAULT_HEIGHT;
365         _sun4i_csi_try_fmt(csi, &csi->fmt);
366         csi->subdev_fmt = sun4i_csi_pad_fmt_default;
367
368         vdev->fops = &sun4i_csi_fops;
369         vdev->ioctl_ops = &sun4i_csi_ioctl_ops;
370         video_set_drvdata(vdev, csi);
371
372         ret = video_register_device(&csi->vdev, VFL_TYPE_VIDEO, -1);
373         if (ret)
374                 return ret;
375
376         dev_info(csi->dev, "Device registered as %s\n",
377                  video_device_node_name(vdev));
378
379         return 0;
380 }