1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * V4L2 Driver for Renesas Capture Engine Unit (CEU) interface |
4 | * Copyright (C) 2017-2018 Jacopo Mondi <jacopo+renesas@jmondi.org> |
5 | * |
6 | * Based on soc-camera driver "soc_camera/sh_mobile_ceu_camera.c" |
7 | * Copyright (C) 2008 Magnus Damm |
8 | * |
9 | * Based on V4L2 Driver for PXA camera host - "pxa_camera.c", |
10 | * Copyright (C) 2006, Sascha Hauer, Pengutronix |
11 | * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> |
12 | */ |
13 | |
14 | #include <linux/delay.h> |
15 | #include <linux/device.h> |
16 | #include <linux/dma-mapping.h> |
17 | #include <linux/err.h> |
18 | #include <linux/errno.h> |
19 | #include <linux/interrupt.h> |
20 | #include <linux/io.h> |
21 | #include <linux/kernel.h> |
22 | #include <linux/mm.h> |
23 | #include <linux/module.h> |
24 | #include <linux/of.h> |
25 | #include <linux/of_graph.h> |
26 | #include <linux/platform_device.h> |
27 | #include <linux/pm_runtime.h> |
28 | #include <linux/slab.h> |
29 | #include <linux/time.h> |
30 | #include <linux/videodev2.h> |
31 | |
32 | #include <media/v4l2-async.h> |
33 | #include <media/v4l2-common.h> |
34 | #include <media/v4l2-ctrls.h> |
35 | #include <media/v4l2-dev.h> |
36 | #include <media/v4l2-device.h> |
37 | #include <media/v4l2-event.h> |
38 | #include <media/v4l2-fwnode.h> |
39 | #include <media/v4l2-image-sizes.h> |
40 | #include <media/v4l2-ioctl.h> |
41 | #include <media/v4l2-mediabus.h> |
42 | #include <media/videobuf2-dma-contig.h> |
43 | |
44 | #include <media/drv-intf/renesas-ceu.h> |
45 | |
46 | #define DRIVER_NAME "renesas-ceu" |
47 | |
48 | /* CEU registers offsets and masks. */ |
49 | #define CEU_CAPSR 0x00 /* Capture start register */ |
50 | #define CEU_CAPCR 0x04 /* Capture control register */ |
51 | #define CEU_CAMCR 0x08 /* Capture interface control register */ |
52 | #define CEU_CAMOR 0x10 /* Capture interface offset register */ |
53 | #define CEU_CAPWR 0x14 /* Capture interface width register */ |
54 | #define CEU_CAIFR 0x18 /* Capture interface input format register */ |
55 | #define CEU_CRCNTR 0x28 /* CEU register control register */ |
56 | #define CEU_CRCMPR 0x2c /* CEU register forcible control register */ |
57 | #define CEU_CFLCR 0x30 /* Capture filter control register */ |
58 | #define CEU_CFSZR 0x34 /* Capture filter size clip register */ |
59 | #define CEU_CDWDR 0x38 /* Capture destination width register */ |
60 | #define CEU_CDAYR 0x3c /* Capture data address Y register */ |
61 | #define CEU_CDACR 0x40 /* Capture data address C register */ |
62 | #define CEU_CFWCR 0x5c /* Firewall operation control register */ |
63 | #define CEU_CDOCR 0x64 /* Capture data output control register */ |
64 | #define CEU_CEIER 0x70 /* Capture event interrupt enable register */ |
65 | #define CEU_CETCR 0x74 /* Capture event flag clear register */ |
66 | #define CEU_CSTSR 0x7c /* Capture status register */ |
67 | #define CEU_CSRTR 0x80 /* Capture software reset register */ |
68 | |
69 | /* Data synchronous fetch mode. */ |
70 | #define CEU_CAMCR_JPEG BIT(4) |
71 | |
72 | /* Input components ordering: CEU_CAMCR.DTARY field. */ |
73 | #define CEU_CAMCR_DTARY_8_UYVY (0x00 << 8) |
74 | #define CEU_CAMCR_DTARY_8_VYUY (0x01 << 8) |
75 | #define CEU_CAMCR_DTARY_8_YUYV (0x02 << 8) |
76 | #define CEU_CAMCR_DTARY_8_YVYU (0x03 << 8) |
77 | /* TODO: input components ordering for 16 bits input. */ |
78 | |
79 | /* Bus transfer MTU. */ |
80 | #define CEU_CAPCR_BUS_WIDTH256 (0x3 << 20) |
81 | |
82 | /* Bus width configuration. */ |
83 | #define CEU_CAMCR_DTIF_16BITS BIT(12) |
84 | |
85 | /* No downsampling to planar YUV420 in image fetch mode. */ |
86 | #define CEU_CDOCR_NO_DOWSAMPLE BIT(4) |
87 | |
88 | /* Swap all input data in 8-bit, 16-bits and 32-bits units (Figure 46.45). */ |
89 | #define CEU_CDOCR_SWAP_ENDIANNESS (7) |
90 | |
91 | /* Capture reset and enable bits. */ |
92 | #define CEU_CAPSR_CPKIL BIT(16) |
93 | #define CEU_CAPSR_CE BIT(0) |
94 | |
95 | /* CEU operating flag bit. */ |
96 | #define CEU_CAPCR_CTNCP BIT(16) |
97 | #define CEU_CSTRST_CPTON BIT(0) |
98 | |
99 | /* Platform specific IRQ source flags. */ |
100 | #define CEU_CETCR_ALL_IRQS_RZ 0x397f313 |
101 | #define CEU_CETCR_ALL_IRQS_SH4 0x3d7f313 |
102 | |
103 | /* Prohibited register access interrupt bit. */ |
104 | #define CEU_CETCR_IGRW BIT(4) |
105 | /* One-frame capture end interrupt. */ |
106 | #define CEU_CEIER_CPE BIT(0) |
107 | /* VBP error. */ |
108 | #define CEU_CEIER_VBP BIT(20) |
109 | #define CEU_CEIER_MASK (CEU_CEIER_CPE | CEU_CEIER_VBP) |
110 | |
111 | #define CEU_MAX_WIDTH 2560 |
112 | #define CEU_MAX_HEIGHT 1920 |
113 | #define CEU_MAX_BPL 8188 |
114 | #define CEU_W_MAX(w) ((w) < CEU_MAX_WIDTH ? (w) : CEU_MAX_WIDTH) |
115 | #define CEU_H_MAX(h) ((h) < CEU_MAX_HEIGHT ? (h) : CEU_MAX_HEIGHT) |
116 | |
117 | /* |
118 | * ceu_bus_fmt - describe a 8-bits yuyv format the sensor can produce |
119 | * |
120 | * @mbus_code: bus format code |
121 | * @fmt_order: CEU_CAMCR.DTARY ordering of input components (Y, Cb, Cr) |
122 | * @fmt_order_swap: swapped CEU_CAMCR.DTARY ordering of input components |
123 | * (Y, Cr, Cb) |
124 | * @swapped: does Cr appear before Cb? |
125 | * @bps: number of bits sent over bus for each sample |
126 | * @bpp: number of bits per pixels unit |
127 | */ |
128 | struct ceu_mbus_fmt { |
129 | u32 mbus_code; |
130 | u32 fmt_order; |
131 | u32 fmt_order_swap; |
132 | bool swapped; |
133 | u8 bps; |
134 | u8 bpp; |
135 | }; |
136 | |
137 | /* |
138 | * ceu_buffer - Link vb2 buffer to the list of available buffers. |
139 | */ |
140 | struct ceu_buffer { |
141 | struct vb2_v4l2_buffer vb; |
142 | struct list_head queue; |
143 | }; |
144 | |
145 | static inline struct ceu_buffer *vb2_to_ceu(struct vb2_v4l2_buffer *vbuf) |
146 | { |
147 | return container_of(vbuf, struct ceu_buffer, vb); |
148 | } |
149 | |
150 | /* |
151 | * ceu_subdev - Wraps v4l2 sub-device and provides async subdevice. |
152 | */ |
153 | struct ceu_subdev { |
154 | struct v4l2_async_connection asd; |
155 | struct v4l2_subdev *v4l2_sd; |
156 | |
157 | /* per-subdevice mbus configuration options */ |
158 | unsigned int mbus_flags; |
159 | struct ceu_mbus_fmt mbus_fmt; |
160 | }; |
161 | |
162 | static struct ceu_subdev *to_ceu_subdev(struct v4l2_async_connection *asd) |
163 | { |
164 | return container_of(asd, struct ceu_subdev, asd); |
165 | } |
166 | |
167 | /* |
168 | * ceu_device - CEU device instance |
169 | */ |
170 | struct ceu_device { |
171 | struct device *dev; |
172 | struct video_device vdev; |
173 | struct v4l2_device v4l2_dev; |
174 | |
175 | /* subdevices descriptors */ |
176 | struct ceu_subdev **subdevs; |
177 | /* the subdevice currently in use */ |
178 | struct ceu_subdev *sd; |
179 | unsigned int sd_index; |
180 | unsigned int num_sd; |
181 | |
182 | /* platform specific mask with all IRQ sources flagged */ |
183 | u32 irq_mask; |
184 | |
185 | /* currently configured field and pixel format */ |
186 | enum v4l2_field field; |
187 | struct v4l2_pix_format_mplane v4l2_pix; |
188 | |
189 | /* async subdev notification helpers */ |
190 | struct v4l2_async_notifier notifier; |
191 | |
192 | /* vb2 queue, capture buffer list and active buffer pointer */ |
193 | struct vb2_queue vb2_vq; |
194 | struct list_head capture; |
195 | struct vb2_v4l2_buffer *active; |
196 | unsigned int sequence; |
197 | |
198 | /* mlock - lock access to interface reset and vb2 queue */ |
199 | struct mutex mlock; |
200 | |
201 | /* lock - lock access to capture buffer queue and active buffer */ |
202 | spinlock_t lock; |
203 | |
204 | /* base - CEU memory base address */ |
205 | void __iomem *base; |
206 | }; |
207 | |
208 | static inline struct ceu_device *v4l2_to_ceu(struct v4l2_device *v4l2_dev) |
209 | { |
210 | return container_of(v4l2_dev, struct ceu_device, v4l2_dev); |
211 | } |
212 | |
213 | /* --- CEU memory output formats --- */ |
214 | |
215 | /* |
216 | * ceu_fmt - describe a memory output format supported by CEU interface. |
217 | * |
218 | * @fourcc: memory layout fourcc format code |
219 | * @bpp: number of bits for each pixel stored in memory |
220 | */ |
221 | struct ceu_fmt { |
222 | u32 fourcc; |
223 | u32 bpp; |
224 | }; |
225 | |
226 | /* |
227 | * ceu_format_list - List of supported memory output formats |
228 | * |
229 | * If sensor provides any YUYV bus format, all the following planar memory |
230 | * formats are available thanks to CEU re-ordering and sub-sampling |
231 | * capabilities. |
232 | */ |
233 | static const struct ceu_fmt ceu_fmt_list[] = { |
234 | { |
235 | .fourcc = V4L2_PIX_FMT_NV16, |
236 | .bpp = 16, |
237 | }, |
238 | { |
239 | .fourcc = V4L2_PIX_FMT_NV61, |
240 | .bpp = 16, |
241 | }, |
242 | { |
243 | .fourcc = V4L2_PIX_FMT_NV12, |
244 | .bpp = 12, |
245 | }, |
246 | { |
247 | .fourcc = V4L2_PIX_FMT_NV21, |
248 | .bpp = 12, |
249 | }, |
250 | { |
251 | .fourcc = V4L2_PIX_FMT_YUYV, |
252 | .bpp = 16, |
253 | }, |
254 | { |
255 | .fourcc = V4L2_PIX_FMT_UYVY, |
256 | .bpp = 16, |
257 | }, |
258 | { |
259 | .fourcc = V4L2_PIX_FMT_YVYU, |
260 | .bpp = 16, |
261 | }, |
262 | { |
263 | .fourcc = V4L2_PIX_FMT_VYUY, |
264 | .bpp = 16, |
265 | }, |
266 | }; |
267 | |
268 | static const struct ceu_fmt *get_ceu_fmt_from_fourcc(unsigned int fourcc) |
269 | { |
270 | const struct ceu_fmt *fmt = &ceu_fmt_list[0]; |
271 | unsigned int i; |
272 | |
273 | for (i = 0; i < ARRAY_SIZE(ceu_fmt_list); i++, fmt++) |
274 | if (fmt->fourcc == fourcc) |
275 | return fmt; |
276 | |
277 | return NULL; |
278 | } |
279 | |
280 | static bool ceu_fmt_mplane(struct v4l2_pix_format_mplane *pix) |
281 | { |
282 | switch (pix->pixelformat) { |
283 | case V4L2_PIX_FMT_YUYV: |
284 | case V4L2_PIX_FMT_UYVY: |
285 | case V4L2_PIX_FMT_YVYU: |
286 | case V4L2_PIX_FMT_VYUY: |
287 | return false; |
288 | case V4L2_PIX_FMT_NV16: |
289 | case V4L2_PIX_FMT_NV61: |
290 | case V4L2_PIX_FMT_NV12: |
291 | case V4L2_PIX_FMT_NV21: |
292 | return true; |
293 | default: |
294 | return false; |
295 | } |
296 | } |
297 | |
298 | /* --- CEU HW operations --- */ |
299 | |
300 | static void ceu_write(struct ceu_device *priv, unsigned int reg_offs, u32 data) |
301 | { |
302 | iowrite32(data, priv->base + reg_offs); |
303 | } |
304 | |
305 | static u32 ceu_read(struct ceu_device *priv, unsigned int reg_offs) |
306 | { |
307 | return ioread32(priv->base + reg_offs); |
308 | } |
309 | |
310 | /* |
311 | * ceu_soft_reset() - Software reset the CEU interface. |
312 | * @ceu_device: CEU device. |
313 | * |
314 | * Returns 0 for success, -EIO for error. |
315 | */ |
316 | static int ceu_soft_reset(struct ceu_device *ceudev) |
317 | { |
318 | unsigned int i; |
319 | |
320 | ceu_write(priv: ceudev, CEU_CAPSR, CEU_CAPSR_CPKIL); |
321 | |
322 | for (i = 0; i < 100; i++) { |
323 | if (!(ceu_read(priv: ceudev, CEU_CSTSR) & CEU_CSTRST_CPTON)) |
324 | break; |
325 | udelay(1); |
326 | } |
327 | |
328 | if (i == 100) { |
329 | dev_err(ceudev->dev, "soft reset time out\n" ); |
330 | return -EIO; |
331 | } |
332 | |
333 | for (i = 0; i < 100; i++) { |
334 | if (!(ceu_read(priv: ceudev, CEU_CAPSR) & CEU_CAPSR_CPKIL)) |
335 | return 0; |
336 | udelay(1); |
337 | } |
338 | |
339 | /* If we get here, CEU has not reset properly. */ |
340 | return -EIO; |
341 | } |
342 | |
343 | /* --- CEU Capture Operations --- */ |
344 | |
345 | /* |
346 | * ceu_hw_config() - Configure CEU interface registers. |
347 | */ |
348 | static int ceu_hw_config(struct ceu_device *ceudev) |
349 | { |
350 | u32 camcr, cdocr, cfzsr, cdwdr, capwr; |
351 | struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix; |
352 | struct ceu_subdev *ceu_sd = ceudev->sd; |
353 | struct ceu_mbus_fmt *mbus_fmt = &ceu_sd->mbus_fmt; |
354 | unsigned int mbus_flags = ceu_sd->mbus_flags; |
355 | |
356 | /* Start configuring CEU registers */ |
357 | ceu_write(priv: ceudev, CEU_CAIFR, data: 0); |
358 | ceu_write(priv: ceudev, CEU_CFWCR, data: 0); |
359 | ceu_write(priv: ceudev, CEU_CRCNTR, data: 0); |
360 | ceu_write(priv: ceudev, CEU_CRCMPR, data: 0); |
361 | |
362 | /* Set the frame capture period for both image capture and data sync. */ |
363 | capwr = (pix->height << 16) | pix->width * mbus_fmt->bpp / 8; |
364 | |
365 | /* |
366 | * Swap input data endianness by default. |
367 | * In data fetch mode bytes are received in chunks of 8 bytes. |
368 | * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first) |
369 | * The data is however by default written to memory in reverse order: |
370 | * D7, D6, D5, D4, D3, D2, D1, D0 (D7 written to lowest byte) |
371 | * |
372 | * Use CEU_CDOCR[2:0] to swap data ordering. |
373 | */ |
374 | cdocr = CEU_CDOCR_SWAP_ENDIANNESS; |
375 | |
376 | /* |
377 | * Configure CAMCR and CDOCR: |
378 | * match input components ordering with memory output format and |
379 | * handle downsampling to YUV420. |
380 | * |
381 | * If the memory output planar format is 'swapped' (Cr before Cb) and |
382 | * input format is not, use the swapped version of CAMCR.DTARY. |
383 | * |
384 | * If the memory output planar format is not 'swapped' (Cb before Cr) |
385 | * and input format is, use the swapped version of CAMCR.DTARY. |
386 | * |
387 | * CEU by default downsample to planar YUV420 (CDCOR[4] = 0). |
388 | * If output is planar YUV422 set CDOCR[4] = 1 |
389 | * |
390 | * No downsample for data fetch sync mode. |
391 | */ |
392 | switch (pix->pixelformat) { |
393 | /* Data fetch sync mode */ |
394 | case V4L2_PIX_FMT_YUYV: |
395 | case V4L2_PIX_FMT_YVYU: |
396 | case V4L2_PIX_FMT_UYVY: |
397 | case V4L2_PIX_FMT_VYUY: |
398 | camcr = CEU_CAMCR_JPEG; |
399 | cdocr |= CEU_CDOCR_NO_DOWSAMPLE; |
400 | cfzsr = (pix->height << 16) | pix->width; |
401 | cdwdr = pix->plane_fmt[0].bytesperline; |
402 | break; |
403 | |
404 | /* Non-swapped planar image capture mode. */ |
405 | case V4L2_PIX_FMT_NV16: |
406 | cdocr |= CEU_CDOCR_NO_DOWSAMPLE; |
407 | fallthrough; |
408 | case V4L2_PIX_FMT_NV12: |
409 | if (mbus_fmt->swapped) |
410 | camcr = mbus_fmt->fmt_order_swap; |
411 | else |
412 | camcr = mbus_fmt->fmt_order; |
413 | |
414 | cfzsr = (pix->height << 16) | pix->width; |
415 | cdwdr = pix->width; |
416 | break; |
417 | |
418 | /* Swapped planar image capture mode. */ |
419 | case V4L2_PIX_FMT_NV61: |
420 | cdocr |= CEU_CDOCR_NO_DOWSAMPLE; |
421 | fallthrough; |
422 | case V4L2_PIX_FMT_NV21: |
423 | if (mbus_fmt->swapped) |
424 | camcr = mbus_fmt->fmt_order; |
425 | else |
426 | camcr = mbus_fmt->fmt_order_swap; |
427 | |
428 | cfzsr = (pix->height << 16) | pix->width; |
429 | cdwdr = pix->width; |
430 | break; |
431 | |
432 | default: |
433 | return -EINVAL; |
434 | } |
435 | |
436 | camcr |= mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; |
437 | camcr |= mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; |
438 | |
439 | /* TODO: handle 16 bit bus width with DTIF bit in CAMCR */ |
440 | ceu_write(priv: ceudev, CEU_CAMCR, data: camcr); |
441 | ceu_write(priv: ceudev, CEU_CDOCR, data: cdocr); |
442 | ceu_write(priv: ceudev, CEU_CAPCR, CEU_CAPCR_BUS_WIDTH256); |
443 | |
444 | /* |
445 | * TODO: make CAMOR offsets configurable. |
446 | * CAMOR wants to know the number of blanks between a VS/HS signal |
447 | * and valid data. This value should actually come from the sensor... |
448 | */ |
449 | ceu_write(priv: ceudev, CEU_CAMOR, data: 0); |
450 | |
451 | /* TODO: 16 bit bus width require re-calculation of cdwdr and cfzsr */ |
452 | ceu_write(priv: ceudev, CEU_CAPWR, data: capwr); |
453 | ceu_write(priv: ceudev, CEU_CFSZR, data: cfzsr); |
454 | ceu_write(priv: ceudev, CEU_CDWDR, data: cdwdr); |
455 | |
456 | return 0; |
457 | } |
458 | |
459 | /* |
460 | * ceu_capture() - Trigger start of a capture sequence. |
461 | * |
462 | * Program the CEU DMA registers with addresses where to transfer image data. |
463 | */ |
464 | static int ceu_capture(struct ceu_device *ceudev) |
465 | { |
466 | struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix; |
467 | dma_addr_t phys_addr_top; |
468 | |
469 | phys_addr_top = |
470 | vb2_dma_contig_plane_dma_addr(vb: &ceudev->active->vb2_buf, plane_no: 0); |
471 | ceu_write(priv: ceudev, CEU_CDAYR, data: phys_addr_top); |
472 | |
473 | /* Ignore CbCr plane for non multi-planar image formats. */ |
474 | if (ceu_fmt_mplane(pix)) { |
475 | phys_addr_top = |
476 | vb2_dma_contig_plane_dma_addr(vb: &ceudev->active->vb2_buf, |
477 | plane_no: 1); |
478 | ceu_write(priv: ceudev, CEU_CDACR, data: phys_addr_top); |
479 | } |
480 | |
481 | /* |
482 | * Trigger new capture start: once for each frame, as we work in |
483 | * one-frame capture mode. |
484 | */ |
485 | ceu_write(priv: ceudev, CEU_CAPSR, CEU_CAPSR_CE); |
486 | |
487 | return 0; |
488 | } |
489 | |
490 | static irqreturn_t ceu_irq(int irq, void *data) |
491 | { |
492 | struct ceu_device *ceudev = data; |
493 | struct vb2_v4l2_buffer *vbuf; |
494 | struct ceu_buffer *buf; |
495 | u32 status; |
496 | |
497 | /* Clean interrupt status. */ |
498 | status = ceu_read(priv: ceudev, CEU_CETCR); |
499 | ceu_write(priv: ceudev, CEU_CETCR, data: ~ceudev->irq_mask); |
500 | |
501 | /* Unexpected interrupt. */ |
502 | if (!(status & CEU_CEIER_MASK)) |
503 | return IRQ_NONE; |
504 | |
505 | spin_lock(lock: &ceudev->lock); |
506 | |
507 | /* Stale interrupt from a released buffer, ignore it. */ |
508 | vbuf = ceudev->active; |
509 | if (!vbuf) { |
510 | spin_unlock(lock: &ceudev->lock); |
511 | return IRQ_HANDLED; |
512 | } |
513 | |
514 | /* |
515 | * When a VBP interrupt occurs, no capture end interrupt will occur |
516 | * and the image of that frame is not captured correctly. |
517 | */ |
518 | if (status & CEU_CEIER_VBP) { |
519 | dev_err(ceudev->dev, "VBP interrupt: abort capture\n" ); |
520 | goto error_irq_out; |
521 | } |
522 | |
523 | /* Prepare to return the 'previous' buffer. */ |
524 | vbuf->vb2_buf.timestamp = ktime_get_ns(); |
525 | vbuf->sequence = ceudev->sequence++; |
526 | vbuf->field = ceudev->field; |
527 | |
528 | /* Prepare a new 'active' buffer and trigger a new capture. */ |
529 | if (!list_empty(head: &ceudev->capture)) { |
530 | buf = list_first_entry(&ceudev->capture, struct ceu_buffer, |
531 | queue); |
532 | list_del(entry: &buf->queue); |
533 | ceudev->active = &buf->vb; |
534 | |
535 | ceu_capture(ceudev); |
536 | } |
537 | |
538 | /* Return the 'previous' buffer. */ |
539 | vb2_buffer_done(vb: &vbuf->vb2_buf, state: VB2_BUF_STATE_DONE); |
540 | |
541 | spin_unlock(lock: &ceudev->lock); |
542 | |
543 | return IRQ_HANDLED; |
544 | |
545 | error_irq_out: |
546 | /* Return the 'previous' buffer and all queued ones. */ |
547 | vb2_buffer_done(vb: &vbuf->vb2_buf, state: VB2_BUF_STATE_ERROR); |
548 | |
549 | list_for_each_entry(buf, &ceudev->capture, queue) |
550 | vb2_buffer_done(vb: &buf->vb.vb2_buf, state: VB2_BUF_STATE_ERROR); |
551 | |
552 | spin_unlock(lock: &ceudev->lock); |
553 | |
554 | return IRQ_HANDLED; |
555 | } |
556 | |
557 | /* --- CEU Videobuf2 operations --- */ |
558 | |
559 | static void ceu_update_plane_sizes(struct v4l2_plane_pix_format *plane, |
560 | unsigned int bpl, unsigned int szimage) |
561 | { |
562 | memset(plane, 0, sizeof(*plane)); |
563 | |
564 | plane->sizeimage = szimage; |
565 | if (plane->bytesperline < bpl || plane->bytesperline > CEU_MAX_BPL) |
566 | plane->bytesperline = bpl; |
567 | } |
568 | |
569 | /* |
570 | * ceu_calc_plane_sizes() - Fill per-plane 'struct v4l2_plane_pix_format' |
571 | * information according to the currently configured |
572 | * pixel format. |
573 | * @ceu_device: CEU device. |
574 | * @ceu_fmt: Active image format. |
575 | * @pix: Pixel format information (store line width and image sizes) |
576 | */ |
577 | static void ceu_calc_plane_sizes(struct ceu_device *ceudev, |
578 | const struct ceu_fmt *ceu_fmt, |
579 | struct v4l2_pix_format_mplane *pix) |
580 | { |
581 | unsigned int bpl, szimage; |
582 | |
583 | switch (pix->pixelformat) { |
584 | case V4L2_PIX_FMT_YUYV: |
585 | case V4L2_PIX_FMT_UYVY: |
586 | case V4L2_PIX_FMT_YVYU: |
587 | case V4L2_PIX_FMT_VYUY: |
588 | pix->num_planes = 1; |
589 | bpl = pix->width * ceu_fmt->bpp / 8; |
590 | szimage = pix->height * bpl; |
591 | ceu_update_plane_sizes(plane: &pix->plane_fmt[0], bpl, szimage); |
592 | break; |
593 | |
594 | case V4L2_PIX_FMT_NV12: |
595 | case V4L2_PIX_FMT_NV21: |
596 | pix->num_planes = 2; |
597 | bpl = pix->width; |
598 | szimage = pix->height * pix->width; |
599 | ceu_update_plane_sizes(plane: &pix->plane_fmt[0], bpl, szimage); |
600 | ceu_update_plane_sizes(plane: &pix->plane_fmt[1], bpl, szimage: szimage / 2); |
601 | break; |
602 | |
603 | case V4L2_PIX_FMT_NV16: |
604 | case V4L2_PIX_FMT_NV61: |
605 | default: |
606 | pix->num_planes = 2; |
607 | bpl = pix->width; |
608 | szimage = pix->height * pix->width; |
609 | ceu_update_plane_sizes(plane: &pix->plane_fmt[0], bpl, szimage); |
610 | ceu_update_plane_sizes(plane: &pix->plane_fmt[1], bpl, szimage); |
611 | break; |
612 | } |
613 | } |
614 | |
615 | /* |
616 | * ceu_vb2_setup() - is called to check whether the driver can accept the |
617 | * requested number of buffers and to fill in plane sizes |
618 | * for the current frame format, if required. |
619 | */ |
620 | static int ceu_vb2_setup(struct vb2_queue *vq, unsigned int *count, |
621 | unsigned int *num_planes, unsigned int sizes[], |
622 | struct device *alloc_devs[]) |
623 | { |
624 | struct ceu_device *ceudev = vb2_get_drv_priv(q: vq); |
625 | struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix; |
626 | unsigned int i; |
627 | |
628 | /* num_planes is set: just check plane sizes. */ |
629 | if (*num_planes) { |
630 | for (i = 0; i < pix->num_planes; i++) |
631 | if (sizes[i] < pix->plane_fmt[i].sizeimage) |
632 | return -EINVAL; |
633 | |
634 | return 0; |
635 | } |
636 | |
637 | /* num_planes not set: called from REQBUFS, just set plane sizes. */ |
638 | *num_planes = pix->num_planes; |
639 | for (i = 0; i < pix->num_planes; i++) |
640 | sizes[i] = pix->plane_fmt[i].sizeimage; |
641 | |
642 | return 0; |
643 | } |
644 | |
645 | static void ceu_vb2_queue(struct vb2_buffer *vb) |
646 | { |
647 | struct ceu_device *ceudev = vb2_get_drv_priv(q: vb->vb2_queue); |
648 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
649 | struct ceu_buffer *buf = vb2_to_ceu(vbuf); |
650 | unsigned long irqflags; |
651 | |
652 | spin_lock_irqsave(&ceudev->lock, irqflags); |
653 | list_add_tail(new: &buf->queue, head: &ceudev->capture); |
654 | spin_unlock_irqrestore(lock: &ceudev->lock, flags: irqflags); |
655 | } |
656 | |
657 | static int ceu_vb2_prepare(struct vb2_buffer *vb) |
658 | { |
659 | struct ceu_device *ceudev = vb2_get_drv_priv(q: vb->vb2_queue); |
660 | struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix; |
661 | unsigned int i; |
662 | |
663 | for (i = 0; i < pix->num_planes; i++) { |
664 | if (vb2_plane_size(vb, plane_no: i) < pix->plane_fmt[i].sizeimage) { |
665 | dev_err(ceudev->dev, |
666 | "Plane size too small (%lu < %u)\n" , |
667 | vb2_plane_size(vb, i), |
668 | pix->plane_fmt[i].sizeimage); |
669 | return -EINVAL; |
670 | } |
671 | |
672 | vb2_set_plane_payload(vb, plane_no: i, size: pix->plane_fmt[i].sizeimage); |
673 | } |
674 | |
675 | return 0; |
676 | } |
677 | |
678 | static int ceu_start_streaming(struct vb2_queue *vq, unsigned int count) |
679 | { |
680 | struct ceu_device *ceudev = vb2_get_drv_priv(q: vq); |
681 | struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; |
682 | struct ceu_buffer *buf; |
683 | unsigned long irqflags; |
684 | int ret; |
685 | |
686 | /* Program the CEU interface according to the CEU image format. */ |
687 | ret = ceu_hw_config(ceudev); |
688 | if (ret) |
689 | goto error_return_bufs; |
690 | |
691 | ret = v4l2_subdev_call(v4l2_sd, video, s_stream, 1); |
692 | if (ret && ret != -ENOIOCTLCMD) { |
693 | dev_dbg(ceudev->dev, |
694 | "Subdevice failed to start streaming: %d\n" , ret); |
695 | goto error_return_bufs; |
696 | } |
697 | |
698 | spin_lock_irqsave(&ceudev->lock, irqflags); |
699 | ceudev->sequence = 0; |
700 | |
701 | /* Grab the first available buffer and trigger the first capture. */ |
702 | buf = list_first_entry(&ceudev->capture, struct ceu_buffer, |
703 | queue); |
704 | |
705 | list_del(entry: &buf->queue); |
706 | ceudev->active = &buf->vb; |
707 | |
708 | /* Clean and program interrupts for first capture. */ |
709 | ceu_write(priv: ceudev, CEU_CETCR, data: ~ceudev->irq_mask); |
710 | ceu_write(priv: ceudev, CEU_CEIER, CEU_CEIER_MASK); |
711 | |
712 | ceu_capture(ceudev); |
713 | |
714 | spin_unlock_irqrestore(lock: &ceudev->lock, flags: irqflags); |
715 | |
716 | return 0; |
717 | |
718 | error_return_bufs: |
719 | spin_lock_irqsave(&ceudev->lock, irqflags); |
720 | list_for_each_entry(buf, &ceudev->capture, queue) |
721 | vb2_buffer_done(vb: &ceudev->active->vb2_buf, |
722 | state: VB2_BUF_STATE_QUEUED); |
723 | ceudev->active = NULL; |
724 | spin_unlock_irqrestore(lock: &ceudev->lock, flags: irqflags); |
725 | |
726 | return ret; |
727 | } |
728 | |
729 | static void ceu_stop_streaming(struct vb2_queue *vq) |
730 | { |
731 | struct ceu_device *ceudev = vb2_get_drv_priv(q: vq); |
732 | struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; |
733 | struct ceu_buffer *buf; |
734 | unsigned long irqflags; |
735 | |
736 | /* Clean and disable interrupt sources. */ |
737 | ceu_write(priv: ceudev, CEU_CETCR, |
738 | data: ceu_read(priv: ceudev, CEU_CETCR) & ceudev->irq_mask); |
739 | ceu_write(priv: ceudev, CEU_CEIER, CEU_CEIER_MASK); |
740 | |
741 | v4l2_subdev_call(v4l2_sd, video, s_stream, 0); |
742 | |
743 | spin_lock_irqsave(&ceudev->lock, irqflags); |
744 | if (ceudev->active) { |
745 | vb2_buffer_done(vb: &ceudev->active->vb2_buf, |
746 | state: VB2_BUF_STATE_ERROR); |
747 | ceudev->active = NULL; |
748 | } |
749 | |
750 | /* Release all queued buffers. */ |
751 | list_for_each_entry(buf, &ceudev->capture, queue) |
752 | vb2_buffer_done(vb: &buf->vb.vb2_buf, state: VB2_BUF_STATE_ERROR); |
753 | INIT_LIST_HEAD(list: &ceudev->capture); |
754 | |
755 | spin_unlock_irqrestore(lock: &ceudev->lock, flags: irqflags); |
756 | |
757 | ceu_soft_reset(ceudev); |
758 | } |
759 | |
760 | static const struct vb2_ops ceu_vb2_ops = { |
761 | .queue_setup = ceu_vb2_setup, |
762 | .buf_queue = ceu_vb2_queue, |
763 | .buf_prepare = ceu_vb2_prepare, |
764 | .wait_prepare = vb2_ops_wait_prepare, |
765 | .wait_finish = vb2_ops_wait_finish, |
766 | .start_streaming = ceu_start_streaming, |
767 | .stop_streaming = ceu_stop_streaming, |
768 | }; |
769 | |
770 | /* --- CEU image formats handling --- */ |
771 | |
772 | /* |
773 | * __ceu_try_fmt() - test format on CEU and sensor |
774 | * @ceudev: The CEU device. |
775 | * @v4l2_fmt: format to test. |
776 | * @sd_mbus_code: the media bus code accepted by the subdevice; output param. |
777 | * |
778 | * Returns 0 for success, < 0 for errors. |
779 | */ |
780 | static int __ceu_try_fmt(struct ceu_device *ceudev, struct v4l2_format *v4l2_fmt, |
781 | u32 *sd_mbus_code) |
782 | { |
783 | struct ceu_subdev *ceu_sd = ceudev->sd; |
784 | struct v4l2_pix_format_mplane *pix = &v4l2_fmt->fmt.pix_mp; |
785 | struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; |
786 | struct v4l2_subdev_pad_config pad_cfg; |
787 | struct v4l2_subdev_state pad_state = { |
788 | .pads = &pad_cfg, |
789 | }; |
790 | const struct ceu_fmt *ceu_fmt; |
791 | u32 mbus_code_old; |
792 | u32 mbus_code; |
793 | int ret; |
794 | |
795 | /* |
796 | * Set format on sensor sub device: bus format used to produce memory |
797 | * format is selected depending on YUV component ordering or |
798 | * at initialization time. |
799 | */ |
800 | struct v4l2_subdev_format sd_format = { |
801 | .which = V4L2_SUBDEV_FORMAT_TRY, |
802 | }; |
803 | |
804 | mbus_code_old = ceu_sd->mbus_fmt.mbus_code; |
805 | |
806 | switch (pix->pixelformat) { |
807 | case V4L2_PIX_FMT_YUYV: |
808 | mbus_code = MEDIA_BUS_FMT_YUYV8_2X8; |
809 | break; |
810 | case V4L2_PIX_FMT_UYVY: |
811 | mbus_code = MEDIA_BUS_FMT_UYVY8_2X8; |
812 | break; |
813 | case V4L2_PIX_FMT_YVYU: |
814 | mbus_code = MEDIA_BUS_FMT_YVYU8_2X8; |
815 | break; |
816 | case V4L2_PIX_FMT_VYUY: |
817 | mbus_code = MEDIA_BUS_FMT_VYUY8_2X8; |
818 | break; |
819 | case V4L2_PIX_FMT_NV16: |
820 | case V4L2_PIX_FMT_NV61: |
821 | case V4L2_PIX_FMT_NV12: |
822 | case V4L2_PIX_FMT_NV21: |
823 | mbus_code = ceu_sd->mbus_fmt.mbus_code; |
824 | break; |
825 | |
826 | default: |
827 | pix->pixelformat = V4L2_PIX_FMT_NV16; |
828 | mbus_code = ceu_sd->mbus_fmt.mbus_code; |
829 | break; |
830 | } |
831 | |
832 | ceu_fmt = get_ceu_fmt_from_fourcc(fourcc: pix->pixelformat); |
833 | |
834 | /* CFSZR requires height and width to be 4-pixel aligned. */ |
835 | v4l_bound_align_image(width: &pix->width, wmin: 2, CEU_MAX_WIDTH, walign: 4, |
836 | height: &pix->height, hmin: 4, CEU_MAX_HEIGHT, halign: 4, salign: 0); |
837 | |
838 | v4l2_fill_mbus_format_mplane(mbus_fmt: &sd_format.format, pix_mp_fmt: pix); |
839 | |
840 | /* |
841 | * Try with the mbus_code matching YUYV components ordering first, |
842 | * if that one fails, fallback to default selected at initialization |
843 | * time. |
844 | */ |
845 | sd_format.format.code = mbus_code; |
846 | ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt, &pad_state, &sd_format); |
847 | if (ret) { |
848 | if (ret == -EINVAL) { |
849 | /* fallback */ |
850 | sd_format.format.code = mbus_code_old; |
851 | ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt, |
852 | &pad_state, &sd_format); |
853 | } |
854 | |
855 | if (ret) |
856 | return ret; |
857 | } |
858 | |
859 | /* Apply size returned by sensor as the CEU can't scale. */ |
860 | v4l2_fill_pix_format_mplane(pix_mp_fmt: pix, mbus_fmt: &sd_format.format); |
861 | |
862 | /* Calculate per-plane sizes based on image format. */ |
863 | ceu_calc_plane_sizes(ceudev, ceu_fmt, pix); |
864 | |
865 | /* Report to caller the configured mbus format. */ |
866 | *sd_mbus_code = sd_format.format.code; |
867 | |
868 | return 0; |
869 | } |
870 | |
871 | /* |
872 | * ceu_try_fmt() - Wrapper for __ceu_try_fmt; discard configured mbus_fmt |
873 | */ |
874 | static int ceu_try_fmt(struct ceu_device *ceudev, struct v4l2_format *v4l2_fmt) |
875 | { |
876 | u32 mbus_code; |
877 | |
878 | return __ceu_try_fmt(ceudev, v4l2_fmt, sd_mbus_code: &mbus_code); |
879 | } |
880 | |
881 | /* |
882 | * ceu_set_fmt() - Apply the supplied format to both sensor and CEU |
883 | */ |
884 | static int ceu_set_fmt(struct ceu_device *ceudev, struct v4l2_format *v4l2_fmt) |
885 | { |
886 | struct ceu_subdev *ceu_sd = ceudev->sd; |
887 | struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; |
888 | u32 mbus_code; |
889 | int ret; |
890 | |
891 | /* |
892 | * Set format on sensor sub device: bus format used to produce memory |
893 | * format is selected at initialization time. |
894 | */ |
895 | struct v4l2_subdev_format format = { |
896 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
897 | }; |
898 | |
899 | ret = __ceu_try_fmt(ceudev, v4l2_fmt, sd_mbus_code: &mbus_code); |
900 | if (ret) |
901 | return ret; |
902 | |
903 | format.format.code = mbus_code; |
904 | v4l2_fill_mbus_format_mplane(mbus_fmt: &format.format, pix_mp_fmt: &v4l2_fmt->fmt.pix_mp); |
905 | ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt, NULL, &format); |
906 | if (ret) |
907 | return ret; |
908 | |
909 | ceudev->v4l2_pix = v4l2_fmt->fmt.pix_mp; |
910 | ceudev->field = V4L2_FIELD_NONE; |
911 | |
912 | return 0; |
913 | } |
914 | |
915 | /* |
916 | * ceu_set_default_fmt() - Apply default NV16 memory output format with VGA |
917 | * sizes. |
918 | */ |
919 | static int ceu_set_default_fmt(struct ceu_device *ceudev) |
920 | { |
921 | int ret; |
922 | |
923 | struct v4l2_format v4l2_fmt = { |
924 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, |
925 | .fmt.pix_mp = { |
926 | .width = VGA_WIDTH, |
927 | .height = VGA_HEIGHT, |
928 | .field = V4L2_FIELD_NONE, |
929 | .pixelformat = V4L2_PIX_FMT_NV16, |
930 | .num_planes = 2, |
931 | .plane_fmt = { |
932 | [0] = { |
933 | .sizeimage = VGA_WIDTH * VGA_HEIGHT * 2, |
934 | .bytesperline = VGA_WIDTH * 2, |
935 | }, |
936 | [1] = { |
937 | .sizeimage = VGA_WIDTH * VGA_HEIGHT * 2, |
938 | .bytesperline = VGA_WIDTH * 2, |
939 | }, |
940 | }, |
941 | }, |
942 | }; |
943 | |
944 | ret = ceu_try_fmt(ceudev, v4l2_fmt: &v4l2_fmt); |
945 | if (ret) |
946 | return ret; |
947 | |
948 | ceudev->v4l2_pix = v4l2_fmt.fmt.pix_mp; |
949 | ceudev->field = V4L2_FIELD_NONE; |
950 | |
951 | return 0; |
952 | } |
953 | |
954 | /* |
955 | * ceu_init_mbus_fmt() - Query sensor for supported formats and initialize |
956 | * CEU media bus format used to produce memory formats. |
957 | * |
958 | * Find out if sensor can produce a permutation of 8-bits YUYV bus format. |
959 | * From a single 8-bits YUYV bus format the CEU can produce several memory |
960 | * output formats: |
961 | * - NV[12|21|16|61] through image fetch mode; |
962 | * - YUYV422 if sensor provides YUYV422 |
963 | * |
964 | * TODO: Other YUYV422 permutations through data fetch sync mode and DTARY |
965 | * TODO: Binary data (eg. JPEG) and raw formats through data fetch sync mode |
966 | */ |
967 | static int ceu_init_mbus_fmt(struct ceu_device *ceudev) |
968 | { |
969 | struct ceu_subdev *ceu_sd = ceudev->sd; |
970 | struct ceu_mbus_fmt *mbus_fmt = &ceu_sd->mbus_fmt; |
971 | struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; |
972 | bool yuyv_bus_fmt = false; |
973 | |
974 | struct v4l2_subdev_mbus_code_enum sd_mbus_fmt = { |
975 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
976 | .index = 0, |
977 | }; |
978 | |
979 | /* Find out if sensor can produce any permutation of 8-bits YUYV422. */ |
980 | while (!yuyv_bus_fmt && |
981 | !v4l2_subdev_call(v4l2_sd, pad, enum_mbus_code, |
982 | NULL, &sd_mbus_fmt)) { |
983 | switch (sd_mbus_fmt.code) { |
984 | case MEDIA_BUS_FMT_YUYV8_2X8: |
985 | case MEDIA_BUS_FMT_YVYU8_2X8: |
986 | case MEDIA_BUS_FMT_UYVY8_2X8: |
987 | case MEDIA_BUS_FMT_VYUY8_2X8: |
988 | yuyv_bus_fmt = true; |
989 | break; |
990 | default: |
991 | /* |
992 | * Only support 8-bits YUYV bus formats at the moment; |
993 | * |
994 | * TODO: add support for binary formats (data sync |
995 | * fetch mode). |
996 | */ |
997 | break; |
998 | } |
999 | |
1000 | sd_mbus_fmt.index++; |
1001 | } |
1002 | |
1003 | if (!yuyv_bus_fmt) |
1004 | return -ENXIO; |
1005 | |
1006 | /* |
1007 | * Save the first encountered YUYV format as "mbus_fmt" and use it |
1008 | * to output all planar YUV422 and YUV420 (NV*) formats to memory as |
1009 | * well as for data synch fetch mode (YUYV - YVYU etc. ). |
1010 | */ |
1011 | mbus_fmt->mbus_code = sd_mbus_fmt.code; |
1012 | mbus_fmt->bps = 8; |
1013 | |
1014 | /* Annotate the selected bus format components ordering. */ |
1015 | switch (sd_mbus_fmt.code) { |
1016 | case MEDIA_BUS_FMT_YUYV8_2X8: |
1017 | mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_YUYV; |
1018 | mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_YVYU; |
1019 | mbus_fmt->swapped = false; |
1020 | mbus_fmt->bpp = 16; |
1021 | break; |
1022 | |
1023 | case MEDIA_BUS_FMT_YVYU8_2X8: |
1024 | mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_YVYU; |
1025 | mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_YUYV; |
1026 | mbus_fmt->swapped = true; |
1027 | mbus_fmt->bpp = 16; |
1028 | break; |
1029 | |
1030 | case MEDIA_BUS_FMT_UYVY8_2X8: |
1031 | mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_UYVY; |
1032 | mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_VYUY; |
1033 | mbus_fmt->swapped = false; |
1034 | mbus_fmt->bpp = 16; |
1035 | break; |
1036 | |
1037 | case MEDIA_BUS_FMT_VYUY8_2X8: |
1038 | mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_VYUY; |
1039 | mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_UYVY; |
1040 | mbus_fmt->swapped = true; |
1041 | mbus_fmt->bpp = 16; |
1042 | break; |
1043 | } |
1044 | |
1045 | return 0; |
1046 | } |
1047 | |
1048 | /* --- Runtime PM Handlers --- */ |
1049 | |
1050 | /* |
1051 | * ceu_runtime_resume() - soft-reset the interface and turn sensor power on. |
1052 | */ |
1053 | static int __maybe_unused ceu_runtime_resume(struct device *dev) |
1054 | { |
1055 | struct ceu_device *ceudev = dev_get_drvdata(dev); |
1056 | struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; |
1057 | |
1058 | v4l2_subdev_call(v4l2_sd, core, s_power, 1); |
1059 | |
1060 | ceu_soft_reset(ceudev); |
1061 | |
1062 | return 0; |
1063 | } |
1064 | |
1065 | /* |
1066 | * ceu_runtime_suspend() - disable capture and interrupts and soft-reset. |
1067 | * Turn sensor power off. |
1068 | */ |
1069 | static int __maybe_unused ceu_runtime_suspend(struct device *dev) |
1070 | { |
1071 | struct ceu_device *ceudev = dev_get_drvdata(dev); |
1072 | struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; |
1073 | |
1074 | v4l2_subdev_call(v4l2_sd, core, s_power, 0); |
1075 | |
1076 | ceu_write(priv: ceudev, CEU_CEIER, data: 0); |
1077 | ceu_soft_reset(ceudev); |
1078 | |
1079 | return 0; |
1080 | } |
1081 | |
1082 | /* --- File Operations --- */ |
1083 | |
1084 | static int ceu_open(struct file *file) |
1085 | { |
1086 | struct ceu_device *ceudev = video_drvdata(file); |
1087 | int ret; |
1088 | |
1089 | ret = v4l2_fh_open(filp: file); |
1090 | if (ret) |
1091 | return ret; |
1092 | |
1093 | mutex_lock(&ceudev->mlock); |
1094 | /* Causes soft-reset and sensor power on on first open */ |
1095 | ret = pm_runtime_resume_and_get(dev: ceudev->dev); |
1096 | mutex_unlock(lock: &ceudev->mlock); |
1097 | |
1098 | return ret; |
1099 | } |
1100 | |
1101 | static int ceu_release(struct file *file) |
1102 | { |
1103 | struct ceu_device *ceudev = video_drvdata(file); |
1104 | |
1105 | vb2_fop_release(file); |
1106 | |
1107 | mutex_lock(&ceudev->mlock); |
1108 | /* Causes soft-reset and sensor power down on last close */ |
1109 | pm_runtime_put(dev: ceudev->dev); |
1110 | mutex_unlock(lock: &ceudev->mlock); |
1111 | |
1112 | return 0; |
1113 | } |
1114 | |
1115 | static const struct v4l2_file_operations ceu_fops = { |
1116 | .owner = THIS_MODULE, |
1117 | .open = ceu_open, |
1118 | .release = ceu_release, |
1119 | .unlocked_ioctl = video_ioctl2, |
1120 | .mmap = vb2_fop_mmap, |
1121 | .poll = vb2_fop_poll, |
1122 | }; |
1123 | |
1124 | /* --- Video Device IOCTLs --- */ |
1125 | |
1126 | static int ceu_querycap(struct file *file, void *priv, |
1127 | struct v4l2_capability *cap) |
1128 | { |
1129 | struct ceu_device *ceudev = video_drvdata(file); |
1130 | |
1131 | strscpy(cap->card, "Renesas CEU" , sizeof(cap->card)); |
1132 | strscpy(cap->driver, DRIVER_NAME, sizeof(cap->driver)); |
1133 | snprintf(buf: cap->bus_info, size: sizeof(cap->bus_info), |
1134 | fmt: "platform:renesas-ceu-%s" , dev_name(dev: ceudev->dev)); |
1135 | |
1136 | return 0; |
1137 | } |
1138 | |
1139 | static int ceu_enum_fmt_vid_cap(struct file *file, void *priv, |
1140 | struct v4l2_fmtdesc *f) |
1141 | { |
1142 | const struct ceu_fmt *fmt; |
1143 | |
1144 | if (f->index >= ARRAY_SIZE(ceu_fmt_list)) |
1145 | return -EINVAL; |
1146 | |
1147 | fmt = &ceu_fmt_list[f->index]; |
1148 | f->pixelformat = fmt->fourcc; |
1149 | |
1150 | return 0; |
1151 | } |
1152 | |
1153 | static int ceu_try_fmt_vid_cap(struct file *file, void *priv, |
1154 | struct v4l2_format *f) |
1155 | { |
1156 | struct ceu_device *ceudev = video_drvdata(file); |
1157 | |
1158 | return ceu_try_fmt(ceudev, v4l2_fmt: f); |
1159 | } |
1160 | |
1161 | static int ceu_s_fmt_vid_cap(struct file *file, void *priv, |
1162 | struct v4l2_format *f) |
1163 | { |
1164 | struct ceu_device *ceudev = video_drvdata(file); |
1165 | |
1166 | if (vb2_is_streaming(q: &ceudev->vb2_vq)) |
1167 | return -EBUSY; |
1168 | |
1169 | return ceu_set_fmt(ceudev, v4l2_fmt: f); |
1170 | } |
1171 | |
1172 | static int ceu_g_fmt_vid_cap(struct file *file, void *priv, |
1173 | struct v4l2_format *f) |
1174 | { |
1175 | struct ceu_device *ceudev = video_drvdata(file); |
1176 | |
1177 | f->fmt.pix_mp = ceudev->v4l2_pix; |
1178 | |
1179 | return 0; |
1180 | } |
1181 | |
1182 | static int ceu_enum_input(struct file *file, void *priv, |
1183 | struct v4l2_input *inp) |
1184 | { |
1185 | struct ceu_device *ceudev = video_drvdata(file); |
1186 | |
1187 | if (inp->index >= ceudev->num_sd) |
1188 | return -EINVAL; |
1189 | |
1190 | inp->type = V4L2_INPUT_TYPE_CAMERA; |
1191 | inp->std = 0; |
1192 | snprintf(buf: inp->name, size: sizeof(inp->name), fmt: "Camera %u" , inp->index); |
1193 | |
1194 | return 0; |
1195 | } |
1196 | |
1197 | static int ceu_g_input(struct file *file, void *priv, unsigned int *i) |
1198 | { |
1199 | struct ceu_device *ceudev = video_drvdata(file); |
1200 | |
1201 | *i = ceudev->sd_index; |
1202 | |
1203 | return 0; |
1204 | } |
1205 | |
1206 | static int ceu_s_input(struct file *file, void *priv, unsigned int i) |
1207 | { |
1208 | struct ceu_device *ceudev = video_drvdata(file); |
1209 | struct ceu_subdev *ceu_sd_old; |
1210 | int ret; |
1211 | |
1212 | if (i >= ceudev->num_sd) |
1213 | return -EINVAL; |
1214 | |
1215 | if (vb2_is_streaming(q: &ceudev->vb2_vq)) |
1216 | return -EBUSY; |
1217 | |
1218 | if (i == ceudev->sd_index) |
1219 | return 0; |
1220 | |
1221 | ceu_sd_old = ceudev->sd; |
1222 | ceudev->sd = ceudev->subdevs[i]; |
1223 | |
1224 | /* |
1225 | * Make sure we can generate output image formats and apply |
1226 | * default one. |
1227 | */ |
1228 | ret = ceu_init_mbus_fmt(ceudev); |
1229 | if (ret) { |
1230 | ceudev->sd = ceu_sd_old; |
1231 | return -EINVAL; |
1232 | } |
1233 | |
1234 | ret = ceu_set_default_fmt(ceudev); |
1235 | if (ret) { |
1236 | ceudev->sd = ceu_sd_old; |
1237 | return -EINVAL; |
1238 | } |
1239 | |
1240 | /* Now that we're sure we can use the sensor, power off the old one. */ |
1241 | v4l2_subdev_call(ceu_sd_old->v4l2_sd, core, s_power, 0); |
1242 | v4l2_subdev_call(ceudev->sd->v4l2_sd, core, s_power, 1); |
1243 | |
1244 | ceudev->sd_index = i; |
1245 | |
1246 | return 0; |
1247 | } |
1248 | |
1249 | static int ceu_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) |
1250 | { |
1251 | struct ceu_device *ceudev = video_drvdata(file); |
1252 | |
1253 | return v4l2_g_parm_cap(vdev: video_devdata(file), sd: ceudev->sd->v4l2_sd, a); |
1254 | } |
1255 | |
1256 | static int ceu_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) |
1257 | { |
1258 | struct ceu_device *ceudev = video_drvdata(file); |
1259 | |
1260 | return v4l2_s_parm_cap(vdev: video_devdata(file), sd: ceudev->sd->v4l2_sd, a); |
1261 | } |
1262 | |
1263 | static int ceu_enum_framesizes(struct file *file, void *fh, |
1264 | struct v4l2_frmsizeenum *fsize) |
1265 | { |
1266 | struct ceu_device *ceudev = video_drvdata(file); |
1267 | struct ceu_subdev *ceu_sd = ceudev->sd; |
1268 | const struct ceu_fmt *ceu_fmt; |
1269 | struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; |
1270 | int ret; |
1271 | |
1272 | struct v4l2_subdev_frame_size_enum fse = { |
1273 | .code = ceu_sd->mbus_fmt.mbus_code, |
1274 | .index = fsize->index, |
1275 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
1276 | }; |
1277 | |
1278 | /* Just check if user supplied pixel format is supported. */ |
1279 | ceu_fmt = get_ceu_fmt_from_fourcc(fourcc: fsize->pixel_format); |
1280 | if (!ceu_fmt) |
1281 | return -EINVAL; |
1282 | |
1283 | ret = v4l2_subdev_call(v4l2_sd, pad, enum_frame_size, |
1284 | NULL, &fse); |
1285 | if (ret) |
1286 | return ret; |
1287 | |
1288 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; |
1289 | fsize->discrete.width = CEU_W_MAX(fse.max_width); |
1290 | fsize->discrete.height = CEU_H_MAX(fse.max_height); |
1291 | |
1292 | return 0; |
1293 | } |
1294 | |
1295 | static int ceu_enum_frameintervals(struct file *file, void *fh, |
1296 | struct v4l2_frmivalenum *fival) |
1297 | { |
1298 | struct ceu_device *ceudev = video_drvdata(file); |
1299 | struct ceu_subdev *ceu_sd = ceudev->sd; |
1300 | const struct ceu_fmt *ceu_fmt; |
1301 | struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; |
1302 | int ret; |
1303 | |
1304 | struct v4l2_subdev_frame_interval_enum fie = { |
1305 | .code = ceu_sd->mbus_fmt.mbus_code, |
1306 | .index = fival->index, |
1307 | .width = fival->width, |
1308 | .height = fival->height, |
1309 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
1310 | }; |
1311 | |
1312 | /* Just check if user supplied pixel format is supported. */ |
1313 | ceu_fmt = get_ceu_fmt_from_fourcc(fourcc: fival->pixel_format); |
1314 | if (!ceu_fmt) |
1315 | return -EINVAL; |
1316 | |
1317 | ret = v4l2_subdev_call(v4l2_sd, pad, enum_frame_interval, NULL, |
1318 | &fie); |
1319 | if (ret) |
1320 | return ret; |
1321 | |
1322 | fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; |
1323 | fival->discrete = fie.interval; |
1324 | |
1325 | return 0; |
1326 | } |
1327 | |
1328 | static const struct v4l2_ioctl_ops ceu_ioctl_ops = { |
1329 | .vidioc_querycap = ceu_querycap, |
1330 | |
1331 | .vidioc_enum_fmt_vid_cap = ceu_enum_fmt_vid_cap, |
1332 | .vidioc_try_fmt_vid_cap_mplane = ceu_try_fmt_vid_cap, |
1333 | .vidioc_s_fmt_vid_cap_mplane = ceu_s_fmt_vid_cap, |
1334 | .vidioc_g_fmt_vid_cap_mplane = ceu_g_fmt_vid_cap, |
1335 | |
1336 | .vidioc_enum_input = ceu_enum_input, |
1337 | .vidioc_g_input = ceu_g_input, |
1338 | .vidioc_s_input = ceu_s_input, |
1339 | |
1340 | .vidioc_reqbufs = vb2_ioctl_reqbufs, |
1341 | .vidioc_querybuf = vb2_ioctl_querybuf, |
1342 | .vidioc_qbuf = vb2_ioctl_qbuf, |
1343 | .vidioc_expbuf = vb2_ioctl_expbuf, |
1344 | .vidioc_dqbuf = vb2_ioctl_dqbuf, |
1345 | .vidioc_create_bufs = vb2_ioctl_create_bufs, |
1346 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, |
1347 | .vidioc_streamon = vb2_ioctl_streamon, |
1348 | .vidioc_streamoff = vb2_ioctl_streamoff, |
1349 | |
1350 | .vidioc_g_parm = ceu_g_parm, |
1351 | .vidioc_s_parm = ceu_s_parm, |
1352 | .vidioc_enum_framesizes = ceu_enum_framesizes, |
1353 | .vidioc_enum_frameintervals = ceu_enum_frameintervals, |
1354 | |
1355 | .vidioc_log_status = v4l2_ctrl_log_status, |
1356 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
1357 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
1358 | }; |
1359 | |
1360 | /* |
1361 | * ceu_vdev_release() - release CEU video device memory when last reference |
1362 | * to this driver is closed |
1363 | */ |
1364 | static void ceu_vdev_release(struct video_device *vdev) |
1365 | { |
1366 | struct ceu_device *ceudev = video_get_drvdata(vdev); |
1367 | |
1368 | kfree(objp: ceudev); |
1369 | } |
1370 | |
1371 | static int ceu_notify_bound(struct v4l2_async_notifier *notifier, |
1372 | struct v4l2_subdev *v4l2_sd, |
1373 | struct v4l2_async_connection *asd) |
1374 | { |
1375 | struct v4l2_device *v4l2_dev = notifier->v4l2_dev; |
1376 | struct ceu_device *ceudev = v4l2_to_ceu(v4l2_dev); |
1377 | struct ceu_subdev *ceu_sd = to_ceu_subdev(asd); |
1378 | |
1379 | ceu_sd->v4l2_sd = v4l2_sd; |
1380 | ceudev->num_sd++; |
1381 | |
1382 | return 0; |
1383 | } |
1384 | |
1385 | static int ceu_notify_complete(struct v4l2_async_notifier *notifier) |
1386 | { |
1387 | struct v4l2_device *v4l2_dev = notifier->v4l2_dev; |
1388 | struct ceu_device *ceudev = v4l2_to_ceu(v4l2_dev); |
1389 | struct video_device *vdev = &ceudev->vdev; |
1390 | struct vb2_queue *q = &ceudev->vb2_vq; |
1391 | struct v4l2_subdev *v4l2_sd; |
1392 | int ret; |
1393 | |
1394 | /* Initialize vb2 queue. */ |
1395 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
1396 | q->io_modes = VB2_MMAP | VB2_DMABUF; |
1397 | q->drv_priv = ceudev; |
1398 | q->ops = &ceu_vb2_ops; |
1399 | q->mem_ops = &vb2_dma_contig_memops; |
1400 | q->buf_struct_size = sizeof(struct ceu_buffer); |
1401 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
1402 | q->min_queued_buffers = 2; |
1403 | q->lock = &ceudev->mlock; |
1404 | q->dev = ceudev->v4l2_dev.dev; |
1405 | |
1406 | ret = vb2_queue_init(q); |
1407 | if (ret) |
1408 | return ret; |
1409 | |
1410 | /* |
1411 | * Make sure at least one sensor is primary and use it to initialize |
1412 | * ceu formats. |
1413 | */ |
1414 | if (!ceudev->sd) { |
1415 | ceudev->sd = ceudev->subdevs[0]; |
1416 | ceudev->sd_index = 0; |
1417 | } |
1418 | |
1419 | v4l2_sd = ceudev->sd->v4l2_sd; |
1420 | |
1421 | ret = ceu_init_mbus_fmt(ceudev); |
1422 | if (ret) |
1423 | return ret; |
1424 | |
1425 | ret = ceu_set_default_fmt(ceudev); |
1426 | if (ret) |
1427 | return ret; |
1428 | |
1429 | /* Register the video device. */ |
1430 | strscpy(vdev->name, DRIVER_NAME, sizeof(vdev->name)); |
1431 | vdev->v4l2_dev = v4l2_dev; |
1432 | vdev->lock = &ceudev->mlock; |
1433 | vdev->queue = &ceudev->vb2_vq; |
1434 | vdev->ctrl_handler = v4l2_sd->ctrl_handler; |
1435 | vdev->fops = &ceu_fops; |
1436 | vdev->ioctl_ops = &ceu_ioctl_ops; |
1437 | vdev->release = ceu_vdev_release; |
1438 | vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | |
1439 | V4L2_CAP_STREAMING; |
1440 | video_set_drvdata(vdev, data: ceudev); |
1441 | |
1442 | ret = video_register_device(vdev, type: VFL_TYPE_VIDEO, nr: -1); |
1443 | if (ret < 0) { |
1444 | v4l2_err(vdev->v4l2_dev, |
1445 | "video_register_device failed: %d\n" , ret); |
1446 | return ret; |
1447 | } |
1448 | |
1449 | return 0; |
1450 | } |
1451 | |
1452 | static const struct v4l2_async_notifier_operations ceu_notify_ops = { |
1453 | .bound = ceu_notify_bound, |
1454 | .complete = ceu_notify_complete, |
1455 | }; |
1456 | |
1457 | /* |
1458 | * ceu_init_async_subdevs() - Initialize CEU subdevices and async_subdevs in |
1459 | * ceu device. Both DT and platform data parsing use |
1460 | * this routine. |
1461 | * |
1462 | * Returns 0 for success, -ENOMEM for failure. |
1463 | */ |
1464 | static int ceu_init_async_subdevs(struct ceu_device *ceudev, unsigned int n_sd) |
1465 | { |
1466 | /* Reserve memory for 'n_sd' ceu_subdev descriptors. */ |
1467 | ceudev->subdevs = devm_kcalloc(dev: ceudev->dev, n: n_sd, |
1468 | size: sizeof(*ceudev->subdevs), GFP_KERNEL); |
1469 | if (!ceudev->subdevs) |
1470 | return -ENOMEM; |
1471 | |
1472 | ceudev->sd = NULL; |
1473 | ceudev->sd_index = 0; |
1474 | ceudev->num_sd = 0; |
1475 | |
1476 | return 0; |
1477 | } |
1478 | |
1479 | /* |
1480 | * ceu_parse_platform_data() - Initialize async_subdevices using platform |
1481 | * device provided data. |
1482 | */ |
1483 | static int ceu_parse_platform_data(struct ceu_device *ceudev, |
1484 | const struct ceu_platform_data *pdata) |
1485 | { |
1486 | const struct ceu_async_subdev *async_sd; |
1487 | struct ceu_subdev *ceu_sd; |
1488 | unsigned int i; |
1489 | int ret; |
1490 | |
1491 | if (pdata->num_subdevs == 0) |
1492 | return -ENODEV; |
1493 | |
1494 | ret = ceu_init_async_subdevs(ceudev, n_sd: pdata->num_subdevs); |
1495 | if (ret) |
1496 | return ret; |
1497 | |
1498 | for (i = 0; i < pdata->num_subdevs; i++) { |
1499 | |
1500 | /* Setup the ceu subdevice and the async subdevice. */ |
1501 | async_sd = &pdata->subdevs[i]; |
1502 | ceu_sd = v4l2_async_nf_add_i2c(&ceudev->notifier, |
1503 | async_sd->i2c_adapter_id, |
1504 | async_sd->i2c_address, |
1505 | struct ceu_subdev); |
1506 | if (IS_ERR(ptr: ceu_sd)) { |
1507 | v4l2_async_nf_cleanup(notifier: &ceudev->notifier); |
1508 | return PTR_ERR(ptr: ceu_sd); |
1509 | } |
1510 | ceu_sd->mbus_flags = async_sd->flags; |
1511 | ceudev->subdevs[i] = ceu_sd; |
1512 | } |
1513 | |
1514 | return pdata->num_subdevs; |
1515 | } |
1516 | |
1517 | /* |
1518 | * ceu_parse_dt() - Initialize async_subdevs parsing device tree graph. |
1519 | */ |
1520 | static int ceu_parse_dt(struct ceu_device *ceudev) |
1521 | { |
1522 | struct device_node *of = ceudev->dev->of_node; |
1523 | struct device_node *ep; |
1524 | struct ceu_subdev *ceu_sd; |
1525 | unsigned int i; |
1526 | int num_ep; |
1527 | int ret; |
1528 | |
1529 | num_ep = of_graph_get_endpoint_count(np: of); |
1530 | if (!num_ep) |
1531 | return -ENODEV; |
1532 | |
1533 | ret = ceu_init_async_subdevs(ceudev, n_sd: num_ep); |
1534 | if (ret) |
1535 | return ret; |
1536 | |
1537 | for (i = 0; i < num_ep; i++) { |
1538 | struct v4l2_fwnode_endpoint fw_ep = { |
1539 | .bus_type = V4L2_MBUS_PARALLEL, |
1540 | .bus = { |
1541 | .parallel = { |
1542 | .flags = V4L2_MBUS_HSYNC_ACTIVE_HIGH | |
1543 | V4L2_MBUS_VSYNC_ACTIVE_HIGH, |
1544 | .bus_width = 8, |
1545 | }, |
1546 | }, |
1547 | }; |
1548 | |
1549 | ep = of_graph_get_endpoint_by_regs(parent: of, port_reg: 0, reg: i); |
1550 | if (!ep) { |
1551 | dev_err(ceudev->dev, |
1552 | "No subdevice connected on endpoint %u.\n" , i); |
1553 | ret = -ENODEV; |
1554 | goto error_cleanup; |
1555 | } |
1556 | |
1557 | ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), vep: &fw_ep); |
1558 | if (ret) { |
1559 | dev_err(ceudev->dev, |
1560 | "Unable to parse endpoint #%u: %d.\n" , i, ret); |
1561 | goto error_cleanup; |
1562 | } |
1563 | |
1564 | /* Setup the ceu subdevice and the async subdevice. */ |
1565 | ceu_sd = v4l2_async_nf_add_fwnode_remote(&ceudev->notifier, |
1566 | of_fwnode_handle(ep), |
1567 | struct ceu_subdev); |
1568 | if (IS_ERR(ptr: ceu_sd)) { |
1569 | ret = PTR_ERR(ptr: ceu_sd); |
1570 | goto error_cleanup; |
1571 | } |
1572 | ceu_sd->mbus_flags = fw_ep.bus.parallel.flags; |
1573 | ceudev->subdevs[i] = ceu_sd; |
1574 | |
1575 | of_node_put(node: ep); |
1576 | } |
1577 | |
1578 | return num_ep; |
1579 | |
1580 | error_cleanup: |
1581 | v4l2_async_nf_cleanup(notifier: &ceudev->notifier); |
1582 | of_node_put(node: ep); |
1583 | return ret; |
1584 | } |
1585 | |
1586 | /* |
1587 | * struct ceu_data - Platform specific CEU data |
1588 | * @irq_mask: CETCR mask with all interrupt sources enabled. The mask differs |
1589 | * between SH4 and RZ platforms. |
1590 | */ |
1591 | struct ceu_data { |
1592 | u32 irq_mask; |
1593 | }; |
1594 | |
1595 | static const struct ceu_data ceu_data_sh4 = { |
1596 | .irq_mask = CEU_CETCR_ALL_IRQS_SH4, |
1597 | }; |
1598 | |
1599 | #if IS_ENABLED(CONFIG_OF) |
1600 | static const struct ceu_data ceu_data_rz = { |
1601 | .irq_mask = CEU_CETCR_ALL_IRQS_RZ, |
1602 | }; |
1603 | |
1604 | static const struct of_device_id ceu_of_match[] = { |
1605 | { .compatible = "renesas,r7s72100-ceu" , .data = &ceu_data_rz }, |
1606 | { .compatible = "renesas,r8a7740-ceu" , .data = &ceu_data_rz }, |
1607 | { } |
1608 | }; |
1609 | MODULE_DEVICE_TABLE(of, ceu_of_match); |
1610 | #endif |
1611 | |
1612 | static int ceu_probe(struct platform_device *pdev) |
1613 | { |
1614 | struct device *dev = &pdev->dev; |
1615 | const struct ceu_data *ceu_data; |
1616 | struct ceu_device *ceudev; |
1617 | unsigned int irq; |
1618 | int num_subdevs; |
1619 | int ret; |
1620 | |
1621 | ceudev = kzalloc(size: sizeof(*ceudev), GFP_KERNEL); |
1622 | if (!ceudev) |
1623 | return -ENOMEM; |
1624 | |
1625 | platform_set_drvdata(pdev, data: ceudev); |
1626 | ceudev->dev = dev; |
1627 | |
1628 | INIT_LIST_HEAD(list: &ceudev->capture); |
1629 | spin_lock_init(&ceudev->lock); |
1630 | mutex_init(&ceudev->mlock); |
1631 | |
1632 | ceudev->base = devm_platform_ioremap_resource(pdev, index: 0); |
1633 | if (IS_ERR(ptr: ceudev->base)) { |
1634 | ret = PTR_ERR(ptr: ceudev->base); |
1635 | goto error_free_ceudev; |
1636 | } |
1637 | |
1638 | ret = platform_get_irq(pdev, 0); |
1639 | if (ret < 0) |
1640 | goto error_free_ceudev; |
1641 | irq = ret; |
1642 | |
1643 | ret = devm_request_irq(dev, irq, handler: ceu_irq, |
1644 | irqflags: 0, devname: dev_name(dev), dev_id: ceudev); |
1645 | if (ret) { |
1646 | dev_err(&pdev->dev, "Unable to request CEU interrupt.\n" ); |
1647 | goto error_free_ceudev; |
1648 | } |
1649 | |
1650 | pm_runtime_enable(dev); |
1651 | |
1652 | ret = v4l2_device_register(dev, v4l2_dev: &ceudev->v4l2_dev); |
1653 | if (ret) |
1654 | goto error_pm_disable; |
1655 | |
1656 | v4l2_async_nf_init(notifier: &ceudev->notifier, v4l2_dev: &ceudev->v4l2_dev); |
1657 | |
1658 | if (IS_ENABLED(CONFIG_OF) && dev->of_node) { |
1659 | ceu_data = of_device_get_match_data(dev); |
1660 | num_subdevs = ceu_parse_dt(ceudev); |
1661 | } else if (dev->platform_data) { |
1662 | /* Assume SH4 if booting with platform data. */ |
1663 | ceu_data = &ceu_data_sh4; |
1664 | num_subdevs = ceu_parse_platform_data(ceudev, |
1665 | pdata: dev->platform_data); |
1666 | } else { |
1667 | num_subdevs = -EINVAL; |
1668 | } |
1669 | |
1670 | if (num_subdevs < 0) { |
1671 | ret = num_subdevs; |
1672 | goto error_v4l2_unregister; |
1673 | } |
1674 | ceudev->irq_mask = ceu_data->irq_mask; |
1675 | |
1676 | ceudev->notifier.v4l2_dev = &ceudev->v4l2_dev; |
1677 | ceudev->notifier.ops = &ceu_notify_ops; |
1678 | ret = v4l2_async_nf_register(notifier: &ceudev->notifier); |
1679 | if (ret) |
1680 | goto error_cleanup; |
1681 | |
1682 | dev_info(dev, "Renesas Capture Engine Unit %s\n" , dev_name(dev)); |
1683 | |
1684 | return 0; |
1685 | |
1686 | error_cleanup: |
1687 | v4l2_async_nf_cleanup(notifier: &ceudev->notifier); |
1688 | error_v4l2_unregister: |
1689 | v4l2_device_unregister(v4l2_dev: &ceudev->v4l2_dev); |
1690 | error_pm_disable: |
1691 | pm_runtime_disable(dev); |
1692 | error_free_ceudev: |
1693 | kfree(objp: ceudev); |
1694 | |
1695 | return ret; |
1696 | } |
1697 | |
1698 | static void ceu_remove(struct platform_device *pdev) |
1699 | { |
1700 | struct ceu_device *ceudev = platform_get_drvdata(pdev); |
1701 | |
1702 | pm_runtime_disable(dev: ceudev->dev); |
1703 | |
1704 | v4l2_async_nf_unregister(notifier: &ceudev->notifier); |
1705 | |
1706 | v4l2_async_nf_cleanup(notifier: &ceudev->notifier); |
1707 | |
1708 | v4l2_device_unregister(v4l2_dev: &ceudev->v4l2_dev); |
1709 | |
1710 | video_unregister_device(vdev: &ceudev->vdev); |
1711 | } |
1712 | |
1713 | static const struct dev_pm_ops ceu_pm_ops = { |
1714 | SET_RUNTIME_PM_OPS(ceu_runtime_suspend, |
1715 | ceu_runtime_resume, |
1716 | NULL) |
1717 | }; |
1718 | |
1719 | static struct platform_driver ceu_driver = { |
1720 | .driver = { |
1721 | .name = DRIVER_NAME, |
1722 | .pm = &ceu_pm_ops, |
1723 | .of_match_table = of_match_ptr(ceu_of_match), |
1724 | }, |
1725 | .probe = ceu_probe, |
1726 | .remove_new = ceu_remove, |
1727 | }; |
1728 | |
1729 | module_platform_driver(ceu_driver); |
1730 | |
1731 | MODULE_DESCRIPTION("Renesas CEU camera driver" ); |
1732 | MODULE_AUTHOR("Jacopo Mondi <jacopo+renesas@jmondi.org>" ); |
1733 | MODULE_LICENSE("GPL v2" ); |
1734 | |