2 * timblogiw.c timberdale FPGA LogiWin Video In driver
3 * Copyright (c) 2009-2010 Intel Corporation
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * Timberdale FPGA LogiWin Video In
23 #include <linux/platform_device.h>
24 #include <linux/slab.h>
25 #include <linux/dmaengine.h>
26 #include <linux/scatterlist.h>
27 #include <linux/interrupt.h>
28 #include <linux/list.h>
29 #include <linux/i2c.h>
30 #include <linux/module.h>
31 #include <media/v4l2-ioctl.h>
32 #include <media/v4l2-device.h>
33 #include <media/videobuf-dma-contig.h>
34 #include <media/timb_video.h>
36 #define DRIVER_NAME "timb-video"
38 #define TIMBLOGIWIN_NAME "Timberdale Video-In"
39 #define TIMBLOGIW_VERSION_CODE 0x04
41 #define TIMBLOGIW_LINES_PER_DESC 44
42 #define TIMBLOGIW_MAX_VIDEO_MEM 16
44 #define TIMBLOGIW_HAS_DECODER(lw) (lw->pdata.encoder.module_name)
48 struct video_device video_dev
;
49 struct v4l2_device v4l2_dev
; /* mutual exclusion */
52 struct timb_video_platform_data pdata
;
53 struct v4l2_subdev
*sd_enc
; /* encoder */
57 struct timblogiw_tvnorm
{
65 struct videobuf_queue vb_vidq
;
66 struct timblogiw_tvnorm
const *cur_norm
;
67 struct list_head capture
;
68 struct dma_chan
*chan
;
69 spinlock_t queue_lock
; /* mutual exclusion */
70 unsigned int frame_count
;
73 struct timblogiw_buffer
{
74 /* common v4l buffer stuff -- must be first */
75 struct videobuf_buffer vb
;
76 struct scatterlist sg
[16];
78 struct timblogiw_fh
*fh
;
81 static const struct timblogiw_tvnorm timblogiw_tvnorms
[] = {
96 static int timblogiw_bytes_per_line(const struct timblogiw_tvnorm
*norm
)
98 return norm
->width
* 2;
102 static int timblogiw_frame_size(const struct timblogiw_tvnorm
*norm
)
104 return norm
->height
* timblogiw_bytes_per_line(norm
);
107 static const struct timblogiw_tvnorm
*timblogiw_get_norm(const v4l2_std_id std
)
110 for (i
= 0; i
< ARRAY_SIZE(timblogiw_tvnorms
); i
++)
111 if (timblogiw_tvnorms
[i
].std
& std
)
112 return timblogiw_tvnorms
+ i
;
114 /* default to first element */
115 return timblogiw_tvnorms
;
118 static void timblogiw_dma_cb(void *data
)
120 struct timblogiw_buffer
*buf
= data
;
121 struct timblogiw_fh
*fh
= buf
->fh
;
122 struct videobuf_buffer
*vb
= &buf
->vb
;
124 spin_lock(&fh
->queue_lock
);
126 /* mark the transfer done */
131 if (vb
->state
!= VIDEOBUF_ERROR
) {
132 list_del(&vb
->queue
);
133 v4l2_get_timestamp(&vb
->ts
);
134 vb
->field_count
= fh
->frame_count
* 2;
135 vb
->state
= VIDEOBUF_DONE
;
140 if (!list_empty(&fh
->capture
)) {
141 vb
= list_entry(fh
->capture
.next
, struct videobuf_buffer
,
143 vb
->state
= VIDEOBUF_ACTIVE
;
146 spin_unlock(&fh
->queue_lock
);
149 static bool timblogiw_dma_filter_fn(struct dma_chan
*chan
, void *filter_param
)
151 return chan
->chan_id
== (uintptr_t)filter_param
;
154 /* IOCTL functions */
156 static int timblogiw_g_fmt(struct file
*file
, void *priv
,
157 struct v4l2_format
*format
)
159 struct video_device
*vdev
= video_devdata(file
);
160 struct timblogiw
*lw
= video_get_drvdata(vdev
);
161 struct timblogiw_fh
*fh
= priv
;
163 dev_dbg(&vdev
->dev
, "%s entry\n", __func__
);
165 if (format
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
168 mutex_lock(&lw
->lock
);
170 format
->fmt
.pix
.width
= fh
->cur_norm
->width
;
171 format
->fmt
.pix
.height
= fh
->cur_norm
->height
;
172 format
->fmt
.pix
.pixelformat
= V4L2_PIX_FMT_UYVY
;
173 format
->fmt
.pix
.bytesperline
= timblogiw_bytes_per_line(fh
->cur_norm
);
174 format
->fmt
.pix
.sizeimage
= timblogiw_frame_size(fh
->cur_norm
);
175 format
->fmt
.pix
.field
= V4L2_FIELD_NONE
;
177 mutex_unlock(&lw
->lock
);
182 static int timblogiw_try_fmt(struct file
*file
, void *priv
,
183 struct v4l2_format
*format
)
185 struct video_device
*vdev
= video_devdata(file
);
186 struct v4l2_pix_format
*pix
= &format
->fmt
.pix
;
189 "%s - width=%d, height=%d, pixelformat=%d, field=%d\n"
190 "bytes per line %d, size image: %d, colorspace: %d\n",
192 pix
->width
, pix
->height
, pix
->pixelformat
, pix
->field
,
193 pix
->bytesperline
, pix
->sizeimage
, pix
->colorspace
);
195 if (format
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
198 if (pix
->field
!= V4L2_FIELD_NONE
)
201 if (pix
->pixelformat
!= V4L2_PIX_FMT_UYVY
)
207 static int timblogiw_s_fmt(struct file
*file
, void *priv
,
208 struct v4l2_format
*format
)
210 struct video_device
*vdev
= video_devdata(file
);
211 struct timblogiw
*lw
= video_get_drvdata(vdev
);
212 struct timblogiw_fh
*fh
= priv
;
213 struct v4l2_pix_format
*pix
= &format
->fmt
.pix
;
216 mutex_lock(&lw
->lock
);
218 err
= timblogiw_try_fmt(file
, priv
, format
);
222 if (videobuf_queue_is_busy(&fh
->vb_vidq
)) {
223 dev_err(&vdev
->dev
, "%s queue busy\n", __func__
);
228 pix
->width
= fh
->cur_norm
->width
;
229 pix
->height
= fh
->cur_norm
->height
;
232 mutex_unlock(&lw
->lock
);
236 static int timblogiw_querycap(struct file
*file
, void *priv
,
237 struct v4l2_capability
*cap
)
239 struct video_device
*vdev
= video_devdata(file
);
241 dev_dbg(&vdev
->dev
, "%s: Entry\n", __func__
);
242 strncpy(cap
->card
, TIMBLOGIWIN_NAME
, sizeof(cap
->card
)-1);
243 strncpy(cap
->driver
, DRIVER_NAME
, sizeof(cap
->driver
) - 1);
244 snprintf(cap
->bus_info
, sizeof(cap
->bus_info
), "platform:%s", vdev
->name
);
245 cap
->device_caps
= V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_STREAMING
|
247 cap
->capabilities
= cap
->device_caps
| V4L2_CAP_DEVICE_CAPS
;
252 static int timblogiw_enum_fmt(struct file
*file
, void *priv
,
253 struct v4l2_fmtdesc
*fmt
)
255 struct video_device
*vdev
= video_devdata(file
);
257 dev_dbg(&vdev
->dev
, "%s, index: %d\n", __func__
, fmt
->index
);
261 memset(fmt
, 0, sizeof(*fmt
));
263 fmt
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
264 strncpy(fmt
->description
, "4:2:2, packed, YUYV",
265 sizeof(fmt
->description
)-1);
266 fmt
->pixelformat
= V4L2_PIX_FMT_UYVY
;
271 static int timblogiw_g_parm(struct file
*file
, void *priv
,
272 struct v4l2_streamparm
*sp
)
274 struct timblogiw_fh
*fh
= priv
;
275 struct v4l2_captureparm
*cp
= &sp
->parm
.capture
;
277 cp
->capability
= V4L2_CAP_TIMEPERFRAME
;
278 cp
->timeperframe
.numerator
= 1;
279 cp
->timeperframe
.denominator
= fh
->cur_norm
->fps
;
284 static int timblogiw_reqbufs(struct file
*file
, void *priv
,
285 struct v4l2_requestbuffers
*rb
)
287 struct video_device
*vdev
= video_devdata(file
);
288 struct timblogiw_fh
*fh
= priv
;
290 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
292 return videobuf_reqbufs(&fh
->vb_vidq
, rb
);
295 static int timblogiw_querybuf(struct file
*file
, void *priv
,
296 struct v4l2_buffer
*b
)
298 struct video_device
*vdev
= video_devdata(file
);
299 struct timblogiw_fh
*fh
= priv
;
301 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
303 return videobuf_querybuf(&fh
->vb_vidq
, b
);
306 static int timblogiw_qbuf(struct file
*file
, void *priv
, struct v4l2_buffer
*b
)
308 struct video_device
*vdev
= video_devdata(file
);
309 struct timblogiw_fh
*fh
= priv
;
311 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
313 return videobuf_qbuf(&fh
->vb_vidq
, b
);
316 static int timblogiw_dqbuf(struct file
*file
, void *priv
,
317 struct v4l2_buffer
*b
)
319 struct video_device
*vdev
= video_devdata(file
);
320 struct timblogiw_fh
*fh
= priv
;
322 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
324 return videobuf_dqbuf(&fh
->vb_vidq
, b
, file
->f_flags
& O_NONBLOCK
);
327 static int timblogiw_g_std(struct file
*file
, void *priv
, v4l2_std_id
*std
)
329 struct video_device
*vdev
= video_devdata(file
);
330 struct timblogiw_fh
*fh
= priv
;
332 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
334 *std
= fh
->cur_norm
->std
;
338 static int timblogiw_s_std(struct file
*file
, void *priv
, v4l2_std_id std
)
340 struct video_device
*vdev
= video_devdata(file
);
341 struct timblogiw
*lw
= video_get_drvdata(vdev
);
342 struct timblogiw_fh
*fh
= priv
;
345 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
347 mutex_lock(&lw
->lock
);
349 if (TIMBLOGIW_HAS_DECODER(lw
))
350 err
= v4l2_subdev_call(lw
->sd_enc
, core
, s_std
, std
);
353 fh
->cur_norm
= timblogiw_get_norm(std
);
355 mutex_unlock(&lw
->lock
);
360 static int timblogiw_enuminput(struct file
*file
, void *priv
,
361 struct v4l2_input
*inp
)
363 struct video_device
*vdev
= video_devdata(file
);
366 dev_dbg(&vdev
->dev
, "%s: Entry\n", __func__
);
373 strncpy(inp
->name
, "Timb input 1", sizeof(inp
->name
) - 1);
374 inp
->type
= V4L2_INPUT_TYPE_CAMERA
;
377 for (i
= 0; i
< ARRAY_SIZE(timblogiw_tvnorms
); i
++)
378 inp
->std
|= timblogiw_tvnorms
[i
].std
;
383 static int timblogiw_g_input(struct file
*file
, void *priv
,
386 struct video_device
*vdev
= video_devdata(file
);
388 dev_dbg(&vdev
->dev
, "%s: Entry\n", __func__
);
395 static int timblogiw_s_input(struct file
*file
, void *priv
, unsigned int input
)
397 struct video_device
*vdev
= video_devdata(file
);
399 dev_dbg(&vdev
->dev
, "%s: Entry\n", __func__
);
406 static int timblogiw_streamon(struct file
*file
, void *priv
, enum v4l2_buf_type type
)
408 struct video_device
*vdev
= video_devdata(file
);
409 struct timblogiw_fh
*fh
= priv
;
411 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
413 if (type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
414 dev_dbg(&vdev
->dev
, "%s - No capture device\n", __func__
);
419 return videobuf_streamon(&fh
->vb_vidq
);
422 static int timblogiw_streamoff(struct file
*file
, void *priv
,
423 enum v4l2_buf_type type
)
425 struct video_device
*vdev
= video_devdata(file
);
426 struct timblogiw_fh
*fh
= priv
;
428 dev_dbg(&vdev
->dev
, "%s entry\n", __func__
);
430 if (type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
433 return videobuf_streamoff(&fh
->vb_vidq
);
436 static int timblogiw_querystd(struct file
*file
, void *priv
, v4l2_std_id
*std
)
438 struct video_device
*vdev
= video_devdata(file
);
439 struct timblogiw
*lw
= video_get_drvdata(vdev
);
440 struct timblogiw_fh
*fh
= priv
;
442 dev_dbg(&vdev
->dev
, "%s entry\n", __func__
);
444 if (TIMBLOGIW_HAS_DECODER(lw
))
445 return v4l2_subdev_call(lw
->sd_enc
, video
, querystd
, std
);
447 *std
= fh
->cur_norm
->std
;
452 static int timblogiw_enum_framesizes(struct file
*file
, void *priv
,
453 struct v4l2_frmsizeenum
*fsize
)
455 struct video_device
*vdev
= video_devdata(file
);
456 struct timblogiw_fh
*fh
= priv
;
458 dev_dbg(&vdev
->dev
, "%s - index: %d, format: %d\n", __func__
,
459 fsize
->index
, fsize
->pixel_format
);
461 if ((fsize
->index
!= 0) ||
462 (fsize
->pixel_format
!= V4L2_PIX_FMT_UYVY
))
465 fsize
->type
= V4L2_FRMSIZE_TYPE_DISCRETE
;
466 fsize
->discrete
.width
= fh
->cur_norm
->width
;
467 fsize
->discrete
.height
= fh
->cur_norm
->height
;
472 /* Video buffer functions */
474 static int buffer_setup(struct videobuf_queue
*vq
, unsigned int *count
,
477 struct timblogiw_fh
*fh
= vq
->priv_data
;
479 *size
= timblogiw_frame_size(fh
->cur_norm
);
484 while (*size
* *count
> TIMBLOGIW_MAX_VIDEO_MEM
* 1024 * 1024)
490 static int buffer_prepare(struct videobuf_queue
*vq
, struct videobuf_buffer
*vb
,
491 enum v4l2_field field
)
493 struct timblogiw_fh
*fh
= vq
->priv_data
;
494 struct timblogiw_buffer
*buf
= container_of(vb
, struct timblogiw_buffer
,
496 unsigned int data_size
= timblogiw_frame_size(fh
->cur_norm
);
499 if (vb
->baddr
&& vb
->bsize
< data_size
)
500 /* User provided buffer, but it is too small */
503 vb
->size
= data_size
;
504 vb
->width
= fh
->cur_norm
->width
;
505 vb
->height
= fh
->cur_norm
->height
;
508 if (vb
->state
== VIDEOBUF_NEEDS_INIT
) {
511 unsigned int bytes_per_desc
= TIMBLOGIW_LINES_PER_DESC
*
512 timblogiw_bytes_per_line(fh
->cur_norm
);
515 sg_init_table(buf
->sg
, ARRAY_SIZE(buf
->sg
));
517 err
= videobuf_iolock(vq
, vb
, NULL
);
521 addr
= videobuf_to_dma_contig(vb
);
522 for (i
= 0, size
= 0; size
< data_size
; i
++) {
523 sg_dma_address(buf
->sg
+ i
) = addr
+ size
;
524 size
+= bytes_per_desc
;
525 sg_dma_len(buf
->sg
+ i
) = (size
> data_size
) ?
526 (bytes_per_desc
- (size
- data_size
)) :
530 vb
->state
= VIDEOBUF_PREPARED
;
538 videobuf_dma_contig_free(vq
, vb
);
539 vb
->state
= VIDEOBUF_NEEDS_INIT
;
543 static void buffer_queue(struct videobuf_queue
*vq
, struct videobuf_buffer
*vb
)
545 struct timblogiw_fh
*fh
= vq
->priv_data
;
546 struct timblogiw_buffer
*buf
= container_of(vb
, struct timblogiw_buffer
,
548 struct dma_async_tx_descriptor
*desc
;
550 int bytes_per_desc
= TIMBLOGIW_LINES_PER_DESC
*
551 timblogiw_bytes_per_line(fh
->cur_norm
);
553 sg_elems
= timblogiw_frame_size(fh
->cur_norm
) / bytes_per_desc
;
555 (timblogiw_frame_size(fh
->cur_norm
) % bytes_per_desc
) ? 1 : 0;
557 if (list_empty(&fh
->capture
))
558 vb
->state
= VIDEOBUF_ACTIVE
;
560 vb
->state
= VIDEOBUF_QUEUED
;
562 list_add_tail(&vb
->queue
, &fh
->capture
);
564 spin_unlock_irq(&fh
->queue_lock
);
566 desc
= dmaengine_prep_slave_sg(fh
->chan
,
567 buf
->sg
, sg_elems
, DMA_DEV_TO_MEM
,
570 spin_lock_irq(&fh
->queue_lock
);
571 list_del_init(&vb
->queue
);
572 vb
->state
= VIDEOBUF_PREPARED
;
576 desc
->callback_param
= buf
;
577 desc
->callback
= timblogiw_dma_cb
;
579 buf
->cookie
= desc
->tx_submit(desc
);
581 spin_lock_irq(&fh
->queue_lock
);
584 static void buffer_release(struct videobuf_queue
*vq
,
585 struct videobuf_buffer
*vb
)
587 struct timblogiw_fh
*fh
= vq
->priv_data
;
588 struct timblogiw_buffer
*buf
= container_of(vb
, struct timblogiw_buffer
,
591 videobuf_waiton(vq
, vb
, 0, 0);
592 if (buf
->cookie
>= 0)
593 dma_sync_wait(fh
->chan
, buf
->cookie
);
595 videobuf_dma_contig_free(vq
, vb
);
596 vb
->state
= VIDEOBUF_NEEDS_INIT
;
599 static struct videobuf_queue_ops timblogiw_video_qops
= {
600 .buf_setup
= buffer_setup
,
601 .buf_prepare
= buffer_prepare
,
602 .buf_queue
= buffer_queue
,
603 .buf_release
= buffer_release
,
606 /* Device Operations functions */
608 static int timblogiw_open(struct file
*file
)
610 struct video_device
*vdev
= video_devdata(file
);
611 struct timblogiw
*lw
= video_get_drvdata(vdev
);
612 struct timblogiw_fh
*fh
;
617 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
619 mutex_lock(&lw
->lock
);
625 if (TIMBLOGIW_HAS_DECODER(lw
) && !lw
->sd_enc
) {
626 struct i2c_adapter
*adapt
;
628 /* find the video decoder */
629 adapt
= i2c_get_adapter(lw
->pdata
.i2c_adapter
);
631 dev_err(&vdev
->dev
, "No I2C bus #%d\n",
632 lw
->pdata
.i2c_adapter
);
637 /* now find the encoder */
638 lw
->sd_enc
= v4l2_i2c_new_subdev_board(&lw
->v4l2_dev
, adapt
,
639 lw
->pdata
.encoder
.info
, NULL
);
641 i2c_put_adapter(adapt
);
644 dev_err(&vdev
->dev
, "Failed to get encoder: %s\n",
645 lw
->pdata
.encoder
.module_name
);
651 fh
= kzalloc(sizeof(*fh
), GFP_KERNEL
);
657 fh
->cur_norm
= timblogiw_tvnorms
;
658 timblogiw_querystd(file
, fh
, &std
);
659 fh
->cur_norm
= timblogiw_get_norm(std
);
661 INIT_LIST_HEAD(&fh
->capture
);
662 spin_lock_init(&fh
->queue_lock
);
665 dma_cap_set(DMA_SLAVE
, mask
);
666 dma_cap_set(DMA_PRIVATE
, mask
);
668 /* find the DMA channel */
669 fh
->chan
= dma_request_channel(mask
, timblogiw_dma_filter_fn
,
670 (void *)(uintptr_t)lw
->pdata
.dma_channel
);
672 dev_err(&vdev
->dev
, "Failed to get DMA channel\n");
678 file
->private_data
= fh
;
679 videobuf_queue_dma_contig_init(&fh
->vb_vidq
,
680 &timblogiw_video_qops
, lw
->dev
, &fh
->queue_lock
,
681 V4L2_BUF_TYPE_VIDEO_CAPTURE
, V4L2_FIELD_NONE
,
682 sizeof(struct timblogiw_buffer
), fh
, NULL
);
686 mutex_unlock(&lw
->lock
);
691 static int timblogiw_close(struct file
*file
)
693 struct video_device
*vdev
= video_devdata(file
);
694 struct timblogiw
*lw
= video_get_drvdata(vdev
);
695 struct timblogiw_fh
*fh
= file
->private_data
;
697 dev_dbg(&vdev
->dev
, "%s: Entry\n", __func__
);
699 videobuf_stop(&fh
->vb_vidq
);
700 videobuf_mmap_free(&fh
->vb_vidq
);
702 dma_release_channel(fh
->chan
);
706 mutex_lock(&lw
->lock
);
708 mutex_unlock(&lw
->lock
);
712 static ssize_t
timblogiw_read(struct file
*file
, char __user
*data
,
713 size_t count
, loff_t
*ppos
)
715 struct video_device
*vdev
= video_devdata(file
);
716 struct timblogiw_fh
*fh
= file
->private_data
;
718 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
720 return videobuf_read_stream(&fh
->vb_vidq
, data
, count
, ppos
, 0,
721 file
->f_flags
& O_NONBLOCK
);
724 static unsigned int timblogiw_poll(struct file
*file
,
725 struct poll_table_struct
*wait
)
727 struct video_device
*vdev
= video_devdata(file
);
728 struct timblogiw_fh
*fh
= file
->private_data
;
730 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
732 return videobuf_poll_stream(file
, &fh
->vb_vidq
, wait
);
735 static int timblogiw_mmap(struct file
*file
, struct vm_area_struct
*vma
)
737 struct video_device
*vdev
= video_devdata(file
);
738 struct timblogiw_fh
*fh
= file
->private_data
;
740 dev_dbg(&vdev
->dev
, "%s: entry\n", __func__
);
742 return videobuf_mmap_mapper(&fh
->vb_vidq
, vma
);
745 /* Platform device functions */
747 static struct v4l2_ioctl_ops timblogiw_ioctl_ops
= {
748 .vidioc_querycap
= timblogiw_querycap
,
749 .vidioc_enum_fmt_vid_cap
= timblogiw_enum_fmt
,
750 .vidioc_g_fmt_vid_cap
= timblogiw_g_fmt
,
751 .vidioc_try_fmt_vid_cap
= timblogiw_try_fmt
,
752 .vidioc_s_fmt_vid_cap
= timblogiw_s_fmt
,
753 .vidioc_g_parm
= timblogiw_g_parm
,
754 .vidioc_reqbufs
= timblogiw_reqbufs
,
755 .vidioc_querybuf
= timblogiw_querybuf
,
756 .vidioc_qbuf
= timblogiw_qbuf
,
757 .vidioc_dqbuf
= timblogiw_dqbuf
,
758 .vidioc_g_std
= timblogiw_g_std
,
759 .vidioc_s_std
= timblogiw_s_std
,
760 .vidioc_enum_input
= timblogiw_enuminput
,
761 .vidioc_g_input
= timblogiw_g_input
,
762 .vidioc_s_input
= timblogiw_s_input
,
763 .vidioc_streamon
= timblogiw_streamon
,
764 .vidioc_streamoff
= timblogiw_streamoff
,
765 .vidioc_querystd
= timblogiw_querystd
,
766 .vidioc_enum_framesizes
= timblogiw_enum_framesizes
,
769 static struct v4l2_file_operations timblogiw_fops
= {
770 .owner
= THIS_MODULE
,
771 .open
= timblogiw_open
,
772 .release
= timblogiw_close
,
773 .unlocked_ioctl
= video_ioctl2
, /* V4L2 ioctl handler */
774 .mmap
= timblogiw_mmap
,
775 .read
= timblogiw_read
,
776 .poll
= timblogiw_poll
,
779 static struct video_device timblogiw_template
= {
780 .name
= TIMBLOGIWIN_NAME
,
781 .fops
= &timblogiw_fops
,
782 .ioctl_ops
= &timblogiw_ioctl_ops
,
783 .release
= video_device_release_empty
,
785 .tvnorms
= V4L2_STD_PAL
| V4L2_STD_NTSC
788 static int timblogiw_probe(struct platform_device
*pdev
)
791 struct timblogiw
*lw
= NULL
;
792 struct timb_video_platform_data
*pdata
= pdev
->dev
.platform_data
;
795 dev_err(&pdev
->dev
, "No platform data\n");
800 if (!pdata
->encoder
.module_name
)
801 dev_info(&pdev
->dev
, "Running without decoder\n");
803 lw
= kzalloc(sizeof(*lw
), GFP_KERNEL
);
809 if (pdev
->dev
.parent
)
810 lw
->dev
= pdev
->dev
.parent
;
812 lw
->dev
= &pdev
->dev
;
814 memcpy(&lw
->pdata
, pdata
, sizeof(lw
->pdata
));
816 mutex_init(&lw
->lock
);
818 lw
->video_dev
= timblogiw_template
;
820 strlcpy(lw
->v4l2_dev
.name
, DRIVER_NAME
, sizeof(lw
->v4l2_dev
.name
));
821 err
= v4l2_device_register(NULL
, &lw
->v4l2_dev
);
825 lw
->video_dev
.v4l2_dev
= &lw
->v4l2_dev
;
827 platform_set_drvdata(pdev
, lw
);
828 video_set_drvdata(&lw
->video_dev
, lw
);
830 err
= video_register_device(&lw
->video_dev
, VFL_TYPE_GRABBER
, 0);
832 dev_err(&pdev
->dev
, "Error reg video: %d\n", err
);
839 v4l2_device_unregister(&lw
->v4l2_dev
);
843 dev_err(&pdev
->dev
, "Failed to register: %d\n", err
);
848 static int timblogiw_remove(struct platform_device
*pdev
)
850 struct timblogiw
*lw
= platform_get_drvdata(pdev
);
852 video_unregister_device(&lw
->video_dev
);
854 v4l2_device_unregister(&lw
->v4l2_dev
);
861 static struct platform_driver timblogiw_platform_driver
= {
864 .owner
= THIS_MODULE
,
866 .probe
= timblogiw_probe
,
867 .remove
= timblogiw_remove
,
870 module_platform_driver(timblogiw_platform_driver
);
872 MODULE_DESCRIPTION(TIMBLOGIWIN_NAME
);
873 MODULE_AUTHOR("Pelagicore AB <info@pelagicore.com>");
874 MODULE_LICENSE("GPL v2");
875 MODULE_ALIAS("platform:"DRIVER_NAME
);