1577bbf23SMaxime Ripard // SPDX-License-Identifier: GPL-2.0+
2577bbf23SMaxime Ripard /*
3577bbf23SMaxime Ripard * Copyright (C) 2016 NextThing Co
4577bbf23SMaxime Ripard * Copyright (C) 2016-2019 Bootlin
5577bbf23SMaxime Ripard *
6577bbf23SMaxime Ripard * Author: Maxime Ripard <maxime.ripard@bootlin.com>
7577bbf23SMaxime Ripard */
8577bbf23SMaxime Ripard
9577bbf23SMaxime Ripard #include <linux/device.h>
10577bbf23SMaxime Ripard #include <linux/pm_runtime.h>
11577bbf23SMaxime Ripard
12577bbf23SMaxime Ripard #include <media/v4l2-ioctl.h>
13577bbf23SMaxime Ripard #include <media/v4l2-mc.h>
14577bbf23SMaxime Ripard #include <media/videobuf2-v4l2.h>
15577bbf23SMaxime Ripard
16577bbf23SMaxime Ripard #include "sun4i_csi.h"
17577bbf23SMaxime Ripard
18577bbf23SMaxime Ripard #define CSI_DEFAULT_WIDTH 640
19577bbf23SMaxime Ripard #define CSI_DEFAULT_HEIGHT 480
20577bbf23SMaxime Ripard
2120a438d5SMaxime Ripard static const struct sun4i_csi_format sun4i_csi_formats[] = {
22577bbf23SMaxime Ripard /* YUV422 inputs */
23577bbf23SMaxime Ripard {
24577bbf23SMaxime Ripard .mbus = MEDIA_BUS_FMT_YUYV8_2X8,
25577bbf23SMaxime Ripard .fourcc = V4L2_PIX_FMT_YUV420M,
26577bbf23SMaxime Ripard .input = CSI_INPUT_YUV,
27577bbf23SMaxime Ripard .output = CSI_OUTPUT_YUV_420_PLANAR,
28577bbf23SMaxime Ripard .num_planes = 3,
29577bbf23SMaxime Ripard .bpp = { 8, 8, 8 },
30577bbf23SMaxime Ripard .hsub = 2,
31577bbf23SMaxime Ripard .vsub = 2,
32577bbf23SMaxime Ripard },
33577bbf23SMaxime Ripard };
34577bbf23SMaxime Ripard
sun4i_csi_find_format(const u32 * fourcc,const u32 * mbus)35577bbf23SMaxime Ripard const struct sun4i_csi_format *sun4i_csi_find_format(const u32 *fourcc,
36577bbf23SMaxime Ripard const u32 *mbus)
37577bbf23SMaxime Ripard {
38577bbf23SMaxime Ripard unsigned int i;
39577bbf23SMaxime Ripard
40577bbf23SMaxime Ripard for (i = 0; i < ARRAY_SIZE(sun4i_csi_formats); i++) {
41577bbf23SMaxime Ripard if (fourcc && *fourcc != sun4i_csi_formats[i].fourcc)
42577bbf23SMaxime Ripard continue;
43577bbf23SMaxime Ripard
44577bbf23SMaxime Ripard if (mbus && *mbus != sun4i_csi_formats[i].mbus)
45577bbf23SMaxime Ripard continue;
46577bbf23SMaxime Ripard
47577bbf23SMaxime Ripard return &sun4i_csi_formats[i];
48577bbf23SMaxime Ripard }
49577bbf23SMaxime Ripard
50577bbf23SMaxime Ripard return NULL;
51577bbf23SMaxime Ripard }
52577bbf23SMaxime Ripard
sun4i_csi_querycap(struct file * file,void * priv,struct v4l2_capability * cap)53577bbf23SMaxime Ripard static int sun4i_csi_querycap(struct file *file, void *priv,
54577bbf23SMaxime Ripard struct v4l2_capability *cap)
55577bbf23SMaxime Ripard {
56577bbf23SMaxime Ripard strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
57577bbf23SMaxime Ripard strscpy(cap->card, "sun4i-csi", sizeof(cap->card));
58577bbf23SMaxime Ripard
59577bbf23SMaxime Ripard return 0;
60577bbf23SMaxime Ripard }
61577bbf23SMaxime Ripard
sun4i_csi_enum_input(struct file * file,void * priv,struct v4l2_input * inp)62577bbf23SMaxime Ripard static int sun4i_csi_enum_input(struct file *file, void *priv,
63577bbf23SMaxime Ripard struct v4l2_input *inp)
64577bbf23SMaxime Ripard {
65577bbf23SMaxime Ripard if (inp->index != 0)
66577bbf23SMaxime Ripard return -EINVAL;
67577bbf23SMaxime Ripard
68577bbf23SMaxime Ripard inp->type = V4L2_INPUT_TYPE_CAMERA;
69577bbf23SMaxime Ripard strscpy(inp->name, "Camera", sizeof(inp->name));
70577bbf23SMaxime Ripard
71577bbf23SMaxime Ripard return 0;
72577bbf23SMaxime Ripard }
73577bbf23SMaxime Ripard
sun4i_csi_g_input(struct file * file,void * fh,unsigned int * i)74577bbf23SMaxime Ripard static int sun4i_csi_g_input(struct file *file, void *fh,
75577bbf23SMaxime Ripard unsigned int *i)
76577bbf23SMaxime Ripard {
77577bbf23SMaxime Ripard *i = 0;
78577bbf23SMaxime Ripard
79577bbf23SMaxime Ripard return 0;
80577bbf23SMaxime Ripard }
81577bbf23SMaxime Ripard
sun4i_csi_s_input(struct file * file,void * fh,unsigned int i)82577bbf23SMaxime Ripard static int sun4i_csi_s_input(struct file *file, void *fh,
83577bbf23SMaxime Ripard unsigned int i)
84577bbf23SMaxime Ripard {
85577bbf23SMaxime Ripard if (i != 0)
86577bbf23SMaxime Ripard return -EINVAL;
87577bbf23SMaxime Ripard
88577bbf23SMaxime Ripard return 0;
89577bbf23SMaxime Ripard }
90577bbf23SMaxime Ripard
_sun4i_csi_try_fmt(struct sun4i_csi * csi,struct v4l2_pix_format_mplane * pix)91577bbf23SMaxime Ripard static void _sun4i_csi_try_fmt(struct sun4i_csi *csi,
92577bbf23SMaxime Ripard struct v4l2_pix_format_mplane *pix)
93577bbf23SMaxime Ripard {
94577bbf23SMaxime Ripard const struct sun4i_csi_format *_fmt;
95577bbf23SMaxime Ripard unsigned int height, width;
96577bbf23SMaxime Ripard unsigned int i;
97577bbf23SMaxime Ripard
98577bbf23SMaxime Ripard _fmt = sun4i_csi_find_format(&pix->pixelformat, NULL);
99577bbf23SMaxime Ripard if (!_fmt)
100577bbf23SMaxime Ripard _fmt = &sun4i_csi_formats[0];
101577bbf23SMaxime Ripard
102577bbf23SMaxime Ripard pix->field = V4L2_FIELD_NONE;
103577bbf23SMaxime Ripard pix->colorspace = V4L2_COLORSPACE_SRGB;
104577bbf23SMaxime Ripard pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
105577bbf23SMaxime Ripard pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
106577bbf23SMaxime Ripard pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace,
107577bbf23SMaxime Ripard pix->ycbcr_enc);
108577bbf23SMaxime Ripard
109577bbf23SMaxime Ripard pix->num_planes = _fmt->num_planes;
110577bbf23SMaxime Ripard pix->pixelformat = _fmt->fourcc;
111577bbf23SMaxime Ripard
112577bbf23SMaxime Ripard /* Align the width and height on the subsampling */
113577bbf23SMaxime Ripard width = ALIGN(pix->width, _fmt->hsub);
114577bbf23SMaxime Ripard height = ALIGN(pix->height, _fmt->vsub);
115577bbf23SMaxime Ripard
116577bbf23SMaxime Ripard /* Clamp the width and height to our capabilities */
117577bbf23SMaxime Ripard pix->width = clamp(width, _fmt->hsub, CSI_MAX_WIDTH);
118577bbf23SMaxime Ripard pix->height = clamp(height, _fmt->vsub, CSI_MAX_HEIGHT);
119577bbf23SMaxime Ripard
120577bbf23SMaxime Ripard for (i = 0; i < _fmt->num_planes; i++) {
121577bbf23SMaxime Ripard unsigned int hsub = i > 0 ? _fmt->hsub : 1;
122577bbf23SMaxime Ripard unsigned int vsub = i > 0 ? _fmt->vsub : 1;
123577bbf23SMaxime Ripard unsigned int bpl;
124577bbf23SMaxime Ripard
125577bbf23SMaxime Ripard bpl = pix->width / hsub * _fmt->bpp[i] / 8;
126577bbf23SMaxime Ripard pix->plane_fmt[i].bytesperline = bpl;
127577bbf23SMaxime Ripard pix->plane_fmt[i].sizeimage = bpl * pix->height / vsub;
128577bbf23SMaxime Ripard }
129577bbf23SMaxime Ripard }
130577bbf23SMaxime Ripard
sun4i_csi_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)131577bbf23SMaxime Ripard static int sun4i_csi_try_fmt_vid_cap(struct file *file, void *priv,
132577bbf23SMaxime Ripard struct v4l2_format *f)
133577bbf23SMaxime Ripard {
134577bbf23SMaxime Ripard struct sun4i_csi *csi = video_drvdata(file);
135577bbf23SMaxime Ripard
136577bbf23SMaxime Ripard _sun4i_csi_try_fmt(csi, &f->fmt.pix_mp);
137577bbf23SMaxime Ripard
138577bbf23SMaxime Ripard return 0;
139577bbf23SMaxime Ripard }
140577bbf23SMaxime Ripard
sun4i_csi_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)141577bbf23SMaxime Ripard static int sun4i_csi_s_fmt_vid_cap(struct file *file, void *priv,
142577bbf23SMaxime Ripard struct v4l2_format *f)
143577bbf23SMaxime Ripard {
144577bbf23SMaxime Ripard struct sun4i_csi *csi = video_drvdata(file);
145577bbf23SMaxime Ripard
146577bbf23SMaxime Ripard _sun4i_csi_try_fmt(csi, &f->fmt.pix_mp);
147577bbf23SMaxime Ripard csi->fmt = f->fmt.pix_mp;
148577bbf23SMaxime Ripard
149577bbf23SMaxime Ripard return 0;
150577bbf23SMaxime Ripard }
151577bbf23SMaxime Ripard
sun4i_csi_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)152577bbf23SMaxime Ripard static int sun4i_csi_g_fmt_vid_cap(struct file *file, void *priv,
153577bbf23SMaxime Ripard struct v4l2_format *f)
154577bbf23SMaxime Ripard {
155577bbf23SMaxime Ripard struct sun4i_csi *csi = video_drvdata(file);
156577bbf23SMaxime Ripard
157577bbf23SMaxime Ripard f->fmt.pix_mp = csi->fmt;
158577bbf23SMaxime Ripard
159577bbf23SMaxime Ripard return 0;
160577bbf23SMaxime Ripard }
161577bbf23SMaxime Ripard
sun4i_csi_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)162577bbf23SMaxime Ripard static int sun4i_csi_enum_fmt_vid_cap(struct file *file, void *priv,
163577bbf23SMaxime Ripard struct v4l2_fmtdesc *f)
164577bbf23SMaxime Ripard {
165577bbf23SMaxime Ripard if (f->index >= ARRAY_SIZE(sun4i_csi_formats))
166577bbf23SMaxime Ripard return -EINVAL;
167577bbf23SMaxime Ripard
168577bbf23SMaxime Ripard f->pixelformat = sun4i_csi_formats[f->index].fourcc;
169577bbf23SMaxime Ripard
170577bbf23SMaxime Ripard return 0;
171577bbf23SMaxime Ripard }
172577bbf23SMaxime Ripard
173577bbf23SMaxime Ripard static const struct v4l2_ioctl_ops sun4i_csi_ioctl_ops = {
174577bbf23SMaxime Ripard .vidioc_querycap = sun4i_csi_querycap,
175577bbf23SMaxime Ripard
176577bbf23SMaxime Ripard .vidioc_enum_fmt_vid_cap = sun4i_csi_enum_fmt_vid_cap,
177577bbf23SMaxime Ripard .vidioc_g_fmt_vid_cap_mplane = sun4i_csi_g_fmt_vid_cap,
178577bbf23SMaxime Ripard .vidioc_s_fmt_vid_cap_mplane = sun4i_csi_s_fmt_vid_cap,
179577bbf23SMaxime Ripard .vidioc_try_fmt_vid_cap_mplane = sun4i_csi_try_fmt_vid_cap,
180577bbf23SMaxime Ripard
181577bbf23SMaxime Ripard .vidioc_enum_input = sun4i_csi_enum_input,
182577bbf23SMaxime Ripard .vidioc_g_input = sun4i_csi_g_input,
183577bbf23SMaxime Ripard .vidioc_s_input = sun4i_csi_s_input,
184577bbf23SMaxime Ripard
185577bbf23SMaxime Ripard .vidioc_reqbufs = vb2_ioctl_reqbufs,
186577bbf23SMaxime Ripard .vidioc_create_bufs = vb2_ioctl_create_bufs,
187577bbf23SMaxime Ripard .vidioc_querybuf = vb2_ioctl_querybuf,
188577bbf23SMaxime Ripard .vidioc_qbuf = vb2_ioctl_qbuf,
189577bbf23SMaxime Ripard .vidioc_dqbuf = vb2_ioctl_dqbuf,
190577bbf23SMaxime Ripard .vidioc_expbuf = vb2_ioctl_expbuf,
191577bbf23SMaxime Ripard .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
192577bbf23SMaxime Ripard .vidioc_streamon = vb2_ioctl_streamon,
193577bbf23SMaxime Ripard .vidioc_streamoff = vb2_ioctl_streamoff,
194577bbf23SMaxime Ripard };
195577bbf23SMaxime Ripard
sun4i_csi_open(struct file * file)196577bbf23SMaxime Ripard static int sun4i_csi_open(struct file *file)
197577bbf23SMaxime Ripard {
198577bbf23SMaxime Ripard struct sun4i_csi *csi = video_drvdata(file);
199577bbf23SMaxime Ripard int ret;
200577bbf23SMaxime Ripard
201577bbf23SMaxime Ripard ret = mutex_lock_interruptible(&csi->lock);
202577bbf23SMaxime Ripard if (ret)
203577bbf23SMaxime Ripard return ret;
204577bbf23SMaxime Ripard
20579e790ffSMauro Carvalho Chehab ret = pm_runtime_resume_and_get(csi->dev);
206577bbf23SMaxime Ripard if (ret < 0)
20779e790ffSMauro Carvalho Chehab goto err_unlock;
208577bbf23SMaxime Ripard
2098fd390b8SEzequiel Garcia ret = v4l2_pipeline_pm_get(&csi->vdev.entity);
210577bbf23SMaxime Ripard if (ret)
211577bbf23SMaxime Ripard goto err_pm_put;
212577bbf23SMaxime Ripard
213577bbf23SMaxime Ripard ret = v4l2_fh_open(file);
214577bbf23SMaxime Ripard if (ret)
215577bbf23SMaxime Ripard goto err_pipeline_pm_put;
216577bbf23SMaxime Ripard
217577bbf23SMaxime Ripard mutex_unlock(&csi->lock);
218577bbf23SMaxime Ripard
219577bbf23SMaxime Ripard return 0;
220577bbf23SMaxime Ripard
221577bbf23SMaxime Ripard err_pipeline_pm_put:
2228fd390b8SEzequiel Garcia v4l2_pipeline_pm_put(&csi->vdev.entity);
223577bbf23SMaxime Ripard
224577bbf23SMaxime Ripard err_pm_put:
225577bbf23SMaxime Ripard pm_runtime_put(csi->dev);
22679e790ffSMauro Carvalho Chehab
22779e790ffSMauro Carvalho Chehab err_unlock:
228577bbf23SMaxime Ripard mutex_unlock(&csi->lock);
229577bbf23SMaxime Ripard
230577bbf23SMaxime Ripard return ret;
231577bbf23SMaxime Ripard }
232577bbf23SMaxime Ripard
sun4i_csi_release(struct file * file)233577bbf23SMaxime Ripard static int sun4i_csi_release(struct file *file)
234577bbf23SMaxime Ripard {
235577bbf23SMaxime Ripard struct sun4i_csi *csi = video_drvdata(file);
236577bbf23SMaxime Ripard
237577bbf23SMaxime Ripard mutex_lock(&csi->lock);
238577bbf23SMaxime Ripard
239503ebad4SHans Verkuil _vb2_fop_release(file, NULL);
240503ebad4SHans Verkuil
2418fd390b8SEzequiel Garcia v4l2_pipeline_pm_put(&csi->vdev.entity);
242577bbf23SMaxime Ripard pm_runtime_put(csi->dev);
243577bbf23SMaxime Ripard
244577bbf23SMaxime Ripard mutex_unlock(&csi->lock);
245577bbf23SMaxime Ripard
246577bbf23SMaxime Ripard return 0;
247577bbf23SMaxime Ripard }
248577bbf23SMaxime Ripard
249577bbf23SMaxime Ripard static const struct v4l2_file_operations sun4i_csi_fops = {
250577bbf23SMaxime Ripard .owner = THIS_MODULE,
251577bbf23SMaxime Ripard .open = sun4i_csi_open,
252577bbf23SMaxime Ripard .release = sun4i_csi_release,
253577bbf23SMaxime Ripard .unlocked_ioctl = video_ioctl2,
254577bbf23SMaxime Ripard .poll = vb2_fop_poll,
255577bbf23SMaxime Ripard .mmap = vb2_fop_mmap,
256577bbf23SMaxime Ripard };
257577bbf23SMaxime Ripard
258577bbf23SMaxime Ripard static const struct v4l2_mbus_framefmt sun4i_csi_pad_fmt_default = {
259577bbf23SMaxime Ripard .width = CSI_DEFAULT_WIDTH,
260577bbf23SMaxime Ripard .height = CSI_DEFAULT_HEIGHT,
261577bbf23SMaxime Ripard .code = MEDIA_BUS_FMT_YUYV8_2X8,
262577bbf23SMaxime Ripard .field = V4L2_FIELD_NONE,
263577bbf23SMaxime Ripard .colorspace = V4L2_COLORSPACE_RAW,
264577bbf23SMaxime Ripard .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
265577bbf23SMaxime Ripard .quantization = V4L2_QUANTIZATION_DEFAULT,
266577bbf23SMaxime Ripard .xfer_func = V4L2_XFER_FUNC_DEFAULT,
267577bbf23SMaxime Ripard };
268577bbf23SMaxime Ripard
sun4i_csi_subdev_init_cfg(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state)269577bbf23SMaxime Ripard static int sun4i_csi_subdev_init_cfg(struct v4l2_subdev *subdev,
270*0d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state)
271577bbf23SMaxime Ripard {
272577bbf23SMaxime Ripard struct v4l2_mbus_framefmt *fmt;
273577bbf23SMaxime Ripard
274*0d346d2aSTomi Valkeinen fmt = v4l2_subdev_get_try_format(subdev, sd_state, CSI_SUBDEV_SINK);
275577bbf23SMaxime Ripard *fmt = sun4i_csi_pad_fmt_default;
276577bbf23SMaxime Ripard
277577bbf23SMaxime Ripard return 0;
278577bbf23SMaxime Ripard }
279577bbf23SMaxime Ripard
sun4i_csi_subdev_get_fmt(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)280577bbf23SMaxime Ripard static int sun4i_csi_subdev_get_fmt(struct v4l2_subdev *subdev,
281*0d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
282577bbf23SMaxime Ripard struct v4l2_subdev_format *fmt)
283577bbf23SMaxime Ripard {
284577bbf23SMaxime Ripard struct sun4i_csi *csi = container_of(subdev, struct sun4i_csi, subdev);
285577bbf23SMaxime Ripard struct v4l2_mbus_framefmt *subdev_fmt;
286577bbf23SMaxime Ripard
287577bbf23SMaxime Ripard if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
288*0d346d2aSTomi Valkeinen subdev_fmt = v4l2_subdev_get_try_format(subdev, sd_state,
289*0d346d2aSTomi Valkeinen fmt->pad);
290577bbf23SMaxime Ripard else
291577bbf23SMaxime Ripard subdev_fmt = &csi->subdev_fmt;
292577bbf23SMaxime Ripard
293577bbf23SMaxime Ripard fmt->format = *subdev_fmt;
294577bbf23SMaxime Ripard
295577bbf23SMaxime Ripard return 0;
296577bbf23SMaxime Ripard }
297577bbf23SMaxime Ripard
sun4i_csi_subdev_set_fmt(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)298577bbf23SMaxime Ripard static int sun4i_csi_subdev_set_fmt(struct v4l2_subdev *subdev,
299*0d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
300577bbf23SMaxime Ripard struct v4l2_subdev_format *fmt)
301577bbf23SMaxime Ripard {
302577bbf23SMaxime Ripard struct sun4i_csi *csi = container_of(subdev, struct sun4i_csi, subdev);
303577bbf23SMaxime Ripard struct v4l2_mbus_framefmt *subdev_fmt;
304577bbf23SMaxime Ripard
305577bbf23SMaxime Ripard if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
306*0d346d2aSTomi Valkeinen subdev_fmt = v4l2_subdev_get_try_format(subdev, sd_state,
307*0d346d2aSTomi Valkeinen fmt->pad);
308577bbf23SMaxime Ripard else
309577bbf23SMaxime Ripard subdev_fmt = &csi->subdev_fmt;
310577bbf23SMaxime Ripard
311577bbf23SMaxime Ripard /* We can only set the format on the sink pad */
312577bbf23SMaxime Ripard if (fmt->pad == CSI_SUBDEV_SINK) {
313577bbf23SMaxime Ripard /* It's the sink, only allow changing the frame size */
314577bbf23SMaxime Ripard subdev_fmt->width = fmt->format.width;
315577bbf23SMaxime Ripard subdev_fmt->height = fmt->format.height;
316577bbf23SMaxime Ripard subdev_fmt->code = fmt->format.code;
317577bbf23SMaxime Ripard }
318577bbf23SMaxime Ripard
319577bbf23SMaxime Ripard fmt->format = *subdev_fmt;
320577bbf23SMaxime Ripard
321577bbf23SMaxime Ripard return 0;
322577bbf23SMaxime Ripard }
323577bbf23SMaxime Ripard
324577bbf23SMaxime Ripard static int
sun4i_csi_subdev_enum_mbus_code(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * mbus)325577bbf23SMaxime Ripard sun4i_csi_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
326*0d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
327577bbf23SMaxime Ripard struct v4l2_subdev_mbus_code_enum *mbus)
328577bbf23SMaxime Ripard {
329577bbf23SMaxime Ripard if (mbus->index >= ARRAY_SIZE(sun4i_csi_formats))
330577bbf23SMaxime Ripard return -EINVAL;
331577bbf23SMaxime Ripard
332577bbf23SMaxime Ripard mbus->code = sun4i_csi_formats[mbus->index].mbus;
333577bbf23SMaxime Ripard
334577bbf23SMaxime Ripard return 0;
335577bbf23SMaxime Ripard }
336577bbf23SMaxime Ripard
337577bbf23SMaxime Ripard static const struct v4l2_subdev_pad_ops sun4i_csi_subdev_pad_ops = {
338577bbf23SMaxime Ripard .link_validate = v4l2_subdev_link_validate_default,
339577bbf23SMaxime Ripard .init_cfg = sun4i_csi_subdev_init_cfg,
340577bbf23SMaxime Ripard .get_fmt = sun4i_csi_subdev_get_fmt,
341577bbf23SMaxime Ripard .set_fmt = sun4i_csi_subdev_set_fmt,
342577bbf23SMaxime Ripard .enum_mbus_code = sun4i_csi_subdev_enum_mbus_code,
343577bbf23SMaxime Ripard };
344577bbf23SMaxime Ripard
345577bbf23SMaxime Ripard const struct v4l2_subdev_ops sun4i_csi_subdev_ops = {
346577bbf23SMaxime Ripard .pad = &sun4i_csi_subdev_pad_ops,
347577bbf23SMaxime Ripard };
348577bbf23SMaxime Ripard
sun4i_csi_v4l2_register(struct sun4i_csi * csi)349577bbf23SMaxime Ripard int sun4i_csi_v4l2_register(struct sun4i_csi *csi)
350577bbf23SMaxime Ripard {
351577bbf23SMaxime Ripard struct video_device *vdev = &csi->vdev;
352577bbf23SMaxime Ripard int ret;
353577bbf23SMaxime Ripard
354577bbf23SMaxime Ripard vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING;
355577bbf23SMaxime Ripard vdev->v4l2_dev = &csi->v4l;
356577bbf23SMaxime Ripard vdev->queue = &csi->queue;
357577bbf23SMaxime Ripard strscpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name));
358577bbf23SMaxime Ripard vdev->release = video_device_release_empty;
359577bbf23SMaxime Ripard vdev->lock = &csi->lock;
360577bbf23SMaxime Ripard
361577bbf23SMaxime Ripard /* Set a default format */
362835fd614SJulia Lawall csi->fmt.pixelformat = sun4i_csi_formats[0].fourcc;
363577bbf23SMaxime Ripard csi->fmt.width = CSI_DEFAULT_WIDTH;
364577bbf23SMaxime Ripard csi->fmt.height = CSI_DEFAULT_HEIGHT;
365577bbf23SMaxime Ripard _sun4i_csi_try_fmt(csi, &csi->fmt);
366577bbf23SMaxime Ripard csi->subdev_fmt = sun4i_csi_pad_fmt_default;
367577bbf23SMaxime Ripard
368577bbf23SMaxime Ripard vdev->fops = &sun4i_csi_fops;
369577bbf23SMaxime Ripard vdev->ioctl_ops = &sun4i_csi_ioctl_ops;
370577bbf23SMaxime Ripard video_set_drvdata(vdev, csi);
371577bbf23SMaxime Ripard
37270cad449SHans Verkuil ret = video_register_device(&csi->vdev, VFL_TYPE_VIDEO, -1);
373577bbf23SMaxime Ripard if (ret)
374577bbf23SMaxime Ripard return ret;
375577bbf23SMaxime Ripard
376577bbf23SMaxime Ripard dev_info(csi->dev, "Device registered as %s\n",
377577bbf23SMaxime Ripard video_device_node_name(vdev));
378577bbf23SMaxime Ripard
379577bbf23SMaxime Ripard return 0;
380577bbf23SMaxime Ripard }
381