diff options
author | Scott Jiang <scott.jiang.linux@gmail.com> | 2012-03-08 15:44:17 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-03-19 14:08:20 -0400 |
commit | 63b1a90da93e019adcafa2b2b1b921fc97debec5 (patch) | |
tree | 1b90018dd9b9ac89207293be1672427ac377c33e /drivers | |
parent | f877ed9780f43da51a4544e5b90b7f4a145964ff (diff) |
[media] add blackfin capture bridge driver
This is a v4l2 bridge driver for Blackfin video capture device, support ppi and eppi interface.
Signed-off-by: Scott Jiang <scott.jiang.linux@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/Kconfig | 2 | ||||
-rw-r--r-- | drivers/media/video/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/video/blackfin/Kconfig | 10 | ||||
-rw-r--r-- | drivers/media/video/blackfin/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/video/blackfin/bfin_capture.c | 1059 | ||||
-rw-r--r-- | drivers/media/video/blackfin/ppi.c | 271 |
6 files changed, 1346 insertions, 0 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index e618ca6e71ba..3cea9797740e 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -871,6 +871,8 @@ source "drivers/media/video/davinci/Kconfig" | |||
871 | 871 | ||
872 | source "drivers/media/video/omap/Kconfig" | 872 | source "drivers/media/video/omap/Kconfig" |
873 | 873 | ||
874 | source "drivers/media/video/blackfin/Kconfig" | ||
875 | |||
874 | config VIDEO_SH_VOU | 876 | config VIDEO_SH_VOU |
875 | tristate "SuperH VOU video output driver" | 877 | tristate "SuperH VOU video output driver" |
876 | depends on VIDEO_DEV && ARCH_SHMOBILE | 878 | depends on VIDEO_DEV && ARCH_SHMOBILE |
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index ac29ae00dce3..c71c0d11755d 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -187,6 +187,8 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV) += s5p-tv/ | |||
187 | 187 | ||
188 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/ | 188 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/ |
189 | 189 | ||
190 | obj-$(CONFIG_BLACKFIN) += blackfin/ | ||
191 | |||
190 | obj-$(CONFIG_ARCH_DAVINCI) += davinci/ | 192 | obj-$(CONFIG_ARCH_DAVINCI) += davinci/ |
191 | 193 | ||
192 | obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o | 194 | obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o |
diff --git a/drivers/media/video/blackfin/Kconfig b/drivers/media/video/blackfin/Kconfig new file mode 100644 index 000000000000..ecd5323768b7 --- /dev/null +++ b/drivers/media/video/blackfin/Kconfig | |||
@@ -0,0 +1,10 @@ | |||
1 | config VIDEO_BLACKFIN_CAPTURE | ||
2 | tristate "Blackfin Video Capture Driver" | ||
3 | depends on VIDEO_V4L2 && BLACKFIN && I2C | ||
4 | select VIDEOBUF2_DMA_CONTIG | ||
5 | help | ||
6 | V4L2 bridge driver for Blackfin video capture device. | ||
7 | Choose PPI or EPPI as its interface. | ||
8 | |||
9 | To compile this driver as a module, choose M here: the | ||
10 | module will be called bfin_video_capture. | ||
diff --git a/drivers/media/video/blackfin/Makefile b/drivers/media/video/blackfin/Makefile new file mode 100644 index 000000000000..aa3a0a216387 --- /dev/null +++ b/drivers/media/video/blackfin/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | bfin_video_capture-objs := bfin_capture.o ppi.o | ||
2 | obj-$(CONFIG_VIDEO_BLACKFIN_CAPTURE) += bfin_video_capture.o | ||
diff --git a/drivers/media/video/blackfin/bfin_capture.c b/drivers/media/video/blackfin/bfin_capture.c new file mode 100644 index 000000000000..514fcf742f5a --- /dev/null +++ b/drivers/media/video/blackfin/bfin_capture.c | |||
@@ -0,0 +1,1059 @@ | |||
1 | /* | ||
2 | * Analog Devices video capture driver | ||
3 | * | ||
4 | * Copyright (c) 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/completion.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/time.h> | ||
33 | #include <linux/types.h> | ||
34 | |||
35 | #include <media/v4l2-chip-ident.h> | ||
36 | #include <media/v4l2-common.h> | ||
37 | #include <media/v4l2-ctrls.h> | ||
38 | #include <media/v4l2-device.h> | ||
39 | #include <media/v4l2-ioctl.h> | ||
40 | #include <media/videobuf2-dma-contig.h> | ||
41 | |||
42 | #include <asm/dma.h> | ||
43 | |||
44 | #include <media/blackfin/bfin_capture.h> | ||
45 | #include <media/blackfin/ppi.h> | ||
46 | |||
47 | #define CAPTURE_DRV_NAME "bfin_capture" | ||
48 | #define BCAP_MIN_NUM_BUF 2 | ||
49 | |||
50 | struct bcap_format { | ||
51 | char *desc; | ||
52 | u32 pixelformat; | ||
53 | enum v4l2_mbus_pixelcode mbus_code; | ||
54 | int bpp; /* bits per pixel */ | ||
55 | }; | ||
56 | |||
57 | struct bcap_buffer { | ||
58 | struct vb2_buffer vb; | ||
59 | struct list_head list; | ||
60 | }; | ||
61 | |||
62 | struct bcap_device { | ||
63 | /* capture device instance */ | ||
64 | struct v4l2_device v4l2_dev; | ||
65 | /* v4l2 control handler */ | ||
66 | struct v4l2_ctrl_handler ctrl_handler; | ||
67 | /* device node data */ | ||
68 | struct video_device *video_dev; | ||
69 | /* sub device instance */ | ||
70 | struct v4l2_subdev *sd; | ||
71 | /* capture config */ | ||
72 | struct bfin_capture_config *cfg; | ||
73 | /* ppi interface */ | ||
74 | struct ppi_if *ppi; | ||
75 | /* current input */ | ||
76 | unsigned int cur_input; | ||
77 | /* current selected standard */ | ||
78 | v4l2_std_id std; | ||
79 | /* used to store pixel format */ | ||
80 | struct v4l2_pix_format fmt; | ||
81 | /* bits per pixel*/ | ||
82 | int bpp; | ||
83 | /* used to store sensor supported format */ | ||
84 | struct bcap_format *sensor_formats; | ||
85 | /* number of sensor formats array */ | ||
86 | int num_sensor_formats; | ||
87 | /* pointing to current video buffer */ | ||
88 | struct bcap_buffer *cur_frm; | ||
89 | /* pointing to next video buffer */ | ||
90 | struct bcap_buffer *next_frm; | ||
91 | /* buffer queue used in videobuf2 */ | ||
92 | struct vb2_queue buffer_queue; | ||
93 | /* allocator-specific contexts for each plane */ | ||
94 | struct vb2_alloc_ctx *alloc_ctx; | ||
95 | /* queue of filled frames */ | ||
96 | struct list_head dma_queue; | ||
97 | /* used in videobuf2 callback */ | ||
98 | spinlock_t lock; | ||
99 | /* used to access capture device */ | ||
100 | struct mutex mutex; | ||
101 | /* used to wait ppi to complete one transfer */ | ||
102 | struct completion comp; | ||
103 | /* prepare to stop */ | ||
104 | bool stop; | ||
105 | }; | ||
106 | |||
107 | struct bcap_fh { | ||
108 | struct v4l2_fh fh; | ||
109 | /* indicates whether this file handle is doing IO */ | ||
110 | bool io_allowed; | ||
111 | }; | ||
112 | |||
113 | static const struct bcap_format bcap_formats[] = { | ||
114 | { | ||
115 | .desc = "YCbCr 4:2:2 Interleaved UYVY", | ||
116 | .pixelformat = V4L2_PIX_FMT_UYVY, | ||
117 | .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, | ||
118 | .bpp = 16, | ||
119 | }, | ||
120 | { | ||
121 | .desc = "YCbCr 4:2:2 Interleaved YUYV", | ||
122 | .pixelformat = V4L2_PIX_FMT_YUYV, | ||
123 | .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, | ||
124 | .bpp = 16, | ||
125 | }, | ||
126 | { | ||
127 | .desc = "RGB 565", | ||
128 | .pixelformat = V4L2_PIX_FMT_RGB565, | ||
129 | .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, | ||
130 | .bpp = 16, | ||
131 | }, | ||
132 | { | ||
133 | .desc = "RGB 444", | ||
134 | .pixelformat = V4L2_PIX_FMT_RGB444, | ||
135 | .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE, | ||
136 | .bpp = 16, | ||
137 | }, | ||
138 | |||
139 | }; | ||
140 | #define BCAP_MAX_FMTS ARRAY_SIZE(bcap_formats) | ||
141 | |||
142 | static irqreturn_t bcap_isr(int irq, void *dev_id); | ||
143 | |||
144 | static struct bcap_buffer *to_bcap_vb(struct vb2_buffer *vb) | ||
145 | { | ||
146 | return container_of(vb, struct bcap_buffer, vb); | ||
147 | } | ||
148 | |||
149 | static int bcap_init_sensor_formats(struct bcap_device *bcap_dev) | ||
150 | { | ||
151 | enum v4l2_mbus_pixelcode code; | ||
152 | struct bcap_format *sf; | ||
153 | unsigned int num_formats = 0; | ||
154 | int i, j; | ||
155 | |||
156 | while (!v4l2_subdev_call(bcap_dev->sd, video, | ||
157 | enum_mbus_fmt, num_formats, &code)) | ||
158 | num_formats++; | ||
159 | if (!num_formats) | ||
160 | return -ENXIO; | ||
161 | |||
162 | sf = kzalloc(num_formats * sizeof(*sf), GFP_KERNEL); | ||
163 | if (!sf) | ||
164 | return -ENOMEM; | ||
165 | |||
166 | for (i = 0; i < num_formats; i++) { | ||
167 | v4l2_subdev_call(bcap_dev->sd, video, | ||
168 | enum_mbus_fmt, i, &code); | ||
169 | for (j = 0; j < BCAP_MAX_FMTS; j++) | ||
170 | if (code == bcap_formats[j].mbus_code) | ||
171 | break; | ||
172 | if (j == BCAP_MAX_FMTS) { | ||
173 | /* we don't allow this sensor working with our bridge */ | ||
174 | kfree(sf); | ||
175 | return -EINVAL; | ||
176 | } | ||
177 | sf[i] = bcap_formats[j]; | ||
178 | } | ||
179 | bcap_dev->sensor_formats = sf; | ||
180 | bcap_dev->num_sensor_formats = num_formats; | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static void bcap_free_sensor_formats(struct bcap_device *bcap_dev) | ||
185 | { | ||
186 | bcap_dev->num_sensor_formats = 0; | ||
187 | kfree(bcap_dev->sensor_formats); | ||
188 | bcap_dev->sensor_formats = NULL; | ||
189 | } | ||
190 | |||
191 | static int bcap_open(struct file *file) | ||
192 | { | ||
193 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
194 | struct video_device *vfd = bcap_dev->video_dev; | ||
195 | struct bcap_fh *bcap_fh; | ||
196 | |||
197 | if (!bcap_dev->sd) { | ||
198 | v4l2_err(&bcap_dev->v4l2_dev, "No sub device registered\n"); | ||
199 | return -ENODEV; | ||
200 | } | ||
201 | |||
202 | bcap_fh = kzalloc(sizeof(*bcap_fh), GFP_KERNEL); | ||
203 | if (!bcap_fh) { | ||
204 | v4l2_err(&bcap_dev->v4l2_dev, | ||
205 | "unable to allocate memory for file handle object\n"); | ||
206 | return -ENOMEM; | ||
207 | } | ||
208 | |||
209 | v4l2_fh_init(&bcap_fh->fh, vfd); | ||
210 | |||
211 | /* store pointer to v4l2_fh in private_data member of file */ | ||
212 | file->private_data = &bcap_fh->fh; | ||
213 | v4l2_fh_add(&bcap_fh->fh); | ||
214 | bcap_fh->io_allowed = false; | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static int bcap_release(struct file *file) | ||
219 | { | ||
220 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
221 | struct v4l2_fh *fh = file->private_data; | ||
222 | struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); | ||
223 | |||
224 | /* if this instance is doing IO */ | ||
225 | if (bcap_fh->io_allowed) | ||
226 | vb2_queue_release(&bcap_dev->buffer_queue); | ||
227 | |||
228 | file->private_data = NULL; | ||
229 | v4l2_fh_del(&bcap_fh->fh); | ||
230 | v4l2_fh_exit(&bcap_fh->fh); | ||
231 | kfree(bcap_fh); | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static int bcap_mmap(struct file *file, struct vm_area_struct *vma) | ||
236 | { | ||
237 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
238 | |||
239 | return vb2_mmap(&bcap_dev->buffer_queue, vma); | ||
240 | } | ||
241 | |||
242 | #ifndef CONFIG_MMU | ||
243 | static unsigned long bcap_get_unmapped_area(struct file *file, | ||
244 | unsigned long addr, | ||
245 | unsigned long len, | ||
246 | unsigned long pgoff, | ||
247 | unsigned long flags) | ||
248 | { | ||
249 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
250 | |||
251 | return vb2_get_unmapped_area(&bcap_dev->buffer_queue, | ||
252 | addr, | ||
253 | len, | ||
254 | pgoff, | ||
255 | flags); | ||
256 | } | ||
257 | #endif | ||
258 | |||
259 | static unsigned int bcap_poll(struct file *file, poll_table *wait) | ||
260 | { | ||
261 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
262 | |||
263 | return vb2_poll(&bcap_dev->buffer_queue, file, wait); | ||
264 | } | ||
265 | |||
266 | static int bcap_queue_setup(struct vb2_queue *vq, | ||
267 | const struct v4l2_format *fmt, | ||
268 | unsigned int *nbuffers, unsigned int *nplanes, | ||
269 | unsigned int sizes[], void *alloc_ctxs[]) | ||
270 | { | ||
271 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); | ||
272 | |||
273 | if (*nbuffers < BCAP_MIN_NUM_BUF) | ||
274 | *nbuffers = BCAP_MIN_NUM_BUF; | ||
275 | |||
276 | *nplanes = 1; | ||
277 | sizes[0] = bcap_dev->fmt.sizeimage; | ||
278 | alloc_ctxs[0] = bcap_dev->alloc_ctx; | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static int bcap_buffer_init(struct vb2_buffer *vb) | ||
284 | { | ||
285 | struct bcap_buffer *buf = to_bcap_vb(vb); | ||
286 | |||
287 | INIT_LIST_HEAD(&buf->list); | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int bcap_buffer_prepare(struct vb2_buffer *vb) | ||
292 | { | ||
293 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); | ||
294 | struct bcap_buffer *buf = to_bcap_vb(vb); | ||
295 | unsigned long size; | ||
296 | |||
297 | size = bcap_dev->fmt.sizeimage; | ||
298 | if (vb2_plane_size(vb, 0) < size) { | ||
299 | v4l2_err(&bcap_dev->v4l2_dev, "buffer too small (%lu < %lu)\n", | ||
300 | vb2_plane_size(vb, 0), size); | ||
301 | return -EINVAL; | ||
302 | } | ||
303 | vb2_set_plane_payload(&buf->vb, 0, size); | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static void bcap_buffer_queue(struct vb2_buffer *vb) | ||
309 | { | ||
310 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); | ||
311 | struct bcap_buffer *buf = to_bcap_vb(vb); | ||
312 | unsigned long flags; | ||
313 | |||
314 | spin_lock_irqsave(&bcap_dev->lock, flags); | ||
315 | list_add_tail(&buf->list, &bcap_dev->dma_queue); | ||
316 | spin_unlock_irqrestore(&bcap_dev->lock, flags); | ||
317 | } | ||
318 | |||
319 | static void bcap_buffer_cleanup(struct vb2_buffer *vb) | ||
320 | { | ||
321 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); | ||
322 | struct bcap_buffer *buf = to_bcap_vb(vb); | ||
323 | unsigned long flags; | ||
324 | |||
325 | spin_lock_irqsave(&bcap_dev->lock, flags); | ||
326 | list_del_init(&buf->list); | ||
327 | spin_unlock_irqrestore(&bcap_dev->lock, flags); | ||
328 | } | ||
329 | |||
330 | static void bcap_lock(struct vb2_queue *vq) | ||
331 | { | ||
332 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); | ||
333 | mutex_lock(&bcap_dev->mutex); | ||
334 | } | ||
335 | |||
336 | static void bcap_unlock(struct vb2_queue *vq) | ||
337 | { | ||
338 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); | ||
339 | mutex_unlock(&bcap_dev->mutex); | ||
340 | } | ||
341 | |||
342 | static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count) | ||
343 | { | ||
344 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); | ||
345 | struct ppi_if *ppi = bcap_dev->ppi; | ||
346 | struct ppi_params params; | ||
347 | int ret; | ||
348 | |||
349 | /* enable streamon on the sub device */ | ||
350 | ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 1); | ||
351 | if (ret && (ret != -ENOIOCTLCMD)) { | ||
352 | v4l2_err(&bcap_dev->v4l2_dev, "stream on failed in subdev\n"); | ||
353 | return ret; | ||
354 | } | ||
355 | |||
356 | /* set ppi params */ | ||
357 | params.width = bcap_dev->fmt.width; | ||
358 | params.height = bcap_dev->fmt.height; | ||
359 | params.bpp = bcap_dev->bpp; | ||
360 | params.ppi_control = bcap_dev->cfg->ppi_control; | ||
361 | params.int_mask = bcap_dev->cfg->int_mask; | ||
362 | params.blank_clocks = bcap_dev->cfg->blank_clocks; | ||
363 | ret = ppi->ops->set_params(ppi, ¶ms); | ||
364 | if (ret < 0) { | ||
365 | v4l2_err(&bcap_dev->v4l2_dev, | ||
366 | "Error in setting ppi params\n"); | ||
367 | return ret; | ||
368 | } | ||
369 | |||
370 | /* attach ppi DMA irq handler */ | ||
371 | ret = ppi->ops->attach_irq(ppi, bcap_isr); | ||
372 | if (ret < 0) { | ||
373 | v4l2_err(&bcap_dev->v4l2_dev, | ||
374 | "Error in attaching interrupt handler\n"); | ||
375 | return ret; | ||
376 | } | ||
377 | |||
378 | INIT_COMPLETION(bcap_dev->comp); | ||
379 | bcap_dev->stop = false; | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static int bcap_stop_streaming(struct vb2_queue *vq) | ||
384 | { | ||
385 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); | ||
386 | struct ppi_if *ppi = bcap_dev->ppi; | ||
387 | int ret; | ||
388 | |||
389 | if (!vb2_is_streaming(vq)) | ||
390 | return 0; | ||
391 | |||
392 | bcap_dev->stop = true; | ||
393 | wait_for_completion(&bcap_dev->comp); | ||
394 | ppi->ops->stop(ppi); | ||
395 | ppi->ops->detach_irq(ppi); | ||
396 | ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 0); | ||
397 | if (ret && (ret != -ENOIOCTLCMD)) | ||
398 | v4l2_err(&bcap_dev->v4l2_dev, | ||
399 | "stream off failed in subdev\n"); | ||
400 | |||
401 | /* release all active buffers */ | ||
402 | while (!list_empty(&bcap_dev->dma_queue)) { | ||
403 | bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next, | ||
404 | struct bcap_buffer, list); | ||
405 | list_del(&bcap_dev->next_frm->list); | ||
406 | vb2_buffer_done(&bcap_dev->next_frm->vb, VB2_BUF_STATE_ERROR); | ||
407 | } | ||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static struct vb2_ops bcap_video_qops = { | ||
412 | .queue_setup = bcap_queue_setup, | ||
413 | .buf_init = bcap_buffer_init, | ||
414 | .buf_prepare = bcap_buffer_prepare, | ||
415 | .buf_cleanup = bcap_buffer_cleanup, | ||
416 | .buf_queue = bcap_buffer_queue, | ||
417 | .wait_prepare = bcap_unlock, | ||
418 | .wait_finish = bcap_lock, | ||
419 | .start_streaming = bcap_start_streaming, | ||
420 | .stop_streaming = bcap_stop_streaming, | ||
421 | }; | ||
422 | |||
423 | static int bcap_reqbufs(struct file *file, void *priv, | ||
424 | struct v4l2_requestbuffers *req_buf) | ||
425 | { | ||
426 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
427 | struct vb2_queue *vq = &bcap_dev->buffer_queue; | ||
428 | struct v4l2_fh *fh = file->private_data; | ||
429 | struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); | ||
430 | |||
431 | if (vb2_is_busy(vq)) | ||
432 | return -EBUSY; | ||
433 | |||
434 | bcap_fh->io_allowed = true; | ||
435 | |||
436 | return vb2_reqbufs(vq, req_buf); | ||
437 | } | ||
438 | |||
439 | static int bcap_querybuf(struct file *file, void *priv, | ||
440 | struct v4l2_buffer *buf) | ||
441 | { | ||
442 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
443 | |||
444 | return vb2_querybuf(&bcap_dev->buffer_queue, buf); | ||
445 | } | ||
446 | |||
447 | static int bcap_qbuf(struct file *file, void *priv, | ||
448 | struct v4l2_buffer *buf) | ||
449 | { | ||
450 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
451 | struct v4l2_fh *fh = file->private_data; | ||
452 | struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); | ||
453 | |||
454 | if (!bcap_fh->io_allowed) | ||
455 | return -EBUSY; | ||
456 | |||
457 | return vb2_qbuf(&bcap_dev->buffer_queue, buf); | ||
458 | } | ||
459 | |||
460 | static int bcap_dqbuf(struct file *file, void *priv, | ||
461 | struct v4l2_buffer *buf) | ||
462 | { | ||
463 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
464 | struct v4l2_fh *fh = file->private_data; | ||
465 | struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); | ||
466 | |||
467 | if (!bcap_fh->io_allowed) | ||
468 | return -EBUSY; | ||
469 | |||
470 | return vb2_dqbuf(&bcap_dev->buffer_queue, | ||
471 | buf, file->f_flags & O_NONBLOCK); | ||
472 | } | ||
473 | |||
474 | static irqreturn_t bcap_isr(int irq, void *dev_id) | ||
475 | { | ||
476 | struct ppi_if *ppi = dev_id; | ||
477 | struct bcap_device *bcap_dev = ppi->priv; | ||
478 | struct timeval timevalue; | ||
479 | struct vb2_buffer *vb = &bcap_dev->cur_frm->vb; | ||
480 | dma_addr_t addr; | ||
481 | |||
482 | spin_lock(&bcap_dev->lock); | ||
483 | |||
484 | if (bcap_dev->cur_frm != bcap_dev->next_frm) { | ||
485 | do_gettimeofday(&timevalue); | ||
486 | vb->v4l2_buf.timestamp = timevalue; | ||
487 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); | ||
488 | bcap_dev->cur_frm = bcap_dev->next_frm; | ||
489 | } | ||
490 | |||
491 | ppi->ops->stop(ppi); | ||
492 | |||
493 | if (bcap_dev->stop) { | ||
494 | complete(&bcap_dev->comp); | ||
495 | } else { | ||
496 | if (!list_empty(&bcap_dev->dma_queue)) { | ||
497 | bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next, | ||
498 | struct bcap_buffer, list); | ||
499 | list_del(&bcap_dev->next_frm->list); | ||
500 | addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->next_frm->vb, 0); | ||
501 | ppi->ops->update_addr(ppi, (unsigned long)addr); | ||
502 | } | ||
503 | ppi->ops->start(ppi); | ||
504 | } | ||
505 | |||
506 | spin_unlock(&bcap_dev->lock); | ||
507 | |||
508 | return IRQ_HANDLED; | ||
509 | } | ||
510 | |||
511 | static int bcap_streamon(struct file *file, void *priv, | ||
512 | enum v4l2_buf_type buf_type) | ||
513 | { | ||
514 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
515 | struct bcap_fh *fh = file->private_data; | ||
516 | struct ppi_if *ppi = bcap_dev->ppi; | ||
517 | dma_addr_t addr; | ||
518 | int ret; | ||
519 | |||
520 | if (!fh->io_allowed) | ||
521 | return -EBUSY; | ||
522 | |||
523 | /* call streamon to start streaming in videobuf */ | ||
524 | ret = vb2_streamon(&bcap_dev->buffer_queue, buf_type); | ||
525 | if (ret) | ||
526 | return ret; | ||
527 | |||
528 | /* if dma queue is empty, return error */ | ||
529 | if (list_empty(&bcap_dev->dma_queue)) { | ||
530 | v4l2_err(&bcap_dev->v4l2_dev, "dma queue is empty\n"); | ||
531 | ret = -EINVAL; | ||
532 | goto err; | ||
533 | } | ||
534 | |||
535 | /* get the next frame from the dma queue */ | ||
536 | bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next, | ||
537 | struct bcap_buffer, list); | ||
538 | bcap_dev->cur_frm = bcap_dev->next_frm; | ||
539 | /* remove buffer from the dma queue */ | ||
540 | list_del(&bcap_dev->cur_frm->list); | ||
541 | addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0); | ||
542 | /* update DMA address */ | ||
543 | ppi->ops->update_addr(ppi, (unsigned long)addr); | ||
544 | /* enable ppi */ | ||
545 | ppi->ops->start(ppi); | ||
546 | |||
547 | return 0; | ||
548 | err: | ||
549 | vb2_streamoff(&bcap_dev->buffer_queue, buf_type); | ||
550 | return ret; | ||
551 | } | ||
552 | |||
553 | static int bcap_streamoff(struct file *file, void *priv, | ||
554 | enum v4l2_buf_type buf_type) | ||
555 | { | ||
556 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
557 | struct bcap_fh *fh = file->private_data; | ||
558 | |||
559 | if (!fh->io_allowed) | ||
560 | return -EBUSY; | ||
561 | |||
562 | return vb2_streamoff(&bcap_dev->buffer_queue, buf_type); | ||
563 | } | ||
564 | |||
565 | static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std) | ||
566 | { | ||
567 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
568 | |||
569 | return v4l2_subdev_call(bcap_dev->sd, video, querystd, std); | ||
570 | } | ||
571 | |||
572 | static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std) | ||
573 | { | ||
574 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
575 | |||
576 | *std = bcap_dev->std; | ||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | static int bcap_s_std(struct file *file, void *priv, v4l2_std_id *std) | ||
581 | { | ||
582 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
583 | int ret; | ||
584 | |||
585 | if (vb2_is_busy(&bcap_dev->buffer_queue)) | ||
586 | return -EBUSY; | ||
587 | |||
588 | ret = v4l2_subdev_call(bcap_dev->sd, core, s_std, *std); | ||
589 | if (ret < 0) | ||
590 | return ret; | ||
591 | |||
592 | bcap_dev->std = *std; | ||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | static int bcap_enum_input(struct file *file, void *priv, | ||
597 | struct v4l2_input *input) | ||
598 | { | ||
599 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
600 | struct bfin_capture_config *config = bcap_dev->cfg; | ||
601 | int ret; | ||
602 | u32 status; | ||
603 | |||
604 | if (input->index >= config->num_inputs) | ||
605 | return -EINVAL; | ||
606 | |||
607 | *input = config->inputs[input->index]; | ||
608 | /* get input status */ | ||
609 | ret = v4l2_subdev_call(bcap_dev->sd, video, g_input_status, &status); | ||
610 | if (!ret) | ||
611 | input->status = status; | ||
612 | return 0; | ||
613 | } | ||
614 | |||
615 | static int bcap_g_input(struct file *file, void *priv, unsigned int *index) | ||
616 | { | ||
617 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
618 | |||
619 | *index = bcap_dev->cur_input; | ||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | static int bcap_s_input(struct file *file, void *priv, unsigned int index) | ||
624 | { | ||
625 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
626 | struct bfin_capture_config *config = bcap_dev->cfg; | ||
627 | struct bcap_route *route; | ||
628 | int ret; | ||
629 | |||
630 | if (vb2_is_busy(&bcap_dev->buffer_queue)) | ||
631 | return -EBUSY; | ||
632 | |||
633 | if (index >= config->num_inputs) | ||
634 | return -EINVAL; | ||
635 | |||
636 | route = &config->routes[index]; | ||
637 | ret = v4l2_subdev_call(bcap_dev->sd, video, s_routing, | ||
638 | route->input, route->output, 0); | ||
639 | if ((ret < 0) && (ret != -ENOIOCTLCMD)) { | ||
640 | v4l2_err(&bcap_dev->v4l2_dev, "Failed to set input\n"); | ||
641 | return ret; | ||
642 | } | ||
643 | bcap_dev->cur_input = index; | ||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static int bcap_try_format(struct bcap_device *bcap, | ||
648 | struct v4l2_pix_format *pixfmt, | ||
649 | enum v4l2_mbus_pixelcode *mbus_code, | ||
650 | int *bpp) | ||
651 | { | ||
652 | struct bcap_format *sf = bcap->sensor_formats; | ||
653 | struct bcap_format *fmt = NULL; | ||
654 | struct v4l2_mbus_framefmt mbus_fmt; | ||
655 | int ret, i; | ||
656 | |||
657 | for (i = 0; i < bcap->num_sensor_formats; i++) { | ||
658 | fmt = &sf[i]; | ||
659 | if (pixfmt->pixelformat == fmt->pixelformat) | ||
660 | break; | ||
661 | } | ||
662 | if (i == bcap->num_sensor_formats) | ||
663 | fmt = &sf[0]; | ||
664 | |||
665 | if (mbus_code) | ||
666 | *mbus_code = fmt->mbus_code; | ||
667 | if (bpp) | ||
668 | *bpp = fmt->bpp; | ||
669 | v4l2_fill_mbus_format(&mbus_fmt, pixfmt, fmt->mbus_code); | ||
670 | ret = v4l2_subdev_call(bcap->sd, video, | ||
671 | try_mbus_fmt, &mbus_fmt); | ||
672 | if (ret < 0) | ||
673 | return ret; | ||
674 | v4l2_fill_pix_format(pixfmt, &mbus_fmt); | ||
675 | pixfmt->bytesperline = pixfmt->width * fmt->bpp / 8; | ||
676 | pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; | ||
677 | return 0; | ||
678 | } | ||
679 | |||
680 | static int bcap_enum_fmt_vid_cap(struct file *file, void *priv, | ||
681 | struct v4l2_fmtdesc *fmt) | ||
682 | { | ||
683 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
684 | struct bcap_format *sf = bcap_dev->sensor_formats; | ||
685 | |||
686 | if (fmt->index >= bcap_dev->num_sensor_formats) | ||
687 | return -EINVAL; | ||
688 | |||
689 | fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
690 | strlcpy(fmt->description, | ||
691 | sf[fmt->index].desc, | ||
692 | sizeof(fmt->description)); | ||
693 | fmt->pixelformat = sf[fmt->index].pixelformat; | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | static int bcap_try_fmt_vid_cap(struct file *file, void *priv, | ||
698 | struct v4l2_format *fmt) | ||
699 | { | ||
700 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
701 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | ||
702 | |||
703 | return bcap_try_format(bcap_dev, pixfmt, NULL, NULL); | ||
704 | } | ||
705 | |||
706 | static int bcap_g_fmt_vid_cap(struct file *file, void *priv, | ||
707 | struct v4l2_format *fmt) | ||
708 | { | ||
709 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
710 | |||
711 | fmt->fmt.pix = bcap_dev->fmt; | ||
712 | return 0; | ||
713 | } | ||
714 | |||
715 | static int bcap_s_fmt_vid_cap(struct file *file, void *priv, | ||
716 | struct v4l2_format *fmt) | ||
717 | { | ||
718 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
719 | struct v4l2_mbus_framefmt mbus_fmt; | ||
720 | enum v4l2_mbus_pixelcode mbus_code; | ||
721 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | ||
722 | int ret, bpp; | ||
723 | |||
724 | if (vb2_is_busy(&bcap_dev->buffer_queue)) | ||
725 | return -EBUSY; | ||
726 | |||
727 | /* see if format works */ | ||
728 | ret = bcap_try_format(bcap_dev, pixfmt, &mbus_code, &bpp); | ||
729 | if (ret < 0) | ||
730 | return ret; | ||
731 | |||
732 | v4l2_fill_mbus_format(&mbus_fmt, pixfmt, mbus_code); | ||
733 | ret = v4l2_subdev_call(bcap_dev->sd, video, s_mbus_fmt, &mbus_fmt); | ||
734 | if (ret < 0) | ||
735 | return ret; | ||
736 | bcap_dev->fmt = *pixfmt; | ||
737 | bcap_dev->bpp = bpp; | ||
738 | return 0; | ||
739 | } | ||
740 | |||
741 | static int bcap_querycap(struct file *file, void *priv, | ||
742 | struct v4l2_capability *cap) | ||
743 | { | ||
744 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
745 | |||
746 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
747 | strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); | ||
748 | strlcpy(cap->bus_info, "Blackfin Platform", sizeof(cap->bus_info)); | ||
749 | strlcpy(cap->card, bcap_dev->cfg->card_name, sizeof(cap->card)); | ||
750 | return 0; | ||
751 | } | ||
752 | |||
753 | static int bcap_g_parm(struct file *file, void *fh, | ||
754 | struct v4l2_streamparm *a) | ||
755 | { | ||
756 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
757 | |||
758 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
759 | return -EINVAL; | ||
760 | return v4l2_subdev_call(bcap_dev->sd, video, g_parm, a); | ||
761 | } | ||
762 | |||
763 | static int bcap_s_parm(struct file *file, void *fh, | ||
764 | struct v4l2_streamparm *a) | ||
765 | { | ||
766 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
767 | |||
768 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
769 | return -EINVAL; | ||
770 | return v4l2_subdev_call(bcap_dev->sd, video, s_parm, a); | ||
771 | } | ||
772 | |||
773 | static int bcap_g_chip_ident(struct file *file, void *priv, | ||
774 | struct v4l2_dbg_chip_ident *chip) | ||
775 | { | ||
776 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
777 | |||
778 | chip->ident = V4L2_IDENT_NONE; | ||
779 | chip->revision = 0; | ||
780 | if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && | ||
781 | chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) | ||
782 | return -EINVAL; | ||
783 | |||
784 | return v4l2_subdev_call(bcap_dev->sd, core, | ||
785 | g_chip_ident, chip); | ||
786 | } | ||
787 | |||
788 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
789 | static int bcap_dbg_g_register(struct file *file, void *priv, | ||
790 | struct v4l2_dbg_register *reg) | ||
791 | { | ||
792 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
793 | |||
794 | return v4l2_subdev_call(bcap_dev->sd, core, | ||
795 | g_register, reg); | ||
796 | } | ||
797 | |||
798 | static int bcap_dbg_s_register(struct file *file, void *priv, | ||
799 | struct v4l2_dbg_register *reg) | ||
800 | { | ||
801 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
802 | |||
803 | return v4l2_subdev_call(bcap_dev->sd, core, | ||
804 | s_register, reg); | ||
805 | } | ||
806 | #endif | ||
807 | |||
808 | static int bcap_log_status(struct file *file, void *priv) | ||
809 | { | ||
810 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
811 | /* status for sub devices */ | ||
812 | v4l2_device_call_all(&bcap_dev->v4l2_dev, 0, core, log_status); | ||
813 | return 0; | ||
814 | } | ||
815 | |||
816 | static const struct v4l2_ioctl_ops bcap_ioctl_ops = { | ||
817 | .vidioc_querycap = bcap_querycap, | ||
818 | .vidioc_g_fmt_vid_cap = bcap_g_fmt_vid_cap, | ||
819 | .vidioc_enum_fmt_vid_cap = bcap_enum_fmt_vid_cap, | ||
820 | .vidioc_s_fmt_vid_cap = bcap_s_fmt_vid_cap, | ||
821 | .vidioc_try_fmt_vid_cap = bcap_try_fmt_vid_cap, | ||
822 | .vidioc_enum_input = bcap_enum_input, | ||
823 | .vidioc_g_input = bcap_g_input, | ||
824 | .vidioc_s_input = bcap_s_input, | ||
825 | .vidioc_querystd = bcap_querystd, | ||
826 | .vidioc_s_std = bcap_s_std, | ||
827 | .vidioc_g_std = bcap_g_std, | ||
828 | .vidioc_reqbufs = bcap_reqbufs, | ||
829 | .vidioc_querybuf = bcap_querybuf, | ||
830 | .vidioc_qbuf = bcap_qbuf, | ||
831 | .vidioc_dqbuf = bcap_dqbuf, | ||
832 | .vidioc_streamon = bcap_streamon, | ||
833 | .vidioc_streamoff = bcap_streamoff, | ||
834 | .vidioc_g_parm = bcap_g_parm, | ||
835 | .vidioc_s_parm = bcap_s_parm, | ||
836 | .vidioc_g_chip_ident = bcap_g_chip_ident, | ||
837 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
838 | .vidioc_g_register = bcap_dbg_g_register, | ||
839 | .vidioc_s_register = bcap_dbg_s_register, | ||
840 | #endif | ||
841 | .vidioc_log_status = bcap_log_status, | ||
842 | }; | ||
843 | |||
844 | static struct v4l2_file_operations bcap_fops = { | ||
845 | .owner = THIS_MODULE, | ||
846 | .open = bcap_open, | ||
847 | .release = bcap_release, | ||
848 | .unlocked_ioctl = video_ioctl2, | ||
849 | .mmap = bcap_mmap, | ||
850 | #ifndef CONFIG_MMU | ||
851 | .get_unmapped_area = bcap_get_unmapped_area, | ||
852 | #endif | ||
853 | .poll = bcap_poll | ||
854 | }; | ||
855 | |||
856 | static int __devinit bcap_probe(struct platform_device *pdev) | ||
857 | { | ||
858 | struct bcap_device *bcap_dev; | ||
859 | struct video_device *vfd; | ||
860 | struct i2c_adapter *i2c_adap; | ||
861 | struct bfin_capture_config *config; | ||
862 | struct vb2_queue *q; | ||
863 | int ret; | ||
864 | |||
865 | config = pdev->dev.platform_data; | ||
866 | if (!config) { | ||
867 | v4l2_err(pdev->dev.driver, "Unable to get board config\n"); | ||
868 | return -ENODEV; | ||
869 | } | ||
870 | |||
871 | bcap_dev = kzalloc(sizeof(*bcap_dev), GFP_KERNEL); | ||
872 | if (!bcap_dev) { | ||
873 | v4l2_err(pdev->dev.driver, "Unable to alloc bcap_dev\n"); | ||
874 | return -ENOMEM; | ||
875 | } | ||
876 | |||
877 | bcap_dev->cfg = config; | ||
878 | |||
879 | bcap_dev->ppi = ppi_create_instance(config->ppi_info); | ||
880 | if (!bcap_dev->ppi) { | ||
881 | v4l2_err(pdev->dev.driver, "Unable to create ppi\n"); | ||
882 | ret = -ENODEV; | ||
883 | goto err_free_dev; | ||
884 | } | ||
885 | bcap_dev->ppi->priv = bcap_dev; | ||
886 | |||
887 | bcap_dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | ||
888 | if (IS_ERR(bcap_dev->alloc_ctx)) { | ||
889 | ret = PTR_ERR(bcap_dev->alloc_ctx); | ||
890 | goto err_free_ppi; | ||
891 | } | ||
892 | |||
893 | vfd = video_device_alloc(); | ||
894 | if (!vfd) { | ||
895 | ret = -ENOMEM; | ||
896 | v4l2_err(pdev->dev.driver, "Unable to alloc video device\n"); | ||
897 | goto err_cleanup_ctx; | ||
898 | } | ||
899 | |||
900 | /* initialize field of video device */ | ||
901 | vfd->release = video_device_release; | ||
902 | vfd->fops = &bcap_fops; | ||
903 | vfd->ioctl_ops = &bcap_ioctl_ops; | ||
904 | vfd->tvnorms = 0; | ||
905 | vfd->v4l2_dev = &bcap_dev->v4l2_dev; | ||
906 | set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); | ||
907 | strncpy(vfd->name, CAPTURE_DRV_NAME, sizeof(vfd->name)); | ||
908 | bcap_dev->video_dev = vfd; | ||
909 | |||
910 | ret = v4l2_device_register(&pdev->dev, &bcap_dev->v4l2_dev); | ||
911 | if (ret) { | ||
912 | v4l2_err(pdev->dev.driver, | ||
913 | "Unable to register v4l2 device\n"); | ||
914 | goto err_release_vdev; | ||
915 | } | ||
916 | v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n"); | ||
917 | |||
918 | bcap_dev->v4l2_dev.ctrl_handler = &bcap_dev->ctrl_handler; | ||
919 | ret = v4l2_ctrl_handler_init(&bcap_dev->ctrl_handler, 0); | ||
920 | if (ret) { | ||
921 | v4l2_err(&bcap_dev->v4l2_dev, | ||
922 | "Unable to init control handler\n"); | ||
923 | goto err_unreg_v4l2; | ||
924 | } | ||
925 | |||
926 | spin_lock_init(&bcap_dev->lock); | ||
927 | /* initialize queue */ | ||
928 | q = &bcap_dev->buffer_queue; | ||
929 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
930 | q->io_modes = VB2_MMAP; | ||
931 | q->drv_priv = bcap_dev; | ||
932 | q->buf_struct_size = sizeof(struct bcap_buffer); | ||
933 | q->ops = &bcap_video_qops; | ||
934 | q->mem_ops = &vb2_dma_contig_memops; | ||
935 | |||
936 | vb2_queue_init(q); | ||
937 | |||
938 | mutex_init(&bcap_dev->mutex); | ||
939 | init_completion(&bcap_dev->comp); | ||
940 | |||
941 | /* init video dma queues */ | ||
942 | INIT_LIST_HEAD(&bcap_dev->dma_queue); | ||
943 | |||
944 | vfd->lock = &bcap_dev->mutex; | ||
945 | |||
946 | /* register video device */ | ||
947 | ret = video_register_device(bcap_dev->video_dev, VFL_TYPE_GRABBER, -1); | ||
948 | if (ret) { | ||
949 | v4l2_err(&bcap_dev->v4l2_dev, | ||
950 | "Unable to register video device\n"); | ||
951 | goto err_free_handler; | ||
952 | } | ||
953 | video_set_drvdata(bcap_dev->video_dev, bcap_dev); | ||
954 | v4l2_info(&bcap_dev->v4l2_dev, "video device registered as: %s\n", | ||
955 | video_device_node_name(vfd)); | ||
956 | |||
957 | /* load up the subdevice */ | ||
958 | i2c_adap = i2c_get_adapter(config->i2c_adapter_id); | ||
959 | if (!i2c_adap) { | ||
960 | v4l2_err(&bcap_dev->v4l2_dev, | ||
961 | "Unable to find i2c adapter\n"); | ||
962 | goto err_unreg_vdev; | ||
963 | |||
964 | } | ||
965 | bcap_dev->sd = v4l2_i2c_new_subdev_board(&bcap_dev->v4l2_dev, | ||
966 | i2c_adap, | ||
967 | &config->board_info, | ||
968 | NULL); | ||
969 | if (bcap_dev->sd) { | ||
970 | int i; | ||
971 | /* update tvnorms from the sub devices */ | ||
972 | for (i = 0; i < config->num_inputs; i++) | ||
973 | vfd->tvnorms |= config->inputs[i].std; | ||
974 | } else { | ||
975 | v4l2_err(&bcap_dev->v4l2_dev, | ||
976 | "Unable to register sub device\n"); | ||
977 | goto err_unreg_vdev; | ||
978 | } | ||
979 | |||
980 | v4l2_info(&bcap_dev->v4l2_dev, "v4l2 sub device registered\n"); | ||
981 | |||
982 | /* now we can probe the default state */ | ||
983 | if (vfd->tvnorms) { | ||
984 | v4l2_std_id std; | ||
985 | ret = v4l2_subdev_call(bcap_dev->sd, core, g_std, &std); | ||
986 | if (ret) { | ||
987 | v4l2_err(&bcap_dev->v4l2_dev, | ||
988 | "Unable to get std\n"); | ||
989 | goto err_unreg_vdev; | ||
990 | } | ||
991 | bcap_dev->std = std; | ||
992 | } | ||
993 | ret = bcap_init_sensor_formats(bcap_dev); | ||
994 | if (ret) { | ||
995 | v4l2_err(&bcap_dev->v4l2_dev, | ||
996 | "Unable to create sensor formats table\n"); | ||
997 | goto err_unreg_vdev; | ||
998 | } | ||
999 | return 0; | ||
1000 | err_unreg_vdev: | ||
1001 | video_unregister_device(bcap_dev->video_dev); | ||
1002 | bcap_dev->video_dev = NULL; | ||
1003 | err_free_handler: | ||
1004 | v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); | ||
1005 | err_unreg_v4l2: | ||
1006 | v4l2_device_unregister(&bcap_dev->v4l2_dev); | ||
1007 | err_release_vdev: | ||
1008 | if (bcap_dev->video_dev) | ||
1009 | video_device_release(bcap_dev->video_dev); | ||
1010 | err_cleanup_ctx: | ||
1011 | vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); | ||
1012 | err_free_ppi: | ||
1013 | ppi_delete_instance(bcap_dev->ppi); | ||
1014 | err_free_dev: | ||
1015 | kfree(bcap_dev); | ||
1016 | return ret; | ||
1017 | } | ||
1018 | |||
1019 | static int __devexit bcap_remove(struct platform_device *pdev) | ||
1020 | { | ||
1021 | struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); | ||
1022 | struct bcap_device *bcap_dev = container_of(v4l2_dev, | ||
1023 | struct bcap_device, v4l2_dev); | ||
1024 | |||
1025 | bcap_free_sensor_formats(bcap_dev); | ||
1026 | video_unregister_device(bcap_dev->video_dev); | ||
1027 | v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); | ||
1028 | v4l2_device_unregister(v4l2_dev); | ||
1029 | vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); | ||
1030 | ppi_delete_instance(bcap_dev->ppi); | ||
1031 | kfree(bcap_dev); | ||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
1035 | static struct platform_driver bcap_driver = { | ||
1036 | .driver = { | ||
1037 | .name = CAPTURE_DRV_NAME, | ||
1038 | .owner = THIS_MODULE, | ||
1039 | }, | ||
1040 | .probe = bcap_probe, | ||
1041 | .remove = __devexit_p(bcap_remove), | ||
1042 | }; | ||
1043 | |||
1044 | static __init int bcap_init(void) | ||
1045 | { | ||
1046 | return platform_driver_register(&bcap_driver); | ||
1047 | } | ||
1048 | |||
1049 | static __exit void bcap_exit(void) | ||
1050 | { | ||
1051 | platform_driver_unregister(&bcap_driver); | ||
1052 | } | ||
1053 | |||
1054 | module_init(bcap_init); | ||
1055 | module_exit(bcap_exit); | ||
1056 | |||
1057 | MODULE_DESCRIPTION("Analog Devices blackfin video capture driver"); | ||
1058 | MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); | ||
1059 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/video/blackfin/ppi.c b/drivers/media/video/blackfin/ppi.c new file mode 100644 index 000000000000..d29592186b02 --- /dev/null +++ b/drivers/media/video/blackfin/ppi.c | |||
@@ -0,0 +1,271 @@ | |||
1 | /* | ||
2 | * ppi.c Analog Devices Parallel Peripheral Interface driver | ||
3 | * | ||
4 | * Copyright (c) 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/slab.h> | ||
21 | |||
22 | #include <asm/bfin_ppi.h> | ||
23 | #include <asm/blackfin.h> | ||
24 | #include <asm/cacheflush.h> | ||
25 | #include <asm/dma.h> | ||
26 | #include <asm/portmux.h> | ||
27 | |||
28 | #include <media/blackfin/ppi.h> | ||
29 | |||
30 | static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler); | ||
31 | static void ppi_detach_irq(struct ppi_if *ppi); | ||
32 | static int ppi_start(struct ppi_if *ppi); | ||
33 | static int ppi_stop(struct ppi_if *ppi); | ||
34 | static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params); | ||
35 | static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr); | ||
36 | |||
37 | static const struct ppi_ops ppi_ops = { | ||
38 | .attach_irq = ppi_attach_irq, | ||
39 | .detach_irq = ppi_detach_irq, | ||
40 | .start = ppi_start, | ||
41 | .stop = ppi_stop, | ||
42 | .set_params = ppi_set_params, | ||
43 | .update_addr = ppi_update_addr, | ||
44 | }; | ||
45 | |||
46 | static irqreturn_t ppi_irq_err(int irq, void *dev_id) | ||
47 | { | ||
48 | struct ppi_if *ppi = dev_id; | ||
49 | const struct ppi_info *info = ppi->info; | ||
50 | |||
51 | switch (info->type) { | ||
52 | case PPI_TYPE_PPI: | ||
53 | { | ||
54 | struct bfin_ppi_regs *reg = info->base; | ||
55 | unsigned short status; | ||
56 | |||
57 | /* register on bf561 is cleared when read | ||
58 | * others are W1C | ||
59 | */ | ||
60 | status = bfin_read16(®->status); | ||
61 | bfin_write16(®->status, 0xff00); | ||
62 | break; | ||
63 | } | ||
64 | case PPI_TYPE_EPPI: | ||
65 | { | ||
66 | struct bfin_eppi_regs *reg = info->base; | ||
67 | bfin_write16(®->status, 0xffff); | ||
68 | break; | ||
69 | } | ||
70 | default: | ||
71 | break; | ||
72 | } | ||
73 | |||
74 | return IRQ_HANDLED; | ||
75 | } | ||
76 | |||
77 | static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler) | ||
78 | { | ||
79 | const struct ppi_info *info = ppi->info; | ||
80 | int ret; | ||
81 | |||
82 | ret = request_dma(info->dma_ch, "PPI_DMA"); | ||
83 | |||
84 | if (ret) { | ||
85 | pr_err("Unable to allocate DMA channel for PPI\n"); | ||
86 | return ret; | ||
87 | } | ||
88 | set_dma_callback(info->dma_ch, handler, ppi); | ||
89 | |||
90 | if (ppi->err_int) { | ||
91 | ret = request_irq(info->irq_err, ppi_irq_err, 0, "PPI ERROR", ppi); | ||
92 | if (ret) { | ||
93 | pr_err("Unable to allocate IRQ for PPI\n"); | ||
94 | free_dma(info->dma_ch); | ||
95 | } | ||
96 | } | ||
97 | return ret; | ||
98 | } | ||
99 | |||
100 | static void ppi_detach_irq(struct ppi_if *ppi) | ||
101 | { | ||
102 | const struct ppi_info *info = ppi->info; | ||
103 | |||
104 | if (ppi->err_int) | ||
105 | free_irq(info->irq_err, ppi); | ||
106 | free_dma(info->dma_ch); | ||
107 | } | ||
108 | |||
109 | static int ppi_start(struct ppi_if *ppi) | ||
110 | { | ||
111 | const struct ppi_info *info = ppi->info; | ||
112 | |||
113 | /* enable DMA */ | ||
114 | enable_dma(info->dma_ch); | ||
115 | |||
116 | /* enable PPI */ | ||
117 | ppi->ppi_control |= PORT_EN; | ||
118 | switch (info->type) { | ||
119 | case PPI_TYPE_PPI: | ||
120 | { | ||
121 | struct bfin_ppi_regs *reg = info->base; | ||
122 | bfin_write16(®->control, ppi->ppi_control); | ||
123 | break; | ||
124 | } | ||
125 | case PPI_TYPE_EPPI: | ||
126 | { | ||
127 | struct bfin_eppi_regs *reg = info->base; | ||
128 | bfin_write32(®->control, ppi->ppi_control); | ||
129 | break; | ||
130 | } | ||
131 | default: | ||
132 | return -EINVAL; | ||
133 | } | ||
134 | |||
135 | SSYNC(); | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static int ppi_stop(struct ppi_if *ppi) | ||
140 | { | ||
141 | const struct ppi_info *info = ppi->info; | ||
142 | |||
143 | /* disable PPI */ | ||
144 | ppi->ppi_control &= ~PORT_EN; | ||
145 | switch (info->type) { | ||
146 | case PPI_TYPE_PPI: | ||
147 | { | ||
148 | struct bfin_ppi_regs *reg = info->base; | ||
149 | bfin_write16(®->control, ppi->ppi_control); | ||
150 | break; | ||
151 | } | ||
152 | case PPI_TYPE_EPPI: | ||
153 | { | ||
154 | struct bfin_eppi_regs *reg = info->base; | ||
155 | bfin_write32(®->control, ppi->ppi_control); | ||
156 | break; | ||
157 | } | ||
158 | default: | ||
159 | return -EINVAL; | ||
160 | } | ||
161 | |||
162 | /* disable DMA */ | ||
163 | clear_dma_irqstat(info->dma_ch); | ||
164 | disable_dma(info->dma_ch); | ||
165 | |||
166 | SSYNC(); | ||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params) | ||
171 | { | ||
172 | const struct ppi_info *info = ppi->info; | ||
173 | int dma32 = 0; | ||
174 | int dma_config, bytes_per_line, lines_per_frame; | ||
175 | |||
176 | bytes_per_line = params->width * params->bpp / 8; | ||
177 | lines_per_frame = params->height; | ||
178 | if (params->int_mask == 0xFFFFFFFF) | ||
179 | ppi->err_int = false; | ||
180 | else | ||
181 | ppi->err_int = true; | ||
182 | |||
183 | dma_config = (DMA_FLOW_STOP | WNR | RESTART | DMA2D | DI_EN); | ||
184 | ppi->ppi_control = params->ppi_control & ~PORT_EN; | ||
185 | switch (info->type) { | ||
186 | case PPI_TYPE_PPI: | ||
187 | { | ||
188 | struct bfin_ppi_regs *reg = info->base; | ||
189 | |||
190 | if (params->ppi_control & DMA32) | ||
191 | dma32 = 1; | ||
192 | |||
193 | bfin_write16(®->control, ppi->ppi_control); | ||
194 | bfin_write16(®->count, bytes_per_line - 1); | ||
195 | bfin_write16(®->frame, lines_per_frame); | ||
196 | break; | ||
197 | } | ||
198 | case PPI_TYPE_EPPI: | ||
199 | { | ||
200 | struct bfin_eppi_regs *reg = info->base; | ||
201 | |||
202 | if ((params->ppi_control & PACK_EN) | ||
203 | || (params->ppi_control & 0x38000) > DLEN_16) | ||
204 | dma32 = 1; | ||
205 | |||
206 | bfin_write32(®->control, ppi->ppi_control); | ||
207 | bfin_write16(®->line, bytes_per_line + params->blank_clocks); | ||
208 | bfin_write16(®->frame, lines_per_frame); | ||
209 | bfin_write16(®->hdelay, 0); | ||
210 | bfin_write16(®->vdelay, 0); | ||
211 | bfin_write16(®->hcount, bytes_per_line); | ||
212 | bfin_write16(®->vcount, lines_per_frame); | ||
213 | break; | ||
214 | } | ||
215 | default: | ||
216 | return -EINVAL; | ||
217 | } | ||
218 | |||
219 | if (dma32) { | ||
220 | dma_config |= WDSIZE_32; | ||
221 | set_dma_x_count(info->dma_ch, bytes_per_line >> 2); | ||
222 | set_dma_x_modify(info->dma_ch, 4); | ||
223 | set_dma_y_modify(info->dma_ch, 4); | ||
224 | } else { | ||
225 | dma_config |= WDSIZE_16; | ||
226 | set_dma_x_count(info->dma_ch, bytes_per_line >> 1); | ||
227 | set_dma_x_modify(info->dma_ch, 2); | ||
228 | set_dma_y_modify(info->dma_ch, 2); | ||
229 | } | ||
230 | set_dma_y_count(info->dma_ch, lines_per_frame); | ||
231 | set_dma_config(info->dma_ch, dma_config); | ||
232 | |||
233 | SSYNC(); | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr) | ||
238 | { | ||
239 | set_dma_start_addr(ppi->info->dma_ch, addr); | ||
240 | } | ||
241 | |||
242 | struct ppi_if *ppi_create_instance(const struct ppi_info *info) | ||
243 | { | ||
244 | struct ppi_if *ppi; | ||
245 | |||
246 | if (!info || !info->pin_req) | ||
247 | return NULL; | ||
248 | |||
249 | if (peripheral_request_list(info->pin_req, KBUILD_MODNAME)) { | ||
250 | pr_err("request peripheral failed\n"); | ||
251 | return NULL; | ||
252 | } | ||
253 | |||
254 | ppi = kzalloc(sizeof(*ppi), GFP_KERNEL); | ||
255 | if (!ppi) { | ||
256 | peripheral_free_list(info->pin_req); | ||
257 | pr_err("unable to allocate memory for ppi handle\n"); | ||
258 | return NULL; | ||
259 | } | ||
260 | ppi->ops = &ppi_ops; | ||
261 | ppi->info = info; | ||
262 | |||
263 | pr_info("ppi probe success\n"); | ||
264 | return ppi; | ||
265 | } | ||
266 | |||
267 | void ppi_delete_instance(struct ppi_if *ppi) | ||
268 | { | ||
269 | peripheral_free_list(ppi->info->pin_req); | ||
270 | kfree(ppi); | ||
271 | } | ||