diff options
author | Anatolij Gustschin <agust@denx.de> | 2010-07-02 09:10:09 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-08-02 14:34:44 -0400 |
commit | 95c5d605ca6fd6ab5ab0f6d097ff97d5aa2f9235 (patch) | |
tree | eac70a00f5e9b98eac2fb31980dea619dcafaf21 /drivers/media/video/fsl-viu.c | |
parent | 2bb00fe6336687f08e0a3733bce2343a821af843 (diff) |
V4L/DVB: v4l: Add MPC5121e VIU video capture driver
Adds support for Video-In (VIU) unit of Freescale
MPC5121e. The driver supports RGB888/RGB565 formats,
capture and overlay on MPC5121e DIU frame buffer.
Signed-off-by: Hongjun Chen <hong-jun.chen@freescale.com>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/fsl-viu.c')
-rw-r--r-- | drivers/media/video/fsl-viu.c | 1632 |
1 files changed, 1632 insertions, 0 deletions
diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c new file mode 100644 index 000000000000..8f1c94f7e00c --- /dev/null +++ b/drivers/media/video/fsl-viu.c | |||
@@ -0,0 +1,1632 @@ | |||
1 | /* | ||
2 | * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. | ||
3 | * | ||
4 | * Freescale VIU video driver | ||
5 | * | ||
6 | * Authors: Hongjun Chen <hong-jun.chen@freescale.com> | ||
7 | * Porting to 2.6.35 by DENX Software Engineering, | ||
8 | * Anatolij Gustschin <agust@denx.de> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/clk.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/of_platform.h> | ||
25 | #include <linux/version.h> | ||
26 | #include <media/v4l2-common.h> | ||
27 | #include <media/v4l2-device.h> | ||
28 | #include <media/v4l2-ioctl.h> | ||
29 | #include <media/videobuf-dma-contig.h> | ||
30 | |||
31 | #define DRV_NAME "fsl_viu" | ||
32 | #define VIU_MAJOR_VERSION 0 | ||
33 | #define VIU_MINOR_VERSION 5 | ||
34 | #define VIU_RELEASE 0 | ||
35 | #define VIU_VERSION KERNEL_VERSION(VIU_MAJOR_VERSION, \ | ||
36 | VIU_MINOR_VERSION, \ | ||
37 | VIU_RELEASE) | ||
38 | |||
39 | #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ | ||
40 | |||
41 | #define VIU_VID_MEM_LIMIT 4 /* Video memory limit, in Mb */ | ||
42 | |||
43 | /* I2C address of video decoder chip is 0x4A */ | ||
44 | #define VIU_VIDEO_DECODER_ADDR 0x25 | ||
45 | |||
46 | /* supported controls */ | ||
47 | static struct v4l2_queryctrl viu_qctrl[] = { | ||
48 | { | ||
49 | .id = V4L2_CID_BRIGHTNESS, | ||
50 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
51 | .name = "Brightness", | ||
52 | .minimum = 0, | ||
53 | .maximum = 255, | ||
54 | .step = 1, | ||
55 | .default_value = 127, | ||
56 | .flags = 0, | ||
57 | }, { | ||
58 | .id = V4L2_CID_CONTRAST, | ||
59 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
60 | .name = "Contrast", | ||
61 | .minimum = 0, | ||
62 | .maximum = 255, | ||
63 | .step = 0x1, | ||
64 | .default_value = 0x10, | ||
65 | .flags = 0, | ||
66 | }, { | ||
67 | .id = V4L2_CID_SATURATION, | ||
68 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
69 | .name = "Saturation", | ||
70 | .minimum = 0, | ||
71 | .maximum = 255, | ||
72 | .step = 0x1, | ||
73 | .default_value = 127, | ||
74 | .flags = 0, | ||
75 | }, { | ||
76 | .id = V4L2_CID_HUE, | ||
77 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
78 | .name = "Hue", | ||
79 | .minimum = -128, | ||
80 | .maximum = 127, | ||
81 | .step = 0x1, | ||
82 | .default_value = 0, | ||
83 | .flags = 0, | ||
84 | } | ||
85 | }; | ||
86 | |||
87 | static int qctl_regs[ARRAY_SIZE(viu_qctrl)]; | ||
88 | |||
89 | static int info_level; | ||
90 | |||
91 | #define dprintk(level, fmt, arg...) \ | ||
92 | do { \ | ||
93 | if (level <= info_level) \ | ||
94 | printk(KERN_DEBUG "viu: " fmt , ## arg); \ | ||
95 | } while (0) | ||
96 | |||
97 | /* | ||
98 | * Basic structures | ||
99 | */ | ||
100 | struct viu_fmt { | ||
101 | char name[32]; | ||
102 | u32 fourcc; /* v4l2 format id */ | ||
103 | u32 pixelformat; | ||
104 | int depth; | ||
105 | }; | ||
106 | |||
107 | static struct viu_fmt formats[] = { | ||
108 | { | ||
109 | .name = "RGB-16 (5/B-6/G-5/R)", | ||
110 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
111 | .pixelformat = V4L2_PIX_FMT_RGB565, | ||
112 | .depth = 16, | ||
113 | }, { | ||
114 | .name = "RGB-32 (A-R-G-B)", | ||
115 | .fourcc = V4L2_PIX_FMT_RGB32, | ||
116 | .pixelformat = V4L2_PIX_FMT_RGB32, | ||
117 | .depth = 32, | ||
118 | } | ||
119 | }; | ||
120 | |||
121 | struct viu_dev; | ||
122 | struct viu_buf; | ||
123 | |||
124 | /* buffer for one video frame */ | ||
125 | struct viu_buf { | ||
126 | /* common v4l buffer stuff -- must be first */ | ||
127 | struct videobuf_buffer vb; | ||
128 | struct viu_fmt *fmt; | ||
129 | }; | ||
130 | |||
131 | struct viu_dmaqueue { | ||
132 | struct viu_dev *dev; | ||
133 | struct list_head active; | ||
134 | struct list_head queued; | ||
135 | struct timer_list timeout; | ||
136 | }; | ||
137 | |||
138 | struct viu_status { | ||
139 | u32 field_irq; | ||
140 | u32 vsync_irq; | ||
141 | u32 hsync_irq; | ||
142 | u32 vstart_irq; | ||
143 | u32 dma_end_irq; | ||
144 | u32 error_irq; | ||
145 | }; | ||
146 | |||
147 | struct viu_reg { | ||
148 | u32 status_cfg; | ||
149 | u32 luminance; | ||
150 | u32 chroma_r; | ||
151 | u32 chroma_g; | ||
152 | u32 chroma_b; | ||
153 | u32 field_base_addr; | ||
154 | u32 dma_inc; | ||
155 | u32 picture_count; | ||
156 | u32 req_alarm; | ||
157 | u32 alpha; | ||
158 | } __attribute__ ((packed)); | ||
159 | |||
160 | struct viu_dev { | ||
161 | struct v4l2_device v4l2_dev; | ||
162 | struct mutex lock; | ||
163 | spinlock_t slock; | ||
164 | int users; | ||
165 | |||
166 | struct device *dev; | ||
167 | /* various device info */ | ||
168 | struct video_device *vdev; | ||
169 | struct viu_dmaqueue vidq; | ||
170 | enum v4l2_field capfield; | ||
171 | int field; | ||
172 | int first; | ||
173 | int dma_done; | ||
174 | |||
175 | /* Hardware register area */ | ||
176 | struct viu_reg *vr; | ||
177 | |||
178 | /* Interrupt vector */ | ||
179 | int irq; | ||
180 | struct viu_status irqs; | ||
181 | |||
182 | /* video overlay */ | ||
183 | struct v4l2_framebuffer ovbuf; | ||
184 | struct viu_fmt *ovfmt; | ||
185 | unsigned int ovenable; | ||
186 | enum v4l2_field ovfield; | ||
187 | |||
188 | /* crop */ | ||
189 | struct v4l2_rect crop_current; | ||
190 | |||
191 | /* clock pointer */ | ||
192 | struct clk *clk; | ||
193 | |||
194 | /* decoder */ | ||
195 | struct v4l2_subdev *decoder; | ||
196 | }; | ||
197 | |||
198 | struct viu_fh { | ||
199 | struct viu_dev *dev; | ||
200 | |||
201 | /* video capture */ | ||
202 | struct videobuf_queue vb_vidq; | ||
203 | spinlock_t vbq_lock; /* spinlock for the videobuf queue */ | ||
204 | |||
205 | /* video overlay */ | ||
206 | struct v4l2_window win; | ||
207 | struct v4l2_clip clips[1]; | ||
208 | |||
209 | /* video capture */ | ||
210 | struct viu_fmt *fmt; | ||
211 | int width, height, sizeimage; | ||
212 | enum v4l2_buf_type type; | ||
213 | }; | ||
214 | |||
215 | static struct viu_reg reg_val; | ||
216 | |||
217 | /* | ||
218 | * Macro definitions of VIU registers | ||
219 | */ | ||
220 | |||
221 | /* STATUS_CONFIG register */ | ||
222 | enum status_config { | ||
223 | SOFT_RST = 1 << 0, | ||
224 | |||
225 | ERR_MASK = 0x0f << 4, /* Error code mask */ | ||
226 | ERR_NO = 0x00, /* No error */ | ||
227 | ERR_DMA_V = 0x01 << 4, /* DMA in vertical active */ | ||
228 | ERR_DMA_VB = 0x02 << 4, /* DMA in vertical blanking */ | ||
229 | ERR_LINE_TOO_LONG = 0x04 << 4, /* Line too long */ | ||
230 | ERR_TOO_MANG_LINES = 0x05 << 4, /* Too many lines in field */ | ||
231 | ERR_LINE_TOO_SHORT = 0x06 << 4, /* Line too short */ | ||
232 | ERR_NOT_ENOUGH_LINE = 0x07 << 4, /* Not enough lines in field */ | ||
233 | ERR_FIFO_OVERFLOW = 0x08 << 4, /* FIFO overflow */ | ||
234 | ERR_FIFO_UNDERFLOW = 0x09 << 4, /* FIFO underflow */ | ||
235 | ERR_1bit_ECC = 0x0a << 4, /* One bit ECC error */ | ||
236 | ERR_MORE_ECC = 0x0b << 4, /* Two/more bits ECC error */ | ||
237 | |||
238 | INT_FIELD_EN = 0x01 << 8, /* Enable field interrupt */ | ||
239 | INT_VSYNC_EN = 0x01 << 9, /* Enable vsync interrupt */ | ||
240 | INT_HSYNC_EN = 0x01 << 10, /* Enable hsync interrupt */ | ||
241 | INT_VSTART_EN = 0x01 << 11, /* Enable vstart interrupt */ | ||
242 | INT_DMA_END_EN = 0x01 << 12, /* Enable DMA end interrupt */ | ||
243 | INT_ERROR_EN = 0x01 << 13, /* Enable error interrupt */ | ||
244 | INT_ECC_EN = 0x01 << 14, /* Enable ECC interrupt */ | ||
245 | |||
246 | INT_FIELD_STATUS = 0x01 << 16, /* field interrupt status */ | ||
247 | INT_VSYNC_STATUS = 0x01 << 17, /* vsync interrupt status */ | ||
248 | INT_HSYNC_STATUS = 0x01 << 18, /* hsync interrupt status */ | ||
249 | INT_VSTART_STATUS = 0x01 << 19, /* vstart interrupt status */ | ||
250 | INT_DMA_END_STATUS = 0x01 << 20, /* DMA end interrupt status */ | ||
251 | INT_ERROR_STATUS = 0x01 << 21, /* error interrupt status */ | ||
252 | |||
253 | DMA_ACT = 0x01 << 27, /* Enable DMA transfer */ | ||
254 | FIELD_NO = 0x01 << 28, /* Field number */ | ||
255 | DITHER_ON = 0x01 << 29, /* Dithering is on */ | ||
256 | ROUND_ON = 0x01 << 30, /* Round is on */ | ||
257 | MODE_32BIT = 0x01 << 31, /* Data in RGBa888, | ||
258 | * 0 in RGB565 | ||
259 | */ | ||
260 | }; | ||
261 | |||
262 | #define norm_maxw() 720 | ||
263 | #define norm_maxh() 576 | ||
264 | |||
265 | #define INT_ALL_STATUS (INT_FIELD_STATUS | INT_VSYNC_STATUS | \ | ||
266 | INT_HSYNC_STATUS | INT_VSTART_STATUS | \ | ||
267 | INT_DMA_END_STATUS | INT_ERROR_STATUS) | ||
268 | |||
269 | #define NUM_FORMATS ARRAY_SIZE(formats) | ||
270 | |||
271 | static irqreturn_t viu_intr(int irq, void *dev_id); | ||
272 | |||
273 | struct viu_fmt *format_by_fourcc(int fourcc) | ||
274 | { | ||
275 | int i; | ||
276 | |||
277 | for (i = 0; i < NUM_FORMATS; i++) { | ||
278 | if (formats[i].pixelformat == fourcc) | ||
279 | return formats + i; | ||
280 | } | ||
281 | |||
282 | dprintk(0, "unknown pixelformat:'%4.4s'\n", (char *)&fourcc); | ||
283 | return NULL; | ||
284 | } | ||
285 | |||
286 | void viu_start_dma(struct viu_dev *dev) | ||
287 | { | ||
288 | struct viu_reg *vr = dev->vr; | ||
289 | |||
290 | dev->field = 0; | ||
291 | |||
292 | /* Enable DMA operation */ | ||
293 | out_be32(&vr->status_cfg, SOFT_RST); | ||
294 | out_be32(&vr->status_cfg, INT_FIELD_EN); | ||
295 | } | ||
296 | |||
297 | void viu_stop_dma(struct viu_dev *dev) | ||
298 | { | ||
299 | struct viu_reg *vr = dev->vr; | ||
300 | int cnt = 100; | ||
301 | u32 status_cfg; | ||
302 | |||
303 | out_be32(&vr->status_cfg, 0); | ||
304 | |||
305 | /* Clear pending interrupts */ | ||
306 | status_cfg = in_be32(&vr->status_cfg); | ||
307 | if (status_cfg & 0x3f0000) | ||
308 | out_be32(&vr->status_cfg, status_cfg & 0x3f0000); | ||
309 | |||
310 | if (status_cfg & DMA_ACT) { | ||
311 | do { | ||
312 | status_cfg = in_be32(&vr->status_cfg); | ||
313 | if (status_cfg & INT_DMA_END_STATUS) | ||
314 | break; | ||
315 | } while (cnt--); | ||
316 | |||
317 | if (cnt < 0) { | ||
318 | /* timed out, issue soft reset */ | ||
319 | out_be32(&vr->status_cfg, SOFT_RST); | ||
320 | out_be32(&vr->status_cfg, 0); | ||
321 | } else { | ||
322 | /* clear DMA_END and other pending irqs */ | ||
323 | out_be32(&vr->status_cfg, status_cfg & 0x3f0000); | ||
324 | } | ||
325 | } | ||
326 | |||
327 | dev->field = 0; | ||
328 | } | ||
329 | |||
330 | static int restart_video_queue(struct viu_dmaqueue *vidq) | ||
331 | { | ||
332 | struct viu_buf *buf, *prev; | ||
333 | |||
334 | dprintk(1, "%s vidq=0x%08lx\n", __func__, (unsigned long)vidq); | ||
335 | if (!list_empty(&vidq->active)) { | ||
336 | buf = list_entry(vidq->active.next, struct viu_buf, vb.queue); | ||
337 | dprintk(2, "restart_queue [%p/%d]: restart dma\n", | ||
338 | buf, buf->vb.i); | ||
339 | |||
340 | viu_stop_dma(vidq->dev); | ||
341 | |||
342 | /* cancel all outstanding capture requests */ | ||
343 | list_for_each_entry_safe(buf, prev, &vidq->active, vb.queue) { | ||
344 | list_del(&buf->vb.queue); | ||
345 | buf->vb.state = VIDEOBUF_ERROR; | ||
346 | wake_up(&buf->vb.done); | ||
347 | } | ||
348 | mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | prev = NULL; | ||
353 | for (;;) { | ||
354 | if (list_empty(&vidq->queued)) | ||
355 | return 0; | ||
356 | buf = list_entry(vidq->queued.next, struct viu_buf, vb.queue); | ||
357 | if (prev == NULL) { | ||
358 | list_del(&buf->vb.queue); | ||
359 | list_add_tail(&buf->vb.queue, &vidq->active); | ||
360 | |||
361 | dprintk(1, "Restarting video dma\n"); | ||
362 | viu_stop_dma(vidq->dev); | ||
363 | viu_start_dma(vidq->dev); | ||
364 | |||
365 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
366 | mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); | ||
367 | dprintk(2, "[%p/%d] restart_queue - first active\n", | ||
368 | buf, buf->vb.i); | ||
369 | |||
370 | } else if (prev->vb.width == buf->vb.width && | ||
371 | prev->vb.height == buf->vb.height && | ||
372 | prev->fmt == buf->fmt) { | ||
373 | list_del(&buf->vb.queue); | ||
374 | list_add_tail(&buf->vb.queue, &vidq->active); | ||
375 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
376 | dprintk(2, "[%p/%d] restart_queue - move to active\n", | ||
377 | buf, buf->vb.i); | ||
378 | } else { | ||
379 | return 0; | ||
380 | } | ||
381 | prev = buf; | ||
382 | } | ||
383 | } | ||
384 | |||
385 | static void viu_vid_timeout(unsigned long data) | ||
386 | { | ||
387 | struct viu_dev *dev = (struct viu_dev *)data; | ||
388 | struct viu_buf *buf; | ||
389 | struct viu_dmaqueue *vidq = &dev->vidq; | ||
390 | |||
391 | while (!list_empty(&vidq->active)) { | ||
392 | buf = list_entry(vidq->active.next, struct viu_buf, vb.queue); | ||
393 | list_del(&buf->vb.queue); | ||
394 | buf->vb.state = VIDEOBUF_ERROR; | ||
395 | wake_up(&buf->vb.done); | ||
396 | dprintk(1, "viu/0: [%p/%d] timeout\n", buf, buf->vb.i); | ||
397 | } | ||
398 | |||
399 | restart_video_queue(vidq); | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * Videobuf operations | ||
404 | */ | ||
405 | static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, | ||
406 | unsigned int *size) | ||
407 | { | ||
408 | struct viu_fh *fh = vq->priv_data; | ||
409 | |||
410 | *size = fh->width * fh->height * fh->fmt->depth >> 3; | ||
411 | if (*count == 0) | ||
412 | *count = 32; | ||
413 | |||
414 | while (*size * *count > VIU_VID_MEM_LIMIT * 1024 * 1024) | ||
415 | (*count)--; | ||
416 | |||
417 | dprintk(1, "%s, count=%d, size=%d\n", __func__, *count, *size); | ||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf) | ||
422 | { | ||
423 | struct videobuf_buffer *vb = &buf->vb; | ||
424 | void *vaddr = NULL; | ||
425 | |||
426 | BUG_ON(in_interrupt()); | ||
427 | |||
428 | videobuf_waiton(&buf->vb, 0, 0); | ||
429 | |||
430 | if (vq->int_ops && vq->int_ops->vaddr) | ||
431 | vaddr = vq->int_ops->vaddr(vb); | ||
432 | |||
433 | if (vaddr) | ||
434 | videobuf_dma_contig_free(vq, &buf->vb); | ||
435 | |||
436 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | ||
437 | } | ||
438 | |||
439 | inline int buffer_activate(struct viu_dev *dev, struct viu_buf *buf) | ||
440 | { | ||
441 | struct viu_reg *vr = dev->vr; | ||
442 | int bpp; | ||
443 | |||
444 | /* setup the DMA base address */ | ||
445 | reg_val.field_base_addr = videobuf_to_dma_contig(&buf->vb); | ||
446 | |||
447 | dprintk(1, "buffer_activate [%p/%d]: dma addr 0x%lx\n", | ||
448 | buf, buf->vb.i, (unsigned long)reg_val.field_base_addr); | ||
449 | |||
450 | /* interlace is on by default, set horizontal DMA increment */ | ||
451 | reg_val.status_cfg = 0; | ||
452 | bpp = buf->fmt->depth >> 3; | ||
453 | switch (bpp) { | ||
454 | case 2: | ||
455 | reg_val.status_cfg &= ~MODE_32BIT; | ||
456 | reg_val.dma_inc = buf->vb.width * 2; | ||
457 | break; | ||
458 | case 4: | ||
459 | reg_val.status_cfg |= MODE_32BIT; | ||
460 | reg_val.dma_inc = buf->vb.width * 4; | ||
461 | break; | ||
462 | default: | ||
463 | dprintk(0, "doesn't support color depth(%d)\n", | ||
464 | bpp * 8); | ||
465 | return -EINVAL; | ||
466 | } | ||
467 | |||
468 | /* setup picture_count register */ | ||
469 | reg_val.picture_count = (buf->vb.height / 2) << 16 | | ||
470 | buf->vb.width; | ||
471 | |||
472 | reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN; | ||
473 | |||
474 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
475 | dev->capfield = buf->vb.field; | ||
476 | |||
477 | /* reset dma increment if needed */ | ||
478 | if (!V4L2_FIELD_HAS_BOTH(buf->vb.field)) | ||
479 | reg_val.dma_inc = 0; | ||
480 | |||
481 | out_be32(&vr->dma_inc, reg_val.dma_inc); | ||
482 | out_be32(&vr->picture_count, reg_val.picture_count); | ||
483 | out_be32(&vr->field_base_addr, reg_val.field_base_addr); | ||
484 | mod_timer(&dev->vidq.timeout, jiffies + BUFFER_TIMEOUT); | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static int buffer_prepare(struct videobuf_queue *vq, | ||
489 | struct videobuf_buffer *vb, | ||
490 | enum v4l2_field field) | ||
491 | { | ||
492 | struct viu_fh *fh = vq->priv_data; | ||
493 | struct viu_buf *buf = container_of(vb, struct viu_buf, vb); | ||
494 | int rc; | ||
495 | |||
496 | BUG_ON(fh->fmt == NULL); | ||
497 | |||
498 | if (fh->width < 48 || fh->width > norm_maxw() || | ||
499 | fh->height < 32 || fh->height > norm_maxh()) | ||
500 | return -EINVAL; | ||
501 | buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; | ||
502 | if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) | ||
503 | return -EINVAL; | ||
504 | |||
505 | if (buf->fmt != fh->fmt || | ||
506 | buf->vb.width != fh->width || | ||
507 | buf->vb.height != fh->height || | ||
508 | buf->vb.field != field) { | ||
509 | buf->fmt = fh->fmt; | ||
510 | buf->vb.width = fh->width; | ||
511 | buf->vb.height = fh->height; | ||
512 | buf->vb.field = field; | ||
513 | } | ||
514 | |||
515 | if (buf->vb.state == VIDEOBUF_NEEDS_INIT) { | ||
516 | rc = videobuf_iolock(vq, &buf->vb, NULL); | ||
517 | if (rc != 0) | ||
518 | goto fail; | ||
519 | |||
520 | buf->vb.width = fh->width; | ||
521 | buf->vb.height = fh->height; | ||
522 | buf->vb.field = field; | ||
523 | buf->fmt = fh->fmt; | ||
524 | } | ||
525 | |||
526 | buf->vb.state = VIDEOBUF_PREPARED; | ||
527 | return 0; | ||
528 | |||
529 | fail: | ||
530 | free_buffer(vq, buf); | ||
531 | return rc; | ||
532 | } | ||
533 | |||
534 | static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) | ||
535 | { | ||
536 | struct viu_buf *buf = container_of(vb, struct viu_buf, vb); | ||
537 | struct viu_fh *fh = vq->priv_data; | ||
538 | struct viu_dev *dev = fh->dev; | ||
539 | struct viu_dmaqueue *vidq = &dev->vidq; | ||
540 | struct viu_buf *prev; | ||
541 | |||
542 | if (!list_empty(&vidq->queued)) { | ||
543 | dprintk(1, "adding vb queue=0x%08lx\n", | ||
544 | (unsigned long)&buf->vb.queue); | ||
545 | dprintk(1, "vidq pointer 0x%p, queued 0x%p\n", | ||
546 | vidq, &vidq->queued); | ||
547 | dprintk(1, "dev %p, queued: self %p, next %p, head %p\n", | ||
548 | dev, &vidq->queued, vidq->queued.next, | ||
549 | vidq->queued.prev); | ||
550 | list_add_tail(&buf->vb.queue, &vidq->queued); | ||
551 | buf->vb.state = VIDEOBUF_QUEUED; | ||
552 | dprintk(2, "[%p/%d] buffer_queue - append to queued\n", | ||
553 | buf, buf->vb.i); | ||
554 | } else if (list_empty(&vidq->active)) { | ||
555 | dprintk(1, "adding vb active=0x%08lx\n", | ||
556 | (unsigned long)&buf->vb.queue); | ||
557 | list_add_tail(&buf->vb.queue, &vidq->active); | ||
558 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
559 | mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); | ||
560 | dprintk(2, "[%p/%d] buffer_queue - first active\n", | ||
561 | buf, buf->vb.i); | ||
562 | |||
563 | buffer_activate(dev, buf); | ||
564 | } else { | ||
565 | dprintk(1, "adding vb queue2=0x%08lx\n", | ||
566 | (unsigned long)&buf->vb.queue); | ||
567 | prev = list_entry(vidq->active.prev, struct viu_buf, vb.queue); | ||
568 | if (prev->vb.width == buf->vb.width && | ||
569 | prev->vb.height == buf->vb.height && | ||
570 | prev->fmt == buf->fmt) { | ||
571 | list_add_tail(&buf->vb.queue, &vidq->active); | ||
572 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
573 | dprintk(2, "[%p/%d] buffer_queue - append to active\n", | ||
574 | buf, buf->vb.i); | ||
575 | } else { | ||
576 | list_add_tail(&buf->vb.queue, &vidq->queued); | ||
577 | buf->vb.state = VIDEOBUF_QUEUED; | ||
578 | dprintk(2, "[%p/%d] buffer_queue - first queued\n", | ||
579 | buf, buf->vb.i); | ||
580 | } | ||
581 | } | ||
582 | } | ||
583 | |||
584 | static void buffer_release(struct videobuf_queue *vq, | ||
585 | struct videobuf_buffer *vb) | ||
586 | { | ||
587 | struct viu_buf *buf = container_of(vb, struct viu_buf, vb); | ||
588 | struct viu_fh *fh = vq->priv_data; | ||
589 | struct viu_dev *dev = (struct viu_dev *)fh->dev; | ||
590 | |||
591 | viu_stop_dma(dev); | ||
592 | free_buffer(vq, buf); | ||
593 | } | ||
594 | |||
595 | static struct videobuf_queue_ops viu_video_qops = { | ||
596 | .buf_setup = buffer_setup, | ||
597 | .buf_prepare = buffer_prepare, | ||
598 | .buf_queue = buffer_queue, | ||
599 | .buf_release = buffer_release, | ||
600 | }; | ||
601 | |||
602 | /* | ||
603 | * IOCTL vidioc handling | ||
604 | */ | ||
605 | static int vidioc_querycap(struct file *file, void *priv, | ||
606 | struct v4l2_capability *cap) | ||
607 | { | ||
608 | strcpy(cap->driver, "viu"); | ||
609 | strcpy(cap->card, "viu"); | ||
610 | cap->version = VIU_VERSION; | ||
611 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | | ||
612 | V4L2_CAP_STREAMING | | ||
613 | V4L2_CAP_VIDEO_OVERLAY | | ||
614 | V4L2_CAP_READWRITE; | ||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | static int vidioc_enum_fmt(struct file *file, void *priv, | ||
619 | struct v4l2_fmtdesc *f) | ||
620 | { | ||
621 | int index = f->index; | ||
622 | |||
623 | if (f->index > NUM_FORMATS) | ||
624 | return -EINVAL; | ||
625 | |||
626 | strlcpy(f->description, formats[index].name, sizeof(f->description)); | ||
627 | f->pixelformat = formats[index].fourcc; | ||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | static int vidioc_g_fmt_cap(struct file *file, void *priv, | ||
632 | struct v4l2_format *f) | ||
633 | { | ||
634 | struct viu_fh *fh = priv; | ||
635 | |||
636 | f->fmt.pix.width = fh->width; | ||
637 | f->fmt.pix.height = fh->height; | ||
638 | f->fmt.pix.field = fh->vb_vidq.field; | ||
639 | f->fmt.pix.pixelformat = fh->fmt->pixelformat; | ||
640 | f->fmt.pix.bytesperline = | ||
641 | (f->fmt.pix.width * fh->fmt->depth) >> 3; | ||
642 | f->fmt.pix.sizeimage = fh->sizeimage; | ||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | static int vidioc_try_fmt_cap(struct file *file, void *priv, | ||
647 | struct v4l2_format *f) | ||
648 | { | ||
649 | struct viu_fmt *fmt; | ||
650 | enum v4l2_field field; | ||
651 | unsigned int maxw, maxh; | ||
652 | |||
653 | fmt = format_by_fourcc(f->fmt.pix.pixelformat); | ||
654 | if (!fmt) { | ||
655 | dprintk(1, "Fourcc format (0x%08x) invalid.", | ||
656 | f->fmt.pix.pixelformat); | ||
657 | return -EINVAL; | ||
658 | } | ||
659 | |||
660 | field = f->fmt.pix.field; | ||
661 | |||
662 | if (field == V4L2_FIELD_ANY) { | ||
663 | field = V4L2_FIELD_INTERLACED; | ||
664 | } else if (field != V4L2_FIELD_INTERLACED) { | ||
665 | dprintk(1, "Field type invalid.\n"); | ||
666 | return -EINVAL; | ||
667 | } | ||
668 | |||
669 | maxw = norm_maxw(); | ||
670 | maxh = norm_maxh(); | ||
671 | |||
672 | f->fmt.pix.field = field; | ||
673 | if (f->fmt.pix.height < 32) | ||
674 | f->fmt.pix.height = 32; | ||
675 | if (f->fmt.pix.height > maxh) | ||
676 | f->fmt.pix.height = maxh; | ||
677 | if (f->fmt.pix.width < 48) | ||
678 | f->fmt.pix.width = 48; | ||
679 | if (f->fmt.pix.width > maxw) | ||
680 | f->fmt.pix.width = maxw; | ||
681 | f->fmt.pix.width &= ~0x03; | ||
682 | f->fmt.pix.bytesperline = | ||
683 | (f->fmt.pix.width * fmt->depth) >> 3; | ||
684 | |||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | static int vidioc_s_fmt_cap(struct file *file, void *priv, | ||
689 | struct v4l2_format *f) | ||
690 | { | ||
691 | struct viu_fh *fh = priv; | ||
692 | int ret; | ||
693 | |||
694 | ret = vidioc_try_fmt_cap(file, fh, f); | ||
695 | if (ret < 0) | ||
696 | return ret; | ||
697 | |||
698 | fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); | ||
699 | fh->width = f->fmt.pix.width; | ||
700 | fh->height = f->fmt.pix.height; | ||
701 | fh->sizeimage = f->fmt.pix.sizeimage; | ||
702 | fh->vb_vidq.field = f->fmt.pix.field; | ||
703 | fh->type = f->type; | ||
704 | dprintk(1, "set to pixelformat '%4.6s'\n", (char *)&fh->fmt->name); | ||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | static int vidioc_g_fmt_overlay(struct file *file, void *priv, | ||
709 | struct v4l2_format *f) | ||
710 | { | ||
711 | struct viu_fh *fh = priv; | ||
712 | |||
713 | f->fmt.win = fh->win; | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | static int verify_preview(struct viu_dev *dev, struct v4l2_window *win) | ||
718 | { | ||
719 | enum v4l2_field field; | ||
720 | int maxw, maxh; | ||
721 | |||
722 | if (dev->ovbuf.base == NULL) | ||
723 | return -EINVAL; | ||
724 | if (dev->ovfmt == NULL) | ||
725 | return -EINVAL; | ||
726 | if (win->w.width < 48 || win->w.height < 32) | ||
727 | return -EINVAL; | ||
728 | |||
729 | field = win->field; | ||
730 | maxw = dev->crop_current.width; | ||
731 | maxh = dev->crop_current.height; | ||
732 | |||
733 | if (field == V4L2_FIELD_ANY) { | ||
734 | field = (win->w.height > maxh/2) | ||
735 | ? V4L2_FIELD_INTERLACED | ||
736 | : V4L2_FIELD_TOP; | ||
737 | } | ||
738 | switch (field) { | ||
739 | case V4L2_FIELD_TOP: | ||
740 | case V4L2_FIELD_BOTTOM: | ||
741 | maxh = maxh / 2; | ||
742 | break; | ||
743 | case V4L2_FIELD_INTERLACED: | ||
744 | break; | ||
745 | default: | ||
746 | return -EINVAL; | ||
747 | } | ||
748 | |||
749 | win->field = field; | ||
750 | if (win->w.width > maxw) | ||
751 | win->w.width = maxw; | ||
752 | if (win->w.height > maxh) | ||
753 | win->w.height = maxh; | ||
754 | return 0; | ||
755 | } | ||
756 | |||
757 | inline void viu_activate_overlay(struct viu_reg *viu_reg) | ||
758 | { | ||
759 | struct viu_reg *vr = viu_reg; | ||
760 | |||
761 | out_be32(&vr->field_base_addr, reg_val.field_base_addr); | ||
762 | out_be32(&vr->dma_inc, reg_val.dma_inc); | ||
763 | out_be32(&vr->picture_count, reg_val.picture_count); | ||
764 | } | ||
765 | |||
766 | static int viu_start_preview(struct viu_dev *dev, struct viu_fh *fh) | ||
767 | { | ||
768 | int bpp; | ||
769 | |||
770 | dprintk(1, "%s %dx%d %s\n", __func__, | ||
771 | fh->win.w.width, fh->win.w.height, dev->ovfmt->name); | ||
772 | |||
773 | reg_val.status_cfg = 0; | ||
774 | |||
775 | /* setup window */ | ||
776 | reg_val.picture_count = (fh->win.w.height / 2) << 16 | | ||
777 | fh->win.w.width; | ||
778 | |||
779 | /* setup color depth and dma increment */ | ||
780 | bpp = dev->ovfmt->depth / 8; | ||
781 | switch (bpp) { | ||
782 | case 2: | ||
783 | reg_val.status_cfg &= ~MODE_32BIT; | ||
784 | reg_val.dma_inc = fh->win.w.width * 2; | ||
785 | break; | ||
786 | case 4: | ||
787 | reg_val.status_cfg |= MODE_32BIT; | ||
788 | reg_val.dma_inc = fh->win.w.width * 4; | ||
789 | break; | ||
790 | default: | ||
791 | dprintk(0, "device doesn't support color depth(%d)\n", | ||
792 | bpp * 8); | ||
793 | return -EINVAL; | ||
794 | } | ||
795 | |||
796 | dev->ovfield = fh->win.field; | ||
797 | if (!V4L2_FIELD_HAS_BOTH(dev->ovfield)) | ||
798 | reg_val.dma_inc = 0; | ||
799 | |||
800 | reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN; | ||
801 | |||
802 | /* setup the base address of the overlay buffer */ | ||
803 | reg_val.field_base_addr = (u32)dev->ovbuf.base; | ||
804 | |||
805 | dev->ovenable = 1; | ||
806 | viu_activate_overlay(dev->vr); | ||
807 | |||
808 | /* start dma */ | ||
809 | viu_start_dma(dev); | ||
810 | return 0; | ||
811 | } | ||
812 | |||
813 | static int vidioc_s_fmt_overlay(struct file *file, void *priv, | ||
814 | struct v4l2_format *f) | ||
815 | { | ||
816 | struct viu_fh *fh = priv; | ||
817 | struct viu_dev *dev = (struct viu_dev *)fh->dev; | ||
818 | unsigned long flags; | ||
819 | int err; | ||
820 | |||
821 | err = verify_preview(dev, &f->fmt.win); | ||
822 | if (err) | ||
823 | return err; | ||
824 | |||
825 | mutex_lock(&dev->lock); | ||
826 | fh->win = f->fmt.win; | ||
827 | |||
828 | spin_lock_irqsave(&dev->slock, flags); | ||
829 | viu_start_preview(dev, fh); | ||
830 | spin_unlock_irqrestore(&dev->slock, flags); | ||
831 | mutex_unlock(&dev->lock); | ||
832 | return 0; | ||
833 | } | ||
834 | |||
835 | static int vidioc_try_fmt_overlay(struct file *file, void *priv, | ||
836 | struct v4l2_format *f) | ||
837 | { | ||
838 | return 0; | ||
839 | } | ||
840 | |||
841 | int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg) | ||
842 | { | ||
843 | struct viu_fh *fh = priv; | ||
844 | struct viu_dev *dev = fh->dev; | ||
845 | struct v4l2_framebuffer *fb = arg; | ||
846 | |||
847 | *fb = dev->ovbuf; | ||
848 | fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; | ||
849 | return 0; | ||
850 | } | ||
851 | |||
852 | int vidioc_s_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg) | ||
853 | { | ||
854 | struct viu_fh *fh = priv; | ||
855 | struct viu_dev *dev = fh->dev; | ||
856 | struct v4l2_framebuffer *fb = arg; | ||
857 | struct viu_fmt *fmt; | ||
858 | |||
859 | if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) | ||
860 | return -EPERM; | ||
861 | |||
862 | /* check args */ | ||
863 | fmt = format_by_fourcc(fb->fmt.pixelformat); | ||
864 | if (fmt == NULL) | ||
865 | return -EINVAL; | ||
866 | |||
867 | /* ok, accept it */ | ||
868 | dev->ovbuf = *fb; | ||
869 | dev->ovfmt = fmt; | ||
870 | if (dev->ovbuf.fmt.bytesperline == 0) { | ||
871 | dev->ovbuf.fmt.bytesperline = | ||
872 | dev->ovbuf.fmt.width * fmt->depth / 8; | ||
873 | } | ||
874 | return 0; | ||
875 | } | ||
876 | |||
877 | static int vidioc_reqbufs(struct file *file, void *priv, | ||
878 | struct v4l2_requestbuffers *p) | ||
879 | { | ||
880 | struct viu_fh *fh = priv; | ||
881 | |||
882 | return videobuf_reqbufs(&fh->vb_vidq, p); | ||
883 | } | ||
884 | |||
885 | static int vidioc_querybuf(struct file *file, void *priv, | ||
886 | struct v4l2_buffer *p) | ||
887 | { | ||
888 | struct viu_fh *fh = priv; | ||
889 | |||
890 | return videobuf_querybuf(&fh->vb_vidq, p); | ||
891 | } | ||
892 | |||
893 | static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) | ||
894 | { | ||
895 | struct viu_fh *fh = priv; | ||
896 | |||
897 | return videobuf_qbuf(&fh->vb_vidq, p); | ||
898 | } | ||
899 | |||
900 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) | ||
901 | { | ||
902 | struct viu_fh *fh = priv; | ||
903 | |||
904 | return videobuf_dqbuf(&fh->vb_vidq, p, | ||
905 | file->f_flags & O_NONBLOCK); | ||
906 | } | ||
907 | |||
908 | static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) | ||
909 | { | ||
910 | struct viu_fh *fh = priv; | ||
911 | |||
912 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
913 | return -EINVAL; | ||
914 | if (fh->type != i) | ||
915 | return -EINVAL; | ||
916 | |||
917 | return videobuf_streamon(&fh->vb_vidq); | ||
918 | } | ||
919 | |||
920 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | ||
921 | { | ||
922 | struct viu_fh *fh = priv; | ||
923 | |||
924 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
925 | return -EINVAL; | ||
926 | if (fh->type != i) | ||
927 | return -EINVAL; | ||
928 | |||
929 | return videobuf_streamoff(&fh->vb_vidq); | ||
930 | } | ||
931 | |||
932 | #define decoder_call(viu, o, f, args...) \ | ||
933 | v4l2_subdev_call(viu->decoder, o, f, ##args) | ||
934 | |||
935 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) | ||
936 | { | ||
937 | struct viu_fh *fh = priv; | ||
938 | |||
939 | decoder_call(fh->dev, core, s_std, *id); | ||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | /* only one input in this driver */ | ||
944 | static int vidioc_enum_input(struct file *file, void *priv, | ||
945 | struct v4l2_input *inp) | ||
946 | { | ||
947 | struct viu_fh *fh = priv; | ||
948 | |||
949 | if (inp->index != 0) | ||
950 | return -EINVAL; | ||
951 | |||
952 | inp->type = V4L2_INPUT_TYPE_CAMERA; | ||
953 | inp->std = fh->dev->vdev->tvnorms; | ||
954 | strcpy(inp->name, "Camera"); | ||
955 | return 0; | ||
956 | } | ||
957 | |||
958 | static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) | ||
959 | { | ||
960 | *i = 0; | ||
961 | return 0; | ||
962 | } | ||
963 | |||
964 | static int vidioc_s_input(struct file *file, void *priv, unsigned int i) | ||
965 | { | ||
966 | struct viu_fh *fh = priv; | ||
967 | |||
968 | if (i > 1) | ||
969 | return -EINVAL; | ||
970 | |||
971 | decoder_call(fh->dev, video, s_routing, i, 0, 0); | ||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | /* Controls */ | ||
976 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
977 | struct v4l2_queryctrl *qc) | ||
978 | { | ||
979 | int i; | ||
980 | |||
981 | for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) { | ||
982 | if (qc->id && qc->id == viu_qctrl[i].id) { | ||
983 | memcpy(qc, &(viu_qctrl[i]), sizeof(*qc)); | ||
984 | return 0; | ||
985 | } | ||
986 | } | ||
987 | return -EINVAL; | ||
988 | } | ||
989 | |||
990 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
991 | struct v4l2_control *ctrl) | ||
992 | { | ||
993 | int i; | ||
994 | |||
995 | for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) { | ||
996 | if (ctrl->id == viu_qctrl[i].id) { | ||
997 | ctrl->value = qctl_regs[i]; | ||
998 | return 0; | ||
999 | } | ||
1000 | } | ||
1001 | return -EINVAL; | ||
1002 | } | ||
1003 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
1004 | struct v4l2_control *ctrl) | ||
1005 | { | ||
1006 | int i; | ||
1007 | |||
1008 | for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) { | ||
1009 | if (ctrl->id == viu_qctrl[i].id) { | ||
1010 | if (ctrl->value < viu_qctrl[i].minimum | ||
1011 | || ctrl->value > viu_qctrl[i].maximum) | ||
1012 | return -ERANGE; | ||
1013 | qctl_regs[i] = ctrl->value; | ||
1014 | return 0; | ||
1015 | } | ||
1016 | } | ||
1017 | return -EINVAL; | ||
1018 | } | ||
1019 | |||
1020 | inline void viu_activate_next_buf(struct viu_dev *dev, | ||
1021 | struct viu_dmaqueue *viuq) | ||
1022 | { | ||
1023 | struct viu_dmaqueue *vidq = viuq; | ||
1024 | struct viu_buf *buf; | ||
1025 | |||
1026 | /* launch another DMA operation for an active/queued buffer */ | ||
1027 | if (!list_empty(&vidq->active)) { | ||
1028 | buf = list_entry(vidq->active.next, struct viu_buf, | ||
1029 | vb.queue); | ||
1030 | dprintk(1, "start another queued buffer: 0x%p\n", buf); | ||
1031 | buffer_activate(dev, buf); | ||
1032 | } else if (!list_empty(&vidq->queued)) { | ||
1033 | buf = list_entry(vidq->queued.next, struct viu_buf, | ||
1034 | vb.queue); | ||
1035 | list_del(&buf->vb.queue); | ||
1036 | |||
1037 | dprintk(1, "start another queued buffer: 0x%p\n", buf); | ||
1038 | list_add_tail(&buf->vb.queue, &vidq->active); | ||
1039 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
1040 | buffer_activate(dev, buf); | ||
1041 | } | ||
1042 | } | ||
1043 | |||
1044 | inline void viu_default_settings(struct viu_reg *viu_reg) | ||
1045 | { | ||
1046 | struct viu_reg *vr = viu_reg; | ||
1047 | |||
1048 | out_be32(&vr->luminance, 0x9512A254); | ||
1049 | out_be32(&vr->chroma_r, 0x03310000); | ||
1050 | out_be32(&vr->chroma_g, 0x06600F38); | ||
1051 | out_be32(&vr->chroma_b, 0x00000409); | ||
1052 | out_be32(&vr->alpha, 0x000000ff); | ||
1053 | out_be32(&vr->req_alarm, 0x00000090); | ||
1054 | dprintk(1, "status reg: 0x%08x, field base: 0x%08x\n", | ||
1055 | in_be32(&vr->status_cfg), in_be32(&vr->field_base_addr)); | ||
1056 | } | ||
1057 | |||
1058 | static void viu_overlay_intr(struct viu_dev *dev, u32 status) | ||
1059 | { | ||
1060 | struct viu_reg *vr = dev->vr; | ||
1061 | |||
1062 | if (status & INT_DMA_END_STATUS) | ||
1063 | dev->dma_done = 1; | ||
1064 | |||
1065 | if (status & INT_FIELD_STATUS) { | ||
1066 | if (dev->dma_done) { | ||
1067 | u32 addr = reg_val.field_base_addr; | ||
1068 | |||
1069 | dev->dma_done = 0; | ||
1070 | if (status & FIELD_NO) | ||
1071 | addr += reg_val.dma_inc; | ||
1072 | |||
1073 | out_be32(&vr->field_base_addr, addr); | ||
1074 | out_be32(&vr->dma_inc, reg_val.dma_inc); | ||
1075 | out_be32(&vr->status_cfg, | ||
1076 | (status & 0xffc0ffff) | | ||
1077 | (status & INT_ALL_STATUS) | | ||
1078 | reg_val.status_cfg); | ||
1079 | } else if (status & INT_VSYNC_STATUS) { | ||
1080 | out_be32(&vr->status_cfg, | ||
1081 | (status & 0xffc0ffff) | | ||
1082 | (status & INT_ALL_STATUS) | | ||
1083 | reg_val.status_cfg); | ||
1084 | } | ||
1085 | } | ||
1086 | } | ||
1087 | |||
1088 | static void viu_capture_intr(struct viu_dev *dev, u32 status) | ||
1089 | { | ||
1090 | struct viu_dmaqueue *vidq = &dev->vidq; | ||
1091 | struct viu_reg *vr = dev->vr; | ||
1092 | struct viu_buf *buf; | ||
1093 | int field_num; | ||
1094 | int need_two; | ||
1095 | int dma_done = 0; | ||
1096 | |||
1097 | field_num = status & FIELD_NO; | ||
1098 | need_two = V4L2_FIELD_HAS_BOTH(dev->capfield); | ||
1099 | |||
1100 | if (status & INT_DMA_END_STATUS) { | ||
1101 | dma_done = 1; | ||
1102 | if (((field_num == 0) && (dev->field == 0)) || | ||
1103 | (field_num && (dev->field == 1))) | ||
1104 | dev->field++; | ||
1105 | } | ||
1106 | |||
1107 | if (status & INT_FIELD_STATUS) { | ||
1108 | dprintk(1, "irq: field %d, done %d\n", | ||
1109 | !!field_num, dma_done); | ||
1110 | if (unlikely(dev->first)) { | ||
1111 | if (field_num == 0) { | ||
1112 | dev->first = 0; | ||
1113 | dprintk(1, "activate first buf\n"); | ||
1114 | viu_activate_next_buf(dev, vidq); | ||
1115 | } else | ||
1116 | dprintk(1, "wait field 0\n"); | ||
1117 | return; | ||
1118 | } | ||
1119 | |||
1120 | /* setup buffer address for next dma operation */ | ||
1121 | if (!list_empty(&vidq->active)) { | ||
1122 | u32 addr = reg_val.field_base_addr; | ||
1123 | |||
1124 | if (field_num && need_two) { | ||
1125 | addr += reg_val.dma_inc; | ||
1126 | dprintk(1, "field 1, 0x%lx, dev field %d\n", | ||
1127 | (unsigned long)addr, dev->field); | ||
1128 | } | ||
1129 | out_be32(&vr->field_base_addr, addr); | ||
1130 | out_be32(&vr->dma_inc, reg_val.dma_inc); | ||
1131 | out_be32(&vr->status_cfg, | ||
1132 | (status & 0xffc0ffff) | | ||
1133 | (status & INT_ALL_STATUS) | | ||
1134 | reg_val.status_cfg); | ||
1135 | return; | ||
1136 | } | ||
1137 | } | ||
1138 | |||
1139 | if (dma_done && field_num && (dev->field == 2)) { | ||
1140 | dev->field = 0; | ||
1141 | buf = list_entry(vidq->active.next, | ||
1142 | struct viu_buf, vb.queue); | ||
1143 | dprintk(1, "viu/0: [%p/%d] 0x%lx/0x%lx: dma complete\n", | ||
1144 | buf, buf->vb.i, | ||
1145 | (unsigned long)videobuf_to_dma_contig(&buf->vb), | ||
1146 | (unsigned long)in_be32(&vr->field_base_addr)); | ||
1147 | |||
1148 | if (waitqueue_active(&buf->vb.done)) { | ||
1149 | list_del(&buf->vb.queue); | ||
1150 | do_gettimeofday(&buf->vb.ts); | ||
1151 | buf->vb.state = VIDEOBUF_DONE; | ||
1152 | buf->vb.field_count++; | ||
1153 | wake_up(&buf->vb.done); | ||
1154 | } | ||
1155 | /* activate next dma buffer */ | ||
1156 | viu_activate_next_buf(dev, vidq); | ||
1157 | } | ||
1158 | } | ||
1159 | |||
1160 | static irqreturn_t viu_intr(int irq, void *dev_id) | ||
1161 | { | ||
1162 | struct viu_dev *dev = (struct viu_dev *)dev_id; | ||
1163 | struct viu_reg *vr = dev->vr; | ||
1164 | u32 status; | ||
1165 | u32 error; | ||
1166 | |||
1167 | status = in_be32(&vr->status_cfg); | ||
1168 | |||
1169 | if (status & INT_ERROR_STATUS) { | ||
1170 | dev->irqs.error_irq++; | ||
1171 | error = status & ERR_MASK; | ||
1172 | if (error) | ||
1173 | dprintk(1, "Err: error(%d), times:%d!\n", | ||
1174 | error >> 4, dev->irqs.error_irq); | ||
1175 | /* Clear interrupt error bit and error flags */ | ||
1176 | out_be32(&vr->status_cfg, | ||
1177 | (status & 0xffc0ffff) | INT_ERROR_STATUS); | ||
1178 | } | ||
1179 | |||
1180 | if (status & INT_DMA_END_STATUS) { | ||
1181 | dev->irqs.dma_end_irq++; | ||
1182 | dev->dma_done = 1; | ||
1183 | dprintk(2, "VIU DMA end interrupt times: %d\n", | ||
1184 | dev->irqs.dma_end_irq); | ||
1185 | } | ||
1186 | |||
1187 | if (status & INT_HSYNC_STATUS) | ||
1188 | dev->irqs.hsync_irq++; | ||
1189 | |||
1190 | if (status & INT_FIELD_STATUS) { | ||
1191 | dev->irqs.field_irq++; | ||
1192 | dprintk(2, "VIU field interrupt times: %d\n", | ||
1193 | dev->irqs.field_irq); | ||
1194 | } | ||
1195 | |||
1196 | if (status & INT_VSTART_STATUS) | ||
1197 | dev->irqs.vstart_irq++; | ||
1198 | |||
1199 | if (status & INT_VSYNC_STATUS) { | ||
1200 | dev->irqs.vsync_irq++; | ||
1201 | dprintk(2, "VIU vsync interrupt times: %d\n", | ||
1202 | dev->irqs.vsync_irq); | ||
1203 | } | ||
1204 | |||
1205 | /* clear all pending irqs */ | ||
1206 | status = in_be32(&vr->status_cfg); | ||
1207 | out_be32(&vr->status_cfg, | ||
1208 | (status & 0xffc0ffff) | (status & INT_ALL_STATUS)); | ||
1209 | |||
1210 | if (dev->ovenable) { | ||
1211 | viu_overlay_intr(dev, status); | ||
1212 | return IRQ_HANDLED; | ||
1213 | } | ||
1214 | |||
1215 | /* Capture mode */ | ||
1216 | viu_capture_intr(dev, status); | ||
1217 | return IRQ_HANDLED; | ||
1218 | } | ||
1219 | |||
1220 | /* | ||
1221 | * File operations for the device | ||
1222 | */ | ||
1223 | static int viu_open(struct file *file) | ||
1224 | { | ||
1225 | struct video_device *vdev = video_devdata(file); | ||
1226 | struct viu_dev *dev = video_get_drvdata(vdev); | ||
1227 | struct viu_fh *fh; | ||
1228 | struct viu_reg *vr; | ||
1229 | int minor = vdev->minor; | ||
1230 | u32 status_cfg; | ||
1231 | int i; | ||
1232 | |||
1233 | dprintk(1, "viu: open (minor=%d)\n", minor); | ||
1234 | |||
1235 | dev->users++; | ||
1236 | if (dev->users > 1) { | ||
1237 | dev->users--; | ||
1238 | return -EBUSY; | ||
1239 | } | ||
1240 | |||
1241 | vr = dev->vr; | ||
1242 | |||
1243 | dprintk(1, "open minor=%d type=%s users=%d\n", minor, | ||
1244 | v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); | ||
1245 | |||
1246 | /* allocate and initialize per filehandle data */ | ||
1247 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | ||
1248 | if (!fh) { | ||
1249 | dev->users--; | ||
1250 | return -ENOMEM; | ||
1251 | } | ||
1252 | |||
1253 | file->private_data = fh; | ||
1254 | fh->dev = dev; | ||
1255 | |||
1256 | fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1257 | fh->fmt = format_by_fourcc(V4L2_PIX_FMT_RGB32); | ||
1258 | fh->width = norm_maxw(); | ||
1259 | fh->height = norm_maxh(); | ||
1260 | dev->crop_current.width = fh->width; | ||
1261 | dev->crop_current.height = fh->height; | ||
1262 | |||
1263 | /* Put all controls at a sane state */ | ||
1264 | for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) | ||
1265 | qctl_regs[i] = viu_qctrl[i].default_value; | ||
1266 | |||
1267 | dprintk(1, "Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n", | ||
1268 | (unsigned long)fh, (unsigned long)dev, | ||
1269 | (unsigned long)&dev->vidq); | ||
1270 | dprintk(1, "Open: list_empty queued=%d\n", | ||
1271 | list_empty(&dev->vidq.queued)); | ||
1272 | dprintk(1, "Open: list_empty active=%d\n", | ||
1273 | list_empty(&dev->vidq.active)); | ||
1274 | |||
1275 | viu_default_settings(vr); | ||
1276 | |||
1277 | status_cfg = in_be32(&vr->status_cfg); | ||
1278 | out_be32(&vr->status_cfg, | ||
1279 | status_cfg & ~(INT_VSYNC_EN | INT_HSYNC_EN | | ||
1280 | INT_FIELD_EN | INT_VSTART_EN | | ||
1281 | INT_DMA_END_EN | INT_ERROR_EN | INT_ECC_EN)); | ||
1282 | |||
1283 | status_cfg = in_be32(&vr->status_cfg); | ||
1284 | out_be32(&vr->status_cfg, status_cfg | INT_ALL_STATUS); | ||
1285 | |||
1286 | spin_lock_init(&fh->vbq_lock); | ||
1287 | videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops, | ||
1288 | dev->dev, &fh->vbq_lock, | ||
1289 | fh->type, V4L2_FIELD_INTERLACED, | ||
1290 | sizeof(struct viu_buf), fh); | ||
1291 | return 0; | ||
1292 | } | ||
1293 | |||
1294 | static ssize_t viu_read(struct file *file, char __user *data, size_t count, | ||
1295 | loff_t *ppos) | ||
1296 | { | ||
1297 | struct viu_fh *fh = file->private_data; | ||
1298 | struct viu_dev *dev = fh->dev; | ||
1299 | int ret = 0; | ||
1300 | |||
1301 | dprintk(2, "%s\n", __func__); | ||
1302 | if (dev->ovenable) | ||
1303 | dev->ovenable = 0; | ||
1304 | |||
1305 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
1306 | viu_start_dma(dev); | ||
1307 | ret = videobuf_read_stream(&fh->vb_vidq, data, count, | ||
1308 | ppos, 0, file->f_flags & O_NONBLOCK); | ||
1309 | return ret; | ||
1310 | } | ||
1311 | return 0; | ||
1312 | } | ||
1313 | |||
1314 | static unsigned int viu_poll(struct file *file, struct poll_table_struct *wait) | ||
1315 | { | ||
1316 | struct viu_fh *fh = file->private_data; | ||
1317 | struct videobuf_queue *q = &fh->vb_vidq; | ||
1318 | |||
1319 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) | ||
1320 | return POLLERR; | ||
1321 | |||
1322 | return videobuf_poll_stream(file, q, wait); | ||
1323 | } | ||
1324 | |||
1325 | static int viu_release(struct file *file) | ||
1326 | { | ||
1327 | struct viu_fh *fh = file->private_data; | ||
1328 | struct viu_dev *dev = fh->dev; | ||
1329 | int minor = video_devdata(file)->minor; | ||
1330 | |||
1331 | viu_stop_dma(dev); | ||
1332 | videobuf_stop(&fh->vb_vidq); | ||
1333 | |||
1334 | kfree(fh); | ||
1335 | |||
1336 | dev->users--; | ||
1337 | dprintk(1, "close (minor=%d, users=%d)\n", | ||
1338 | minor, dev->users); | ||
1339 | return 0; | ||
1340 | } | ||
1341 | |||
1342 | void viu_reset(struct viu_reg *reg) | ||
1343 | { | ||
1344 | out_be32(®->status_cfg, 0); | ||
1345 | out_be32(®->luminance, 0x9512a254); | ||
1346 | out_be32(®->chroma_r, 0x03310000); | ||
1347 | out_be32(®->chroma_g, 0x06600f38); | ||
1348 | out_be32(®->chroma_b, 0x00000409); | ||
1349 | out_be32(®->field_base_addr, 0); | ||
1350 | out_be32(®->dma_inc, 0); | ||
1351 | out_be32(®->picture_count, 0x01e002d0); | ||
1352 | out_be32(®->req_alarm, 0x00000090); | ||
1353 | out_be32(®->alpha, 0x000000ff); | ||
1354 | } | ||
1355 | |||
1356 | static int viu_mmap(struct file *file, struct vm_area_struct *vma) | ||
1357 | { | ||
1358 | struct viu_fh *fh = file->private_data; | ||
1359 | int ret; | ||
1360 | |||
1361 | dprintk(1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); | ||
1362 | |||
1363 | ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); | ||
1364 | |||
1365 | dprintk(1, "vma start=0x%08lx, size=%ld, ret=%d\n", | ||
1366 | (unsigned long)vma->vm_start, | ||
1367 | (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, | ||
1368 | ret); | ||
1369 | |||
1370 | return ret; | ||
1371 | } | ||
1372 | |||
1373 | static struct v4l2_file_operations viu_fops = { | ||
1374 | .owner = THIS_MODULE, | ||
1375 | .open = viu_open, | ||
1376 | .release = viu_release, | ||
1377 | .read = viu_read, | ||
1378 | .poll = viu_poll, | ||
1379 | .ioctl = video_ioctl2, /* V4L2 ioctl handler */ | ||
1380 | .mmap = viu_mmap, | ||
1381 | }; | ||
1382 | |||
1383 | static const struct v4l2_ioctl_ops viu_ioctl_ops = { | ||
1384 | .vidioc_querycap = vidioc_querycap, | ||
1385 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, | ||
1386 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_cap, | ||
1387 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_cap, | ||
1388 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_cap, | ||
1389 | .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt, | ||
1390 | .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_overlay, | ||
1391 | .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_overlay, | ||
1392 | .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_overlay, | ||
1393 | .vidioc_g_fbuf = vidioc_g_fbuf, | ||
1394 | .vidioc_s_fbuf = vidioc_s_fbuf, | ||
1395 | .vidioc_reqbufs = vidioc_reqbufs, | ||
1396 | .vidioc_querybuf = vidioc_querybuf, | ||
1397 | .vidioc_qbuf = vidioc_qbuf, | ||
1398 | .vidioc_dqbuf = vidioc_dqbuf, | ||
1399 | .vidioc_s_std = vidioc_s_std, | ||
1400 | .vidioc_enum_input = vidioc_enum_input, | ||
1401 | .vidioc_g_input = vidioc_g_input, | ||
1402 | .vidioc_s_input = vidioc_s_input, | ||
1403 | .vidioc_queryctrl = vidioc_queryctrl, | ||
1404 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
1405 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1406 | .vidioc_streamon = vidioc_streamon, | ||
1407 | .vidioc_streamoff = vidioc_streamoff, | ||
1408 | }; | ||
1409 | |||
1410 | static struct video_device viu_template = { | ||
1411 | .name = "FSL viu", | ||
1412 | .fops = &viu_fops, | ||
1413 | .minor = -1, | ||
1414 | .ioctl_ops = &viu_ioctl_ops, | ||
1415 | .release = video_device_release, | ||
1416 | |||
1417 | .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL, | ||
1418 | .current_norm = V4L2_STD_NTSC_M, | ||
1419 | }; | ||
1420 | |||
1421 | static int __devinit viu_of_probe(struct of_device *op, | ||
1422 | const struct of_device_id *match) | ||
1423 | { | ||
1424 | struct viu_dev *viu_dev; | ||
1425 | struct video_device *vdev; | ||
1426 | struct resource r; | ||
1427 | struct viu_reg __iomem *viu_regs; | ||
1428 | struct i2c_adapter *ad; | ||
1429 | int ret, viu_irq; | ||
1430 | |||
1431 | ret = of_address_to_resource(op->dev.of_node, 0, &r); | ||
1432 | if (ret) { | ||
1433 | dev_err(&op->dev, "Can't parse device node resource\n"); | ||
1434 | return -ENODEV; | ||
1435 | } | ||
1436 | |||
1437 | viu_irq = irq_of_parse_and_map(op->dev.of_node, 0); | ||
1438 | if (viu_irq == NO_IRQ) { | ||
1439 | dev_err(&op->dev, "Error while mapping the irq\n"); | ||
1440 | return -EINVAL; | ||
1441 | } | ||
1442 | |||
1443 | /* request mem region */ | ||
1444 | if (!devm_request_mem_region(&op->dev, r.start, | ||
1445 | sizeof(struct viu_reg), DRV_NAME)) { | ||
1446 | dev_err(&op->dev, "Error while requesting mem region\n"); | ||
1447 | ret = -EBUSY; | ||
1448 | goto err; | ||
1449 | } | ||
1450 | |||
1451 | /* remap registers */ | ||
1452 | viu_regs = devm_ioremap(&op->dev, r.start, sizeof(struct viu_reg)); | ||
1453 | if (!viu_regs) { | ||
1454 | dev_err(&op->dev, "Can't map register set\n"); | ||
1455 | ret = -ENOMEM; | ||
1456 | goto err; | ||
1457 | } | ||
1458 | |||
1459 | /* Prepare our private structure */ | ||
1460 | viu_dev = devm_kzalloc(&op->dev, sizeof(struct viu_dev), GFP_ATOMIC); | ||
1461 | if (!viu_dev) { | ||
1462 | dev_err(&op->dev, "Can't allocate private structure\n"); | ||
1463 | ret = -ENOMEM; | ||
1464 | goto err; | ||
1465 | } | ||
1466 | |||
1467 | viu_dev->vr = viu_regs; | ||
1468 | viu_dev->irq = viu_irq; | ||
1469 | viu_dev->dev = &op->dev; | ||
1470 | |||
1471 | /* init video dma queues */ | ||
1472 | INIT_LIST_HEAD(&viu_dev->vidq.active); | ||
1473 | INIT_LIST_HEAD(&viu_dev->vidq.queued); | ||
1474 | |||
1475 | /* initialize locks */ | ||
1476 | mutex_init(&viu_dev->lock); | ||
1477 | |||
1478 | snprintf(viu_dev->v4l2_dev.name, | ||
1479 | sizeof(viu_dev->v4l2_dev.name), "%s", "VIU"); | ||
1480 | ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev); | ||
1481 | if (ret < 0) { | ||
1482 | dev_err(&op->dev, "v4l2_device_register() failed: %d\n", ret); | ||
1483 | goto err; | ||
1484 | } | ||
1485 | |||
1486 | ad = i2c_get_adapter(0); | ||
1487 | viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad, | ||
1488 | "saa7115", "saa7113", VIU_VIDEO_DECODER_ADDR, NULL); | ||
1489 | |||
1490 | viu_dev->vidq.timeout.function = viu_vid_timeout; | ||
1491 | viu_dev->vidq.timeout.data = (unsigned long)viu_dev; | ||
1492 | init_timer(&viu_dev->vidq.timeout); | ||
1493 | viu_dev->first = 1; | ||
1494 | |||
1495 | /* Allocate memory for video device */ | ||
1496 | vdev = video_device_alloc(); | ||
1497 | if (vdev == NULL) { | ||
1498 | ret = -ENOMEM; | ||
1499 | goto err_vdev; | ||
1500 | } | ||
1501 | |||
1502 | memcpy(vdev, &viu_template, sizeof(viu_template)); | ||
1503 | |||
1504 | vdev->v4l2_dev = &viu_dev->v4l2_dev; | ||
1505 | |||
1506 | viu_dev->vdev = vdev; | ||
1507 | |||
1508 | video_set_drvdata(viu_dev->vdev, viu_dev); | ||
1509 | |||
1510 | ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1); | ||
1511 | if (ret < 0) { | ||
1512 | video_device_release(viu_dev->vdev); | ||
1513 | goto err_vdev; | ||
1514 | } | ||
1515 | |||
1516 | /* enable VIU clock */ | ||
1517 | viu_dev->clk = clk_get(&op->dev, "viu_clk"); | ||
1518 | if (IS_ERR(viu_dev->clk)) { | ||
1519 | dev_err(&op->dev, "failed to find the clock module!\n"); | ||
1520 | ret = -ENODEV; | ||
1521 | goto err_clk; | ||
1522 | } else { | ||
1523 | clk_enable(viu_dev->clk); | ||
1524 | } | ||
1525 | |||
1526 | /* reset VIU module */ | ||
1527 | viu_reset(viu_dev->vr); | ||
1528 | |||
1529 | /* install interrupt handler */ | ||
1530 | if (request_irq(viu_dev->irq, viu_intr, 0, "viu", (void *)viu_dev)) { | ||
1531 | dev_err(&op->dev, "Request VIU IRQ failed.\n"); | ||
1532 | ret = -ENODEV; | ||
1533 | goto err_irq; | ||
1534 | } | ||
1535 | |||
1536 | dev_info(&op->dev, "Freescale VIU Video Capture Board\n"); | ||
1537 | return ret; | ||
1538 | |||
1539 | err_irq: | ||
1540 | clk_disable(viu_dev->clk); | ||
1541 | clk_put(viu_dev->clk); | ||
1542 | err_clk: | ||
1543 | video_unregister_device(viu_dev->vdev); | ||
1544 | err_vdev: | ||
1545 | i2c_put_adapter(ad); | ||
1546 | v4l2_device_unregister(&viu_dev->v4l2_dev); | ||
1547 | err: | ||
1548 | irq_dispose_mapping(viu_irq); | ||
1549 | return ret; | ||
1550 | } | ||
1551 | |||
1552 | static int __devexit viu_of_remove(struct of_device *op) | ||
1553 | { | ||
1554 | struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev); | ||
1555 | struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev); | ||
1556 | struct v4l2_subdev *sdev = list_entry(v4l2_dev->subdevs.next, | ||
1557 | struct v4l2_subdev, list); | ||
1558 | struct i2c_client *client = v4l2_get_subdevdata(sdev); | ||
1559 | |||
1560 | free_irq(dev->irq, (void *)dev); | ||
1561 | irq_dispose_mapping(dev->irq); | ||
1562 | |||
1563 | clk_disable(dev->clk); | ||
1564 | clk_put(dev->clk); | ||
1565 | |||
1566 | video_unregister_device(dev->vdev); | ||
1567 | i2c_put_adapter(client->adapter); | ||
1568 | v4l2_device_unregister(&dev->v4l2_dev); | ||
1569 | return 0; | ||
1570 | } | ||
1571 | |||
1572 | #ifdef CONFIG_PM | ||
1573 | static int viu_suspend(struct of_device *op, pm_message_t state) | ||
1574 | { | ||
1575 | struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev); | ||
1576 | struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev); | ||
1577 | |||
1578 | clk_disable(dev->clk); | ||
1579 | return 0; | ||
1580 | } | ||
1581 | |||
1582 | static int viu_resume(struct of_device *op) | ||
1583 | { | ||
1584 | struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev); | ||
1585 | struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev); | ||
1586 | |||
1587 | clk_enable(dev->clk); | ||
1588 | return 0; | ||
1589 | } | ||
1590 | #endif | ||
1591 | |||
1592 | /* | ||
1593 | * Initialization and module stuff | ||
1594 | */ | ||
1595 | static struct of_device_id mpc512x_viu_of_match[] = { | ||
1596 | { | ||
1597 | .compatible = "fsl,mpc5121-viu", | ||
1598 | }, | ||
1599 | {}, | ||
1600 | }; | ||
1601 | MODULE_DEVICE_TABLE(of, mpc512x_viu_of_match); | ||
1602 | |||
1603 | static struct of_platform_driver viu_of_platform_driver = { | ||
1604 | .probe = viu_of_probe, | ||
1605 | .remove = __devexit_p(viu_of_remove), | ||
1606 | #ifdef CONFIG_PM | ||
1607 | .suspend = viu_suspend, | ||
1608 | .resume = viu_resume, | ||
1609 | #endif | ||
1610 | .driver = { | ||
1611 | .name = DRV_NAME, | ||
1612 | .owner = THIS_MODULE, | ||
1613 | .of_match_table = mpc512x_viu_of_match, | ||
1614 | }, | ||
1615 | }; | ||
1616 | |||
1617 | static int __init viu_init(void) | ||
1618 | { | ||
1619 | return of_register_platform_driver(&viu_of_platform_driver); | ||
1620 | } | ||
1621 | |||
1622 | static void __exit viu_exit(void) | ||
1623 | { | ||
1624 | of_unregister_platform_driver(&viu_of_platform_driver); | ||
1625 | } | ||
1626 | |||
1627 | module_init(viu_init); | ||
1628 | module_exit(viu_exit); | ||
1629 | |||
1630 | MODULE_DESCRIPTION("Freescale Video-In(VIU)"); | ||
1631 | MODULE_AUTHOR("Hongjun Chen"); | ||
1632 | MODULE_LICENSE("GPL"); | ||