1
2
3
4
5
6
7
8
9#include <linux/clk.h>
10#include <linux/delay.h>
11#include <linux/gcd.h>
12#include <linux/interrupt.h>
13#include <linux/mfd/syscon.h>
14#include <linux/module.h>
15#include <linux/of_graph.h>
16#include <linux/pinctrl/consumer.h>
17#include <linux/platform_device.h>
18#include <linux/regmap.h>
19#include <linux/types.h>
20
21#include <media/v4l2-ctrls.h>
22#include <media/v4l2-device.h>
23#include <media/v4l2-event.h>
24#include <media/v4l2-fwnode.h>
25#include <media/v4l2-mc.h>
26#include <media/v4l2-subdev.h>
27#include <media/videobuf2-dma-contig.h>
28
29#include <media/imx.h>
30#include "imx-media.h"
31
32#define IMX7_CSI_PAD_SINK 0
33#define IMX7_CSI_PAD_SRC 1
34#define IMX7_CSI_PADS_NUM 2
35
36
37#define CSICR1_RESET_VAL 0x40000800
38#define CSICR2_RESET_VAL 0x0
39#define CSICR3_RESET_VAL 0x0
40
41
42#define BIT_SWAP16_EN BIT(31)
43#define BIT_EXT_VSYNC BIT(30)
44#define BIT_EOF_INT_EN BIT(29)
45#define BIT_PRP_IF_EN BIT(28)
46#define BIT_CCIR_MODE BIT(27)
47#define BIT_COF_INT_EN BIT(26)
48#define BIT_SF_OR_INTEN BIT(25)
49#define BIT_RF_OR_INTEN BIT(24)
50#define BIT_SFF_DMA_DONE_INTEN BIT(22)
51#define BIT_STATFF_INTEN BIT(21)
52#define BIT_FB2_DMA_DONE_INTEN BIT(20)
53#define BIT_FB1_DMA_DONE_INTEN BIT(19)
54#define BIT_RXFF_INTEN BIT(18)
55#define BIT_SOF_POL BIT(17)
56#define BIT_SOF_INTEN BIT(16)
57#define BIT_MCLKDIV (0xF << 12)
58#define BIT_HSYNC_POL BIT(11)
59#define BIT_CCIR_EN BIT(10)
60#define BIT_MCLKEN BIT(9)
61#define BIT_FCC BIT(8)
62#define BIT_PACK_DIR BIT(7)
63#define BIT_CLR_STATFIFO BIT(6)
64#define BIT_CLR_RXFIFO BIT(5)
65#define BIT_GCLK_MODE BIT(4)
66#define BIT_INV_DATA BIT(3)
67#define BIT_INV_PCLK BIT(2)
68#define BIT_REDGE BIT(1)
69#define BIT_PIXEL_BIT BIT(0)
70
71#define SHIFT_MCLKDIV 12
72
73
74#define BIT_FRMCNT (0xFFFF << 16)
75#define BIT_FRMCNT_RST BIT(15)
76#define BIT_DMA_REFLASH_RFF BIT(14)
77#define BIT_DMA_REFLASH_SFF BIT(13)
78#define BIT_DMA_REQ_EN_RFF BIT(12)
79#define BIT_DMA_REQ_EN_SFF BIT(11)
80#define BIT_STATFF_LEVEL (0x7 << 8)
81#define BIT_HRESP_ERR_EN BIT(7)
82#define BIT_RXFF_LEVEL (0x7 << 4)
83#define BIT_TWO_8BIT_SENSOR BIT(3)
84#define BIT_ZERO_PACK_EN BIT(2)
85#define BIT_ECC_INT_EN BIT(1)
86#define BIT_ECC_AUTO_EN BIT(0)
87
88#define SHIFT_FRMCNT 16
89#define SHIFT_RXFIFO_LEVEL 4
90
91
92#define BIT_ADDR_CH_ERR_INT BIT(28)
93#define BIT_FIELD0_INT BIT(27)
94#define BIT_FIELD1_INT BIT(26)
95#define BIT_SFF_OR_INT BIT(25)
96#define BIT_RFF_OR_INT BIT(24)
97#define BIT_DMA_TSF_DONE_SFF BIT(22)
98#define BIT_STATFF_INT BIT(21)
99#define BIT_DMA_TSF_DONE_FB2 BIT(20)
100#define BIT_DMA_TSF_DONE_FB1 BIT(19)
101#define BIT_RXFF_INT BIT(18)
102#define BIT_EOF_INT BIT(17)
103#define BIT_SOF_INT BIT(16)
104#define BIT_F2_INT BIT(15)
105#define BIT_F1_INT BIT(14)
106#define BIT_COF_INT BIT(13)
107#define BIT_HRESP_ERR_INT BIT(7)
108#define BIT_ECC_INT BIT(1)
109#define BIT_DRDY BIT(0)
110
111
112#define BIT_CSI_HW_ENABLE BIT(31)
113#define BIT_MIPI_DATA_FORMAT_RAW8 (0x2a << 25)
114#define BIT_MIPI_DATA_FORMAT_RAW10 (0x2b << 25)
115#define BIT_MIPI_DATA_FORMAT_RAW12 (0x2c << 25)
116#define BIT_MIPI_DATA_FORMAT_RAW14 (0x2d << 25)
117#define BIT_MIPI_DATA_FORMAT_YUV422_8B (0x1e << 25)
118#define BIT_MIPI_DATA_FORMAT_MASK (0x3F << 25)
119#define BIT_MIPI_DATA_FORMAT_OFFSET 25
120#define BIT_DATA_FROM_MIPI BIT(22)
121#define BIT_MIPI_YU_SWAP BIT(21)
122#define BIT_MIPI_DOUBLE_CMPNT BIT(20)
123#define BIT_BASEADDR_CHG_ERR_EN BIT(9)
124#define BIT_BASEADDR_SWITCH_SEL BIT(5)
125#define BIT_BASEADDR_SWITCH_EN BIT(4)
126#define BIT_PARALLEL24_EN BIT(3)
127#define BIT_DEINTERLACE_EN BIT(2)
128#define BIT_TVDECODER_IN_EN BIT(1)
129#define BIT_NTSC_EN BIT(0)
130
131#define CSI_MCLK_VF 1
132#define CSI_MCLK_ENC 2
133#define CSI_MCLK_RAW 4
134#define CSI_MCLK_I2C 8
135
136#define CSI_CSICR1 0x0
137#define CSI_CSICR2 0x4
138#define CSI_CSICR3 0x8
139#define CSI_STATFIFO 0xC
140#define CSI_CSIRXFIFO 0x10
141#define CSI_CSIRXCNT 0x14
142#define CSI_CSISR 0x18
143
144#define CSI_CSIDBG 0x1C
145#define CSI_CSIDMASA_STATFIFO 0x20
146#define CSI_CSIDMATS_STATFIFO 0x24
147#define CSI_CSIDMASA_FB1 0x28
148#define CSI_CSIDMASA_FB2 0x2C
149#define CSI_CSIFBUF_PARA 0x30
150#define CSI_CSIIMAG_PARA 0x34
151
152#define CSI_CSICR18 0x48
153#define CSI_CSICR19 0x4c
154
155struct imx7_csi {
156 struct device *dev;
157 struct v4l2_subdev sd;
158 struct v4l2_async_notifier notifier;
159 struct imx_media_video_dev *vdev;
160 struct imx_media_dev *imxmd;
161 struct media_pad pad[IMX7_CSI_PADS_NUM];
162
163
164 struct mutex lock;
165
166 spinlock_t irqlock;
167
168 struct v4l2_subdev *src_sd;
169
170 struct media_entity *sink;
171
172 struct v4l2_mbus_framefmt format_mbus[IMX7_CSI_PADS_NUM];
173 const struct imx_media_pixfmt *cc[IMX7_CSI_PADS_NUM];
174 struct v4l2_fract frame_interval[IMX7_CSI_PADS_NUM];
175
176 struct v4l2_ctrl_handler ctrl_hdlr;
177
178 void __iomem *regbase;
179 int irq;
180 struct clk *mclk;
181
182
183 struct imx_media_buffer *active_vb2_buf[2];
184 struct imx_media_dma_buf underrun_buf;
185
186 int buf_num;
187 u32 frame_sequence;
188
189 bool last_eof;
190 bool is_init;
191 bool is_streaming;
192 bool is_csi2;
193
194 struct completion last_eof_completion;
195};
196
197static struct imx7_csi *
198imx7_csi_notifier_to_dev(struct v4l2_async_notifier *n)
199{
200 return container_of(n, struct imx7_csi, notifier);
201}
202
203static u32 imx7_csi_reg_read(struct imx7_csi *csi, unsigned int offset)
204{
205 return readl(csi->regbase + offset);
206}
207
208static void imx7_csi_reg_write(struct imx7_csi *csi, unsigned int value,
209 unsigned int offset)
210{
211 writel(value, csi->regbase + offset);
212}
213
214static void imx7_csi_hw_reset(struct imx7_csi *csi)
215{
216 imx7_csi_reg_write(csi,
217 imx7_csi_reg_read(csi, CSI_CSICR3) | BIT_FRMCNT_RST,
218 CSI_CSICR3);
219
220 imx7_csi_reg_write(csi, CSICR1_RESET_VAL, CSI_CSICR1);
221 imx7_csi_reg_write(csi, CSICR2_RESET_VAL, CSI_CSICR2);
222 imx7_csi_reg_write(csi, CSICR3_RESET_VAL, CSI_CSICR3);
223}
224
225static u32 imx7_csi_irq_clear(struct imx7_csi *csi)
226{
227 u32 isr;
228
229 isr = imx7_csi_reg_read(csi, CSI_CSISR);
230 imx7_csi_reg_write(csi, isr, CSI_CSISR);
231
232 return isr;
233}
234
235static void imx7_csi_init_interface(struct imx7_csi *csi)
236{
237 unsigned int val = 0;
238 unsigned int imag_para;
239
240 val = BIT_SOF_POL | BIT_REDGE | BIT_GCLK_MODE | BIT_HSYNC_POL |
241 BIT_FCC | 1 << SHIFT_MCLKDIV | BIT_MCLKEN;
242 imx7_csi_reg_write(csi, val, CSI_CSICR1);
243
244 imag_para = (800 << 16) | 600;
245 imx7_csi_reg_write(csi, imag_para, CSI_CSIIMAG_PARA);
246
247 val = BIT_DMA_REFLASH_RFF;
248 imx7_csi_reg_write(csi, val, CSI_CSICR3);
249}
250
251static void imx7_csi_hw_enable_irq(struct imx7_csi *csi)
252{
253 u32 cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
254
255 cr1 |= BIT_SOF_INTEN;
256 cr1 |= BIT_RFF_OR_INT;
257
258
259 cr1 |= BIT_FB1_DMA_DONE_INTEN;
260 cr1 |= BIT_FB2_DMA_DONE_INTEN;
261
262 cr1 |= BIT_EOF_INT_EN;
263
264 imx7_csi_reg_write(csi, cr1, CSI_CSICR1);
265}
266
267static void imx7_csi_hw_disable_irq(struct imx7_csi *csi)
268{
269 u32 cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
270
271 cr1 &= ~BIT_SOF_INTEN;
272 cr1 &= ~BIT_RFF_OR_INT;
273 cr1 &= ~BIT_FB1_DMA_DONE_INTEN;
274 cr1 &= ~BIT_FB2_DMA_DONE_INTEN;
275 cr1 &= ~BIT_EOF_INT_EN;
276
277 imx7_csi_reg_write(csi, cr1, CSI_CSICR1);
278}
279
280static void imx7_csi_hw_enable(struct imx7_csi *csi)
281{
282 u32 cr = imx7_csi_reg_read(csi, CSI_CSICR18);
283
284 cr |= BIT_CSI_HW_ENABLE;
285
286 imx7_csi_reg_write(csi, cr, CSI_CSICR18);
287}
288
289static void imx7_csi_hw_disable(struct imx7_csi *csi)
290{
291 u32 cr = imx7_csi_reg_read(csi, CSI_CSICR18);
292
293 cr &= ~BIT_CSI_HW_ENABLE;
294
295 imx7_csi_reg_write(csi, cr, CSI_CSICR18);
296}
297
298static void imx7_csi_dma_reflash(struct imx7_csi *csi)
299{
300 u32 cr3;
301
302 cr3 = imx7_csi_reg_read(csi, CSI_CSICR3);
303 cr3 |= BIT_DMA_REFLASH_RFF;
304 imx7_csi_reg_write(csi, cr3, CSI_CSICR3);
305}
306
307static void imx7_csi_rx_fifo_clear(struct imx7_csi *csi)
308{
309 u32 cr1;
310
311 cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
312 imx7_csi_reg_write(csi, cr1 & ~BIT_FCC, CSI_CSICR1);
313 cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
314 imx7_csi_reg_write(csi, cr1 | BIT_CLR_RXFIFO, CSI_CSICR1);
315
316 cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
317 imx7_csi_reg_write(csi, cr1 | BIT_FCC, CSI_CSICR1);
318}
319
320static void imx7_csi_buf_stride_set(struct imx7_csi *csi, u32 stride)
321{
322 imx7_csi_reg_write(csi, stride, CSI_CSIFBUF_PARA);
323}
324
325static void imx7_csi_deinterlace_enable(struct imx7_csi *csi, bool enable)
326{
327 u32 cr18 = imx7_csi_reg_read(csi, CSI_CSICR18);
328
329 if (enable)
330 cr18 |= BIT_DEINTERLACE_EN;
331 else
332 cr18 &= ~BIT_DEINTERLACE_EN;
333
334 imx7_csi_reg_write(csi, cr18, CSI_CSICR18);
335}
336
337static void imx7_csi_dmareq_rff_enable(struct imx7_csi *csi)
338{
339 u32 cr3 = imx7_csi_reg_read(csi, CSI_CSICR3);
340 u32 cr2 = imx7_csi_reg_read(csi, CSI_CSICR2);
341
342
343 cr2 |= 0xC0000000;
344
345 cr3 |= BIT_DMA_REQ_EN_RFF;
346 cr3 |= BIT_HRESP_ERR_EN;
347 cr3 &= ~BIT_RXFF_LEVEL;
348 cr3 |= 0x2 << 4;
349
350 imx7_csi_reg_write(csi, cr3, CSI_CSICR3);
351 imx7_csi_reg_write(csi, cr2, CSI_CSICR2);
352}
353
354static void imx7_csi_dmareq_rff_disable(struct imx7_csi *csi)
355{
356 u32 cr3 = imx7_csi_reg_read(csi, CSI_CSICR3);
357
358 cr3 &= ~BIT_DMA_REQ_EN_RFF;
359 cr3 &= ~BIT_HRESP_ERR_EN;
360 imx7_csi_reg_write(csi, cr3, CSI_CSICR3);
361}
362
363static void imx7_csi_set_imagpara(struct imx7_csi *csi, int width, int height)
364{
365 int imag_para;
366 int rx_count;
367
368 rx_count = (width * height) >> 2;
369 imx7_csi_reg_write(csi, rx_count, CSI_CSIRXCNT);
370
371 imag_para = (width << 16) | height;
372 imx7_csi_reg_write(csi, imag_para, CSI_CSIIMAG_PARA);
373
374
375 imx7_csi_dma_reflash(csi);
376}
377
378static void imx7_csi_sw_reset(struct imx7_csi *csi)
379{
380 imx7_csi_hw_disable(csi);
381
382 imx7_csi_rx_fifo_clear(csi);
383
384 imx7_csi_dma_reflash(csi);
385
386 usleep_range(2000, 3000);
387
388 imx7_csi_irq_clear(csi);
389
390 imx7_csi_hw_enable(csi);
391}
392
393static void imx7_csi_error_recovery(struct imx7_csi *csi)
394{
395 imx7_csi_hw_disable(csi);
396
397 imx7_csi_rx_fifo_clear(csi);
398
399 imx7_csi_dma_reflash(csi);
400
401 imx7_csi_hw_enable(csi);
402}
403
404static int imx7_csi_init(struct imx7_csi *csi)
405{
406 int ret;
407
408 if (csi->is_init)
409 return 0;
410
411 ret = clk_prepare_enable(csi->mclk);
412 if (ret < 0)
413 return ret;
414 imx7_csi_hw_reset(csi);
415 imx7_csi_init_interface(csi);
416 imx7_csi_dmareq_rff_enable(csi);
417
418 csi->is_init = true;
419
420 return 0;
421}
422
423static void imx7_csi_deinit(struct imx7_csi *csi)
424{
425 if (!csi->is_init)
426 return;
427
428 imx7_csi_hw_reset(csi);
429 imx7_csi_init_interface(csi);
430 imx7_csi_dmareq_rff_disable(csi);
431 clk_disable_unprepare(csi->mclk);
432
433 csi->is_init = false;
434}
435
436static int imx7_csi_link_setup(struct media_entity *entity,
437 const struct media_pad *local,
438 const struct media_pad *remote, u32 flags)
439{
440 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
441 struct imx7_csi *csi = v4l2_get_subdevdata(sd);
442 struct v4l2_subdev *remote_sd;
443 int ret = 0;
444
445 dev_dbg(csi->dev, "link setup %s -> %s\n", remote->entity->name,
446 local->entity->name);
447
448 mutex_lock(&csi->lock);
449
450 if (local->flags & MEDIA_PAD_FL_SINK) {
451 if (!is_media_entity_v4l2_subdev(remote->entity)) {
452 ret = -EINVAL;
453 goto unlock;
454 }
455
456 remote_sd = media_entity_to_v4l2_subdev(remote->entity);
457
458 if (flags & MEDIA_LNK_FL_ENABLED) {
459 if (csi->src_sd) {
460 ret = -EBUSY;
461 goto unlock;
462 }
463 csi->src_sd = remote_sd;
464 } else {
465 csi->src_sd = NULL;
466 }
467
468 goto init;
469 }
470
471
472 if (flags & MEDIA_LNK_FL_ENABLED) {
473 if (csi->sink) {
474 ret = -EBUSY;
475 goto unlock;
476 }
477 csi->sink = remote->entity;
478 } else {
479 v4l2_ctrl_handler_free(&csi->ctrl_hdlr);
480 v4l2_ctrl_handler_init(&csi->ctrl_hdlr, 0);
481 csi->sink = NULL;
482 }
483
484init:
485 if (csi->sink || csi->src_sd)
486 ret = imx7_csi_init(csi);
487 else
488 imx7_csi_deinit(csi);
489
490unlock:
491 mutex_unlock(&csi->lock);
492
493 return ret;
494}
495
496static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd,
497 struct media_link *link,
498 struct v4l2_subdev_format *source_fmt,
499 struct v4l2_subdev_format *sink_fmt)
500{
501 struct imx7_csi *csi = v4l2_get_subdevdata(sd);
502 struct media_pad *pad;
503 int ret;
504
505 ret = v4l2_subdev_link_validate_default(sd, link, source_fmt, sink_fmt);
506 if (ret)
507 return ret;
508
509 if (!csi->src_sd)
510 return -EPIPE;
511
512
513
514
515
516 pad = imx_media_pipeline_pad(&csi->src_sd->entity, 0, 0, true);
517 if (!pad)
518 return -ENODEV;
519
520 mutex_lock(&csi->lock);
521
522 csi->is_csi2 = (pad->entity->function == MEDIA_ENT_F_VID_IF_BRIDGE);
523
524 mutex_unlock(&csi->lock);
525
526 return 0;
527}
528
529static void imx7_csi_update_buf(struct imx7_csi *csi, dma_addr_t phys,
530 int buf_num)
531{
532 if (buf_num == 1)
533 imx7_csi_reg_write(csi, phys, CSI_CSIDMASA_FB2);
534 else
535 imx7_csi_reg_write(csi, phys, CSI_CSIDMASA_FB1);
536}
537
538static void imx7_csi_setup_vb2_buf(struct imx7_csi *csi)
539{
540 struct imx_media_video_dev *vdev = csi->vdev;
541 struct imx_media_buffer *buf;
542 struct vb2_buffer *vb2_buf;
543 dma_addr_t phys[2];
544 int i;
545
546 for (i = 0; i < 2; i++) {
547 buf = imx_media_capture_device_next_buf(vdev);
548 if (buf) {
549 csi->active_vb2_buf[i] = buf;
550 vb2_buf = &buf->vbuf.vb2_buf;
551 phys[i] = vb2_dma_contig_plane_dma_addr(vb2_buf, 0);
552 } else {
553 csi->active_vb2_buf[i] = NULL;
554 phys[i] = csi->underrun_buf.phys;
555 }
556
557 imx7_csi_update_buf(csi, phys[i], i);
558 }
559}
560
561static void imx7_csi_dma_unsetup_vb2_buf(struct imx7_csi *csi,
562 enum vb2_buffer_state return_status)
563{
564 struct imx_media_buffer *buf;
565 int i;
566
567
568 for (i = 0; i < 2; i++) {
569 buf = csi->active_vb2_buf[i];
570 if (buf) {
571 struct vb2_buffer *vb = &buf->vbuf.vb2_buf;
572
573 vb->timestamp = ktime_get_ns();
574 vb2_buffer_done(vb, return_status);
575 }
576 }
577}
578
579static void imx7_csi_vb2_buf_done(struct imx7_csi *csi)
580{
581 struct imx_media_video_dev *vdev = csi->vdev;
582 struct imx_media_buffer *done, *next;
583 struct vb2_buffer *vb;
584 dma_addr_t phys;
585
586 done = csi->active_vb2_buf[csi->buf_num];
587 if (done) {
588 done->vbuf.field = vdev->fmt.fmt.pix.field;
589 done->vbuf.sequence = csi->frame_sequence;
590 vb = &done->vbuf.vb2_buf;
591 vb->timestamp = ktime_get_ns();
592 vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
593 }
594 csi->frame_sequence++;
595
596
597 next = imx_media_capture_device_next_buf(vdev);
598 if (next) {
599 phys = vb2_dma_contig_plane_dma_addr(&next->vbuf.vb2_buf, 0);
600 csi->active_vb2_buf[csi->buf_num] = next;
601 } else {
602 phys = csi->underrun_buf.phys;
603 csi->active_vb2_buf[csi->buf_num] = NULL;
604 }
605
606 imx7_csi_update_buf(csi, phys, csi->buf_num);
607}
608
609static irqreturn_t imx7_csi_irq_handler(int irq, void *data)
610{
611 struct imx7_csi *csi = data;
612 u32 status;
613
614 spin_lock(&csi->irqlock);
615
616 status = imx7_csi_irq_clear(csi);
617
618 if (status & BIT_RFF_OR_INT) {
619 dev_warn(csi->dev, "Rx fifo overflow\n");
620 imx7_csi_error_recovery(csi);
621 }
622
623 if (status & BIT_HRESP_ERR_INT) {
624 dev_warn(csi->dev, "Hresponse error detected\n");
625 imx7_csi_error_recovery(csi);
626 }
627
628 if (status & BIT_ADDR_CH_ERR_INT) {
629 imx7_csi_hw_disable(csi);
630
631 imx7_csi_dma_reflash(csi);
632
633 imx7_csi_hw_enable(csi);
634 }
635
636 if ((status & BIT_DMA_TSF_DONE_FB1) &&
637 (status & BIT_DMA_TSF_DONE_FB2)) {
638
639
640
641
642
643
644
645
646 } else if (status & BIT_DMA_TSF_DONE_FB1) {
647 csi->buf_num = 0;
648 } else if (status & BIT_DMA_TSF_DONE_FB2) {
649 csi->buf_num = 1;
650 }
651
652 if ((status & BIT_DMA_TSF_DONE_FB1) ||
653 (status & BIT_DMA_TSF_DONE_FB2)) {
654 imx7_csi_vb2_buf_done(csi);
655
656 if (csi->last_eof) {
657 complete(&csi->last_eof_completion);
658 csi->last_eof = false;
659 }
660 }
661
662 spin_unlock(&csi->irqlock);
663
664 return IRQ_HANDLED;
665}
666
667static int imx7_csi_dma_start(struct imx7_csi *csi)
668{
669 struct imx_media_video_dev *vdev = csi->vdev;
670 struct v4l2_pix_format *out_pix = &vdev->fmt.fmt.pix;
671 int ret;
672
673 ret = imx_media_alloc_dma_buf(csi->dev, &csi->underrun_buf,
674 out_pix->sizeimage);
675 if (ret < 0) {
676 v4l2_warn(&csi->sd, "consider increasing the CMA area\n");
677 return ret;
678 }
679
680 csi->frame_sequence = 0;
681 csi->last_eof = false;
682 init_completion(&csi->last_eof_completion);
683
684 imx7_csi_setup_vb2_buf(csi);
685
686 return 0;
687}
688
689static void imx7_csi_dma_stop(struct imx7_csi *csi)
690{
691 unsigned long timeout_jiffies;
692 unsigned long flags;
693 int ret;
694
695
696 spin_lock_irqsave(&csi->irqlock, flags);
697 csi->last_eof = true;
698 spin_unlock_irqrestore(&csi->irqlock, flags);
699
700
701
702
703 timeout_jiffies = msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT);
704 ret = wait_for_completion_timeout(&csi->last_eof_completion,
705 timeout_jiffies);
706 if (ret == 0)
707 v4l2_warn(&csi->sd, "wait last EOF timeout\n");
708
709 imx7_csi_hw_disable_irq(csi);
710
711 imx7_csi_dma_unsetup_vb2_buf(csi, VB2_BUF_STATE_ERROR);
712
713 imx_media_free_dma_buf(csi->dev, &csi->underrun_buf);
714}
715
716static int imx7_csi_configure(struct imx7_csi *csi)
717{
718 struct imx_media_video_dev *vdev = csi->vdev;
719 struct v4l2_pix_format *out_pix = &vdev->fmt.fmt.pix;
720 __u32 in_code = csi->format_mbus[IMX7_CSI_PAD_SINK].code;
721 u32 cr1, cr18;
722 int width = out_pix->width;
723
724 if (out_pix->field == V4L2_FIELD_INTERLACED) {
725 imx7_csi_deinterlace_enable(csi, true);
726 imx7_csi_buf_stride_set(csi, out_pix->width);
727 } else {
728 imx7_csi_deinterlace_enable(csi, false);
729 imx7_csi_buf_stride_set(csi, 0);
730 }
731
732 cr18 = imx7_csi_reg_read(csi, CSI_CSICR18);
733
734 if (!csi->is_csi2) {
735 if (out_pix->pixelformat == V4L2_PIX_FMT_UYVY ||
736 out_pix->pixelformat == V4L2_PIX_FMT_YUYV)
737 width *= 2;
738
739 imx7_csi_set_imagpara(csi, width, out_pix->height);
740
741 cr18 |= (BIT_BASEADDR_SWITCH_EN | BIT_BASEADDR_SWITCH_SEL |
742 BIT_BASEADDR_CHG_ERR_EN);
743 imx7_csi_reg_write(csi, cr18, CSI_CSICR18);
744
745 return 0;
746 }
747
748 imx7_csi_set_imagpara(csi, width, out_pix->height);
749
750 cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
751 cr1 &= ~BIT_GCLK_MODE;
752
753 cr18 &= BIT_MIPI_DATA_FORMAT_MASK;
754 cr18 |= BIT_DATA_FROM_MIPI;
755
756 switch (out_pix->pixelformat) {
757 case V4L2_PIX_FMT_UYVY:
758 case V4L2_PIX_FMT_YUYV:
759 cr18 |= BIT_MIPI_DATA_FORMAT_YUV422_8B;
760 break;
761 case V4L2_PIX_FMT_GREY:
762 if (in_code == MEDIA_BUS_FMT_Y8_1X8)
763 cr18 |= BIT_MIPI_DATA_FORMAT_RAW8;
764 else if (in_code == MEDIA_BUS_FMT_Y10_1X10)
765 cr18 |= BIT_MIPI_DATA_FORMAT_RAW10;
766 else
767 cr18 |= BIT_MIPI_DATA_FORMAT_RAW12;
768 break;
769 case V4L2_PIX_FMT_Y10:
770 cr18 |= BIT_MIPI_DATA_FORMAT_RAW10;
771 cr1 |= BIT_PIXEL_BIT;
772 break;
773 case V4L2_PIX_FMT_Y12:
774 cr18 |= BIT_MIPI_DATA_FORMAT_RAW12;
775 cr1 |= BIT_PIXEL_BIT;
776 break;
777 case V4L2_PIX_FMT_SBGGR8:
778 cr18 |= BIT_MIPI_DATA_FORMAT_RAW8;
779 break;
780 case V4L2_PIX_FMT_SBGGR16:
781 if (in_code == MEDIA_BUS_FMT_SBGGR10_1X10)
782 cr18 |= BIT_MIPI_DATA_FORMAT_RAW10;
783 else if (in_code == MEDIA_BUS_FMT_SBGGR12_1X12)
784 cr18 |= BIT_MIPI_DATA_FORMAT_RAW12;
785 else if (in_code == MEDIA_BUS_FMT_SBGGR14_1X14)
786 cr18 |= BIT_MIPI_DATA_FORMAT_RAW14;
787 cr1 |= BIT_PIXEL_BIT;
788 break;
789 default:
790 return -EINVAL;
791 }
792
793 imx7_csi_reg_write(csi, cr1, CSI_CSICR1);
794 imx7_csi_reg_write(csi, cr18, CSI_CSICR18);
795
796 return 0;
797}
798
799static void imx7_csi_enable(struct imx7_csi *csi)
800{
801 imx7_csi_sw_reset(csi);
802
803 imx7_csi_dmareq_rff_enable(csi);
804 imx7_csi_hw_enable_irq(csi);
805 imx7_csi_hw_enable(csi);
806}
807
808static void imx7_csi_disable(struct imx7_csi *csi)
809{
810 imx7_csi_dmareq_rff_disable(csi);
811
812 imx7_csi_hw_disable_irq(csi);
813
814 imx7_csi_buf_stride_set(csi, 0);
815
816 imx7_csi_hw_disable(csi);
817}
818
819static int imx7_csi_streaming_start(struct imx7_csi *csi)
820{
821 int ret;
822
823 ret = imx7_csi_dma_start(csi);
824 if (ret < 0)
825 return ret;
826
827 ret = imx7_csi_configure(csi);
828 if (ret < 0)
829 goto dma_stop;
830
831 imx7_csi_enable(csi);
832
833 return 0;
834
835dma_stop:
836 imx7_csi_dma_stop(csi);
837
838 return ret;
839}
840
841static int imx7_csi_streaming_stop(struct imx7_csi *csi)
842{
843 imx7_csi_dma_stop(csi);
844
845 imx7_csi_disable(csi);
846
847 return 0;
848}
849
850static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable)
851{
852 struct imx7_csi *csi = v4l2_get_subdevdata(sd);
853 int ret = 0;
854
855 mutex_lock(&csi->lock);
856
857 if (!csi->src_sd || !csi->sink) {
858 ret = -EPIPE;
859 goto out_unlock;
860 }
861
862 if (csi->is_streaming == !!enable)
863 goto out_unlock;
864
865 if (enable) {
866 ret = v4l2_subdev_call(csi->src_sd, video, s_stream, 1);
867 if (ret < 0)
868 goto out_unlock;
869
870 ret = imx7_csi_streaming_start(csi);
871 if (ret < 0) {
872 v4l2_subdev_call(csi->src_sd, video, s_stream, 0);
873 goto out_unlock;
874 }
875 } else {
876 imx7_csi_streaming_stop(csi);
877
878 v4l2_subdev_call(csi->src_sd, video, s_stream, 0);
879 }
880
881 csi->is_streaming = !!enable;
882
883out_unlock:
884 mutex_unlock(&csi->lock);
885
886 return ret;
887}
888
889static struct v4l2_mbus_framefmt *
890imx7_csi_get_format(struct imx7_csi *csi,
891 struct v4l2_subdev_pad_config *cfg,
892 unsigned int pad,
893 enum v4l2_subdev_format_whence which)
894{
895 if (which == V4L2_SUBDEV_FORMAT_TRY)
896 return v4l2_subdev_get_try_format(&csi->sd, cfg, pad);
897
898 return &csi->format_mbus[pad];
899}
900
901static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd,
902 struct v4l2_subdev_pad_config *cfg,
903 struct v4l2_subdev_mbus_code_enum *code)
904{
905 struct imx7_csi *csi = v4l2_get_subdevdata(sd);
906 struct v4l2_mbus_framefmt *in_fmt;
907 int ret = 0;
908
909 mutex_lock(&csi->lock);
910
911 in_fmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SINK, code->which);
912
913 switch (code->pad) {
914 case IMX7_CSI_PAD_SINK:
915 ret = imx_media_enum_mbus_formats(&code->code, code->index,
916 PIXFMT_SEL_ANY);
917 break;
918 case IMX7_CSI_PAD_SRC:
919 if (code->index != 0) {
920 ret = -EINVAL;
921 goto out_unlock;
922 }
923
924 code->code = in_fmt->code;
925 break;
926 default:
927 ret = -EINVAL;
928 }
929
930out_unlock:
931 mutex_unlock(&csi->lock);
932
933 return ret;
934}
935
936static int imx7_csi_get_fmt(struct v4l2_subdev *sd,
937 struct v4l2_subdev_pad_config *cfg,
938 struct v4l2_subdev_format *sdformat)
939{
940 struct imx7_csi *csi = v4l2_get_subdevdata(sd);
941 struct v4l2_mbus_framefmt *fmt;
942 int ret = 0;
943
944 mutex_lock(&csi->lock);
945
946 fmt = imx7_csi_get_format(csi, cfg, sdformat->pad, sdformat->which);
947 if (!fmt) {
948 ret = -EINVAL;
949 goto out_unlock;
950 }
951
952 sdformat->format = *fmt;
953
954out_unlock:
955 mutex_unlock(&csi->lock);
956
957 return ret;
958}
959
960static int imx7_csi_try_fmt(struct imx7_csi *csi,
961 struct v4l2_subdev_pad_config *cfg,
962 struct v4l2_subdev_format *sdformat,
963 const struct imx_media_pixfmt **cc)
964{
965 const struct imx_media_pixfmt *in_cc;
966 struct v4l2_mbus_framefmt *in_fmt;
967 u32 code;
968
969 in_fmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SINK,
970 sdformat->which);
971 if (!in_fmt)
972 return -EINVAL;
973
974 switch (sdformat->pad) {
975 case IMX7_CSI_PAD_SRC:
976 in_cc = imx_media_find_mbus_format(in_fmt->code,
977 PIXFMT_SEL_ANY);
978
979 sdformat->format.width = in_fmt->width;
980 sdformat->format.height = in_fmt->height;
981 sdformat->format.code = in_fmt->code;
982 sdformat->format.field = in_fmt->field;
983 *cc = in_cc;
984
985 sdformat->format.colorspace = in_fmt->colorspace;
986 sdformat->format.xfer_func = in_fmt->xfer_func;
987 sdformat->format.quantization = in_fmt->quantization;
988 sdformat->format.ycbcr_enc = in_fmt->ycbcr_enc;
989 break;
990 case IMX7_CSI_PAD_SINK:
991 *cc = imx_media_find_mbus_format(sdformat->format.code,
992 PIXFMT_SEL_ANY);
993 if (!*cc) {
994 imx_media_enum_mbus_formats(&code, 0,
995 PIXFMT_SEL_YUV_RGB);
996 *cc = imx_media_find_mbus_format(code,
997 PIXFMT_SEL_YUV_RGB);
998 sdformat->format.code = (*cc)->codes[0];
999 }
1000
1001 if (sdformat->format.field != V4L2_FIELD_INTERLACED)
1002 sdformat->format.field = V4L2_FIELD_NONE;
1003 break;
1004 default:
1005 return -EINVAL;
1006 }
1007
1008 imx_media_try_colorimetry(&sdformat->format, false);
1009
1010 return 0;
1011}
1012
1013static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
1014 struct v4l2_subdev_pad_config *cfg,
1015 struct v4l2_subdev_format *sdformat)
1016{
1017 struct imx7_csi *csi = v4l2_get_subdevdata(sd);
1018 const struct imx_media_pixfmt *outcc;
1019 struct v4l2_mbus_framefmt *outfmt;
1020 const struct imx_media_pixfmt *cc;
1021 struct v4l2_mbus_framefmt *fmt;
1022 struct v4l2_subdev_format format;
1023 int ret = 0;
1024
1025 if (sdformat->pad >= IMX7_CSI_PADS_NUM)
1026 return -EINVAL;
1027
1028 mutex_lock(&csi->lock);
1029
1030 if (csi->is_streaming) {
1031 ret = -EBUSY;
1032 goto out_unlock;
1033 }
1034
1035 ret = imx7_csi_try_fmt(csi, cfg, sdformat, &cc);
1036 if (ret < 0)
1037 goto out_unlock;
1038
1039 fmt = imx7_csi_get_format(csi, cfg, sdformat->pad, sdformat->which);
1040 if (!fmt) {
1041 ret = -EINVAL;
1042 goto out_unlock;
1043 }
1044
1045 *fmt = sdformat->format;
1046
1047 if (sdformat->pad == IMX7_CSI_PAD_SINK) {
1048
1049 format.pad = IMX7_CSI_PAD_SRC;
1050 format.which = sdformat->which;
1051 format.format = sdformat->format;
1052 if (imx7_csi_try_fmt(csi, cfg, &format, &outcc)) {
1053 ret = -EINVAL;
1054 goto out_unlock;
1055 }
1056 outfmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SRC,
1057 sdformat->which);
1058 *outfmt = format.format;
1059
1060 if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
1061 csi->cc[IMX7_CSI_PAD_SRC] = outcc;
1062 }
1063
1064 if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
1065 csi->cc[sdformat->pad] = cc;
1066
1067out_unlock:
1068 mutex_unlock(&csi->lock);
1069
1070 return ret;
1071}
1072
1073static int imx7_csi_registered(struct v4l2_subdev *sd)
1074{
1075 struct imx7_csi *csi = v4l2_get_subdevdata(sd);
1076 int ret;
1077 int i;
1078
1079 for (i = 0; i < IMX7_CSI_PADS_NUM; i++) {
1080
1081 ret = imx_media_init_mbus_fmt(&csi->format_mbus[i],
1082 800, 600, 0, V4L2_FIELD_NONE,
1083 &csi->cc[i]);
1084 if (ret < 0)
1085 return ret;
1086
1087
1088 csi->frame_interval[i].numerator = 1;
1089 csi->frame_interval[i].denominator = 30;
1090 }
1091
1092 csi->vdev = imx_media_capture_device_init(csi->sd.dev, &csi->sd,
1093 IMX7_CSI_PAD_SRC);
1094 if (IS_ERR(csi->vdev))
1095 return PTR_ERR(csi->vdev);
1096
1097 ret = imx_media_capture_device_register(csi->vdev);
1098 if (ret)
1099 imx_media_capture_device_remove(csi->vdev);
1100
1101 return ret;
1102}
1103
1104static void imx7_csi_unregistered(struct v4l2_subdev *sd)
1105{
1106 struct imx7_csi *csi = v4l2_get_subdevdata(sd);
1107
1108 imx_media_capture_device_unregister(csi->vdev);
1109 imx_media_capture_device_remove(csi->vdev);
1110}
1111
1112static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
1113 struct v4l2_subdev_pad_config *cfg)
1114{
1115 struct imx7_csi *csi = v4l2_get_subdevdata(sd);
1116 struct v4l2_mbus_framefmt *mf;
1117 int ret;
1118 int i;
1119
1120 for (i = 0; i < IMX7_CSI_PADS_NUM; i++) {
1121 mf = v4l2_subdev_get_try_format(sd, cfg, i);
1122
1123 ret = imx_media_init_mbus_fmt(mf, 800, 600, 0, V4L2_FIELD_NONE,
1124 &csi->cc[i]);
1125 if (ret < 0)
1126 return ret;
1127 }
1128
1129 return 0;
1130}
1131
1132static const struct media_entity_operations imx7_csi_entity_ops = {
1133 .link_setup = imx7_csi_link_setup,
1134 .link_validate = v4l2_subdev_link_validate,
1135 .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
1136};
1137
1138static const struct v4l2_subdev_video_ops imx7_csi_video_ops = {
1139 .s_stream = imx7_csi_s_stream,
1140};
1141
1142static const struct v4l2_subdev_pad_ops imx7_csi_pad_ops = {
1143 .init_cfg = imx7_csi_init_cfg,
1144 .enum_mbus_code = imx7_csi_enum_mbus_code,
1145 .get_fmt = imx7_csi_get_fmt,
1146 .set_fmt = imx7_csi_set_fmt,
1147 .link_validate = imx7_csi_pad_link_validate,
1148};
1149
1150static const struct v4l2_subdev_ops imx7_csi_subdev_ops = {
1151 .video = &imx7_csi_video_ops,
1152 .pad = &imx7_csi_pad_ops,
1153};
1154
1155static const struct v4l2_subdev_internal_ops imx7_csi_internal_ops = {
1156 .registered = imx7_csi_registered,
1157 .unregistered = imx7_csi_unregistered,
1158};
1159
1160static int imx7_csi_notify_bound(struct v4l2_async_notifier *notifier,
1161 struct v4l2_subdev *sd,
1162 struct v4l2_async_subdev *asd)
1163{
1164 struct imx7_csi *csi = imx7_csi_notifier_to_dev(notifier);
1165 struct media_pad *sink = &csi->sd.entity.pads[IMX7_CSI_PAD_SINK];
1166
1167
1168 if (WARN_ON(sd->entity.function != MEDIA_ENT_F_VID_MUX))
1169 return -ENXIO;
1170
1171
1172 sd->grp_id = IMX_MEDIA_GRP_ID_CSI_MUX;
1173
1174 return v4l2_create_fwnode_links_to_pad(sd, sink);
1175}
1176
1177static const struct v4l2_async_notifier_operations imx7_csi_notify_ops = {
1178 .bound = imx7_csi_notify_bound,
1179};
1180
1181static int imx7_csi_async_register(struct imx7_csi *csi)
1182{
1183 struct v4l2_async_subdev *asd = NULL;
1184 struct fwnode_handle *ep;
1185 int ret;
1186
1187 v4l2_async_notifier_init(&csi->notifier);
1188
1189 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi->dev), 0, 0,
1190 FWNODE_GRAPH_ENDPOINT_NEXT);
1191 if (ep) {
1192 asd = kzalloc(sizeof(*asd), GFP_KERNEL);
1193 if (!asd) {
1194 fwnode_handle_put(ep);
1195 return -ENOMEM;
1196 }
1197
1198 ret = v4l2_async_notifier_add_fwnode_remote_subdev(
1199 &csi->notifier, ep, asd);
1200
1201 fwnode_handle_put(ep);
1202
1203 if (ret) {
1204 kfree(asd);
1205
1206 if (ret != -EEXIST)
1207 return ret;
1208 }
1209 }
1210
1211 csi->notifier.ops = &imx7_csi_notify_ops;
1212
1213 ret = v4l2_async_subdev_notifier_register(&csi->sd, &csi->notifier);
1214 if (ret)
1215 return ret;
1216
1217 return v4l2_async_register_subdev(&csi->sd);
1218}
1219
1220static int imx7_csi_probe(struct platform_device *pdev)
1221{
1222 struct device *dev = &pdev->dev;
1223 struct device_node *node = dev->of_node;
1224 struct imx_media_dev *imxmd;
1225 struct imx7_csi *csi;
1226 int i, ret;
1227
1228 csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL);
1229 if (!csi)
1230 return -ENOMEM;
1231
1232 csi->dev = dev;
1233
1234 csi->mclk = devm_clk_get(&pdev->dev, "mclk");
1235 if (IS_ERR(csi->mclk)) {
1236 ret = PTR_ERR(csi->mclk);
1237 dev_err(dev, "Failed to get mclk: %d", ret);
1238 return ret;
1239 }
1240
1241 csi->irq = platform_get_irq(pdev, 0);
1242 if (csi->irq < 0)
1243 return csi->irq;
1244
1245 csi->regbase = devm_platform_ioremap_resource(pdev, 0);
1246 if (IS_ERR(csi->regbase))
1247 return PTR_ERR(csi->regbase);
1248
1249 spin_lock_init(&csi->irqlock);
1250 mutex_init(&csi->lock);
1251
1252
1253 ret = devm_request_irq(dev, csi->irq, imx7_csi_irq_handler, 0, "csi",
1254 (void *)csi);
1255 if (ret < 0) {
1256 dev_err(dev, "Request CSI IRQ failed.\n");
1257 goto destroy_mutex;
1258 }
1259
1260
1261 imxmd = imx_media_dev_init(dev, NULL);
1262 if (IS_ERR(imxmd)) {
1263 ret = PTR_ERR(imxmd);
1264 goto destroy_mutex;
1265 }
1266 platform_set_drvdata(pdev, &csi->sd);
1267
1268 ret = imx_media_of_add_csi(imxmd, node);
1269 if (ret < 0 && ret != -ENODEV && ret != -EEXIST)
1270 goto cleanup;
1271
1272 ret = imx_media_dev_notifier_register(imxmd, NULL);
1273 if (ret < 0)
1274 goto cleanup;
1275
1276 csi->imxmd = imxmd;
1277 v4l2_subdev_init(&csi->sd, &imx7_csi_subdev_ops);
1278 v4l2_set_subdevdata(&csi->sd, csi);
1279 csi->sd.internal_ops = &imx7_csi_internal_ops;
1280 csi->sd.entity.ops = &imx7_csi_entity_ops;
1281 csi->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
1282 csi->sd.dev = &pdev->dev;
1283 csi->sd.owner = THIS_MODULE;
1284 csi->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
1285 csi->sd.grp_id = IMX_MEDIA_GRP_ID_CSI;
1286 snprintf(csi->sd.name, sizeof(csi->sd.name), "csi");
1287
1288 v4l2_ctrl_handler_init(&csi->ctrl_hdlr, 0);
1289 csi->sd.ctrl_handler = &csi->ctrl_hdlr;
1290
1291 for (i = 0; i < IMX7_CSI_PADS_NUM; i++)
1292 csi->pad[i].flags = (i == IMX7_CSI_PAD_SINK) ?
1293 MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
1294
1295 ret = media_entity_pads_init(&csi->sd.entity, IMX7_CSI_PADS_NUM,
1296 csi->pad);
1297 if (ret < 0)
1298 goto free;
1299
1300 ret = imx7_csi_async_register(csi);
1301 if (ret)
1302 goto subdev_notifier_cleanup;
1303
1304 return 0;
1305
1306subdev_notifier_cleanup:
1307 v4l2_async_notifier_unregister(&csi->notifier);
1308 v4l2_async_notifier_cleanup(&csi->notifier);
1309
1310free:
1311 v4l2_ctrl_handler_free(&csi->ctrl_hdlr);
1312
1313cleanup:
1314 v4l2_async_notifier_unregister(&imxmd->notifier);
1315 v4l2_async_notifier_cleanup(&imxmd->notifier);
1316 v4l2_device_unregister(&imxmd->v4l2_dev);
1317 media_device_unregister(&imxmd->md);
1318 media_device_cleanup(&imxmd->md);
1319
1320destroy_mutex:
1321 mutex_destroy(&csi->lock);
1322
1323 return ret;
1324}
1325
1326static int imx7_csi_remove(struct platform_device *pdev)
1327{
1328 struct v4l2_subdev *sd = platform_get_drvdata(pdev);
1329 struct imx7_csi *csi = v4l2_get_subdevdata(sd);
1330 struct imx_media_dev *imxmd = csi->imxmd;
1331
1332 v4l2_async_notifier_unregister(&imxmd->notifier);
1333 v4l2_async_notifier_cleanup(&imxmd->notifier);
1334
1335 media_device_unregister(&imxmd->md);
1336 v4l2_device_unregister(&imxmd->v4l2_dev);
1337 media_device_cleanup(&imxmd->md);
1338
1339 v4l2_async_notifier_unregister(&csi->notifier);
1340 v4l2_async_notifier_cleanup(&csi->notifier);
1341 v4l2_async_unregister_subdev(sd);
1342 v4l2_ctrl_handler_free(&csi->ctrl_hdlr);
1343
1344 mutex_destroy(&csi->lock);
1345
1346 return 0;
1347}
1348
1349static const struct of_device_id imx7_csi_of_match[] = {
1350 { .compatible = "fsl,imx7-csi" },
1351 { .compatible = "fsl,imx6ul-csi" },
1352 { },
1353};
1354MODULE_DEVICE_TABLE(of, imx7_csi_of_match);
1355
1356static struct platform_driver imx7_csi_driver = {
1357 .probe = imx7_csi_probe,
1358 .remove = imx7_csi_remove,
1359 .driver = {
1360 .of_match_table = imx7_csi_of_match,
1361 .name = "imx7-csi",
1362 },
1363};
1364module_platform_driver(imx7_csi_driver);
1365
1366MODULE_DESCRIPTION("i.MX7 CSI subdev driver");
1367MODULE_AUTHOR("Rui Miguel Silva <rui.silva@linaro.org>");
1368MODULE_LICENSE("GPL v2");
1369MODULE_ALIAS("platform:imx7-csi");
1370