]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - drivers/staging/media/dt3155v4l/dt3155v4l.c
[media] dt3155v4l: move vb2_queue to top-level
[mirror_ubuntu-focal-kernel.git] / drivers / staging / media / dt3155v4l / dt3155v4l.c
CommitLineData
717f4a5f
MM
1/***************************************************************************
2 * Copyright (C) 2006-2010 by Marin Mitov *
3 * mitov@issp.bas.bg *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
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 * *
717f4a5f
MM
15 ***************************************************************************/
16
99c97852 17#include <linux/module.h>
d42bffb8
MM
18#include <linux/version.h>
19#include <linux/stringify.h>
7ec21181 20#include <linux/delay.h>
d42bffb8 21#include <linux/kthread.h>
dac95cb8 22#include <linux/slab.h>
a57941c2
MM
23#include <media/v4l2-dev.h>
24#include <media/v4l2-ioctl.h>
0dcb953a 25#include <media/v4l2-common.h>
8ded351a 26#include <media/videobuf2-dma-contig.h>
d42bffb8
MM
27
28#include "dt3155v4l.h"
d42bffb8 29
d42bffb8
MM
30#define DT3155_DEVICE_ID 0x1223
31
8ded351a
MM
32#ifdef CONFIG_DT3155_STREAMING
33#define DT3155_CAPTURE_METHOD V4L2_CAP_STREAMING
34#else
35#define DT3155_CAPTURE_METHOD V4L2_CAP_READWRITE
36#endif
37
d42bffb8
MM
38/* global initializers (for all boards) */
39#ifdef CONFIG_DT3155_CCIR
40static const u8 csr2_init = VT_50HZ;
41#define DT3155_CURRENT_NORM V4L2_STD_625_50
42static const unsigned int img_width = 768;
43static const unsigned int img_height = 576;
44static const unsigned int frames_per_sec = 25;
45static const struct v4l2_fmtdesc frame_std[] = {
46 {
47 .index = 0,
48 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
49 .flags = 0,
50 .description = "CCIR/50Hz 8 bits gray",
51 .pixelformat = V4L2_PIX_FMT_GREY,
52 },
53};
54#else
55static const u8 csr2_init = VT_60HZ;
56#define DT3155_CURRENT_NORM V4L2_STD_525_60
57static const unsigned int img_width = 640;
58static const unsigned int img_height = 480;
59static const unsigned int frames_per_sec = 30;
60static const struct v4l2_fmtdesc frame_std[] = {
61 {
62 .index = 0,
63 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
64 .flags = 0,
65 .description = "RS-170/60Hz 8 bits gray",
66 .pixelformat = V4L2_PIX_FMT_GREY,
67 },
68};
69#endif
70
71#define NUM_OF_FORMATS ARRAY_SIZE(frame_std)
72
73static u8 config_init = ACQ_MODE_EVEN;
74
75/**
76 * read_i2c_reg - reads an internal i2c register
77 *
78 * @addr: dt3155 mmio base address
79 * @index: index (internal address) of register to read
80 * @data: pointer to byte the read data will be placed in
81 *
82 * returns: zero on success or error code
83 *
84 * This function starts reading the specified (by index) register
85 * and busy waits for the process to finish. The result is placed
86 * in a byte pointed by data.
87 */
6a11087b 88static int read_i2c_reg(void __iomem *addr, u8 index, u8 *data)
d42bffb8
MM
89{
90 u32 tmp = index;
91
6a11087b 92 iowrite32((tmp << 17) | IIC_READ, addr + IIC_CSR2);
d42bffb8
MM
93 mmiowb();
94 udelay(45); /* wait at least 43 usec for NEW_CYCLE to clear */
c94a2e47
HS
95 if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
96 return -EIO; /* error: NEW_CYCLE not cleared */
d42bffb8
MM
97 tmp = ioread32(addr + IIC_CSR1);
98 if (tmp & DIRECT_ABORT) {
d42bffb8
MM
99 /* reset DIRECT_ABORT bit */
100 iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
c94a2e47 101 return -EIO; /* error: DIRECT_ABORT set */
d42bffb8 102 }
6a11087b 103 *data = tmp >> 24;
d42bffb8
MM
104 return 0;
105}
106
107/**
108 * write_i2c_reg - writes to an internal i2c register
109 *
110 * @addr: dt3155 mmio base address
111 * @index: index (internal address) of register to read
112 * @data: data to be written
113 *
114 * returns: zero on success or error code
115 *
6a11087b 116 * This function starts writing the specified (by index) register
d42bffb8
MM
117 * and busy waits for the process to finish.
118 */
6a11087b 119static int write_i2c_reg(void __iomem *addr, u8 index, u8 data)
d42bffb8
MM
120{
121 u32 tmp = index;
122
6a11087b 123 iowrite32((tmp << 17) | IIC_WRITE | data, addr + IIC_CSR2);
d42bffb8
MM
124 mmiowb();
125 udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */
c94a2e47
HS
126 if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
127 return -EIO; /* error: NEW_CYCLE not cleared */
d42bffb8 128 if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) {
d42bffb8
MM
129 /* reset DIRECT_ABORT bit */
130 iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
c94a2e47 131 return -EIO; /* error: DIRECT_ABORT set */
d42bffb8
MM
132 }
133 return 0;
134}
135
136/**
137 * write_i2c_reg_nowait - writes to an internal i2c register
138 *
139 * @addr: dt3155 mmio base address
140 * @index: index (internal address) of register to read
141 * @data: data to be written
142 *
6a11087b 143 * This function starts writing the specified (by index) register
d42bffb8
MM
144 * and then returns.
145 */
2342df0e 146static void write_i2c_reg_nowait(void __iomem *addr, u8 index, u8 data)
d42bffb8
MM
147{
148 u32 tmp = index;
149
6a11087b 150 iowrite32((tmp << 17) | IIC_WRITE | data, addr + IIC_CSR2);
d42bffb8
MM
151 mmiowb();
152}
153
154/**
155 * wait_i2c_reg - waits the read/write to finish
156 *
157 * @addr: dt3155 mmio base address
158 *
159 * returns: zero on success or error code
160 *
6a11087b 161 * This function waits reading/writing to finish.
d42bffb8 162 */
2342df0e 163static int wait_i2c_reg(void __iomem *addr)
d42bffb8
MM
164{
165 if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
166 udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */
c94a2e47
HS
167 if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
168 return -EIO; /* error: NEW_CYCLE not cleared */
d42bffb8 169 if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) {
d42bffb8
MM
170 /* reset DIRECT_ABORT bit */
171 iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
c94a2e47 172 return -EIO; /* error: DIRECT_ABORT set */
d42bffb8
MM
173 }
174 return 0;
175}
176
6a11087b 177static int dt3155_start_acq(struct dt3155_priv *pd)
d42bffb8 178{
8ded351a 179 struct vb2_buffer *vb = pd->curr_buf;
d42bffb8
MM
180 dma_addr_t dma_addr;
181
1f28291c 182 dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
d42bffb8 183 iowrite32(dma_addr, pd->regs + EVEN_DMA_START);
8ded351a
MM
184 iowrite32(dma_addr + img_width, pd->regs + ODD_DMA_START);
185 iowrite32(img_width, pd->regs + EVEN_DMA_STRIDE);
186 iowrite32(img_width, pd->regs + ODD_DMA_STRIDE);
d42bffb8
MM
187 /* enable interrupts, clear all irq flags */
188 iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
189 FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR);
190 iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
191 FLD_DN_ODD | FLD_DN_EVEN | CAP_CONT_EVEN | CAP_CONT_ODD,
192 pd->regs + CSR1);
193 wait_i2c_reg(pd->regs);
194 write_i2c_reg(pd->regs, CONFIG, pd->config);
195 write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE);
196 write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_DONE);
197
198 /* start the board */
199 write_i2c_reg(pd->regs, CSR2, pd->csr2 | BUSY_EVEN | BUSY_ODD);
200 return 0; /* success */
201}
202
203static int
9556be12
HV
204dt3155_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
205 unsigned int *nbuffers, unsigned int *num_planes,
527f18be
DC
206 unsigned int sizes[], void *alloc_ctxs[])
207
8ded351a 208{
9556be12
HV
209 struct dt3155_priv *pd = vb2_get_drv_priv(vq);
210 unsigned size = img_width * img_height;
8ded351a 211
9556be12
HV
212 if (vq->num_buffers + *nbuffers < 2)
213 *nbuffers = 2 - vq->num_buffers;
214 if (fmt && fmt->fmt.pix.sizeimage < size)
215 return -EINVAL;
8ded351a 216 *num_planes = 1;
9556be12
HV
217 sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size;
218 alloc_ctxs[0] = pd->alloc_ctx;
8ded351a
MM
219 return 0;
220}
221
6a11087b 222static int dt3155_buf_prepare(struct vb2_buffer *vb)
d42bffb8 223{
8ded351a 224 vb2_set_plane_payload(vb, 0, img_width * img_height);
d42bffb8
MM
225 return 0;
226}
227
6a11087b 228static void dt3155_stop_streaming(struct vb2_queue *q)
d42bffb8 229{
8ded351a
MM
230 struct dt3155_priv *pd = vb2_get_drv_priv(q);
231 struct vb2_buffer *vb;
232
233 spin_lock_irq(&pd->lock);
234 while (!list_empty(&pd->dmaq)) {
235 vb = list_first_entry(&pd->dmaq, typeof(*vb), done_entry);
236 list_del(&vb->done_entry);
237 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
238 }
239 spin_unlock_irq(&pd->lock);
240 msleep(45); /* irq hendler will stop the hardware */
9556be12
HV
241 /* disable all irqs, clear all irq flags */
242 iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD,
243 pd->regs + INT_CSR);
d42bffb8
MM
244}
245
6a11087b 246static void dt3155_buf_queue(struct vb2_buffer *vb)
d42bffb8 247{
8ded351a
MM
248 struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue);
249
250 /* pd->q->streaming = 1 when dt3155_buf_queue() is invoked */
251 spin_lock_irq(&pd->lock);
252 if (pd->curr_buf)
253 list_add_tail(&vb->done_entry, &pd->dmaq);
254 else {
255 pd->curr_buf = vb;
256 dt3155_start_acq(pd);
257 }
258 spin_unlock_irq(&pd->lock);
d42bffb8
MM
259}
260
5ae7437e 261static const struct vb2_ops q_ops = {
8ded351a 262 .queue_setup = dt3155_queue_setup,
9556be12
HV
263 .wait_prepare = vb2_ops_wait_prepare,
264 .wait_finish = vb2_ops_wait_finish,
d42bffb8 265 .buf_prepare = dt3155_buf_prepare,
8ded351a 266 .stop_streaming = dt3155_stop_streaming,
d42bffb8 267 .buf_queue = dt3155_buf_queue,
d42bffb8
MM
268};
269
6a11087b 270static irqreturn_t dt3155_irq_handler_even(int irq, void *dev_id)
d42bffb8
MM
271{
272 struct dt3155_priv *ipd = dev_id;
8ded351a 273 struct vb2_buffer *ivb;
d42bffb8
MM
274 dma_addr_t dma_addr;
275 u32 tmp;
276
277 tmp = ioread32(ipd->regs + INT_CSR) & (FLD_START | FLD_END_ODD);
278 if (!tmp)
279 return IRQ_NONE; /* not our irq */
280 if ((tmp & FLD_START) && !(tmp & FLD_END_ODD)) {
281 iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START,
282 ipd->regs + INT_CSR);
283 ipd->field_count++;
284 return IRQ_HANDLED; /* start of field irq */
285 }
d42bffb8
MM
286 tmp = ioread32(ipd->regs + CSR1) & (FLD_CRPT_EVEN | FLD_CRPT_ODD);
287 if (tmp) {
d42bffb8
MM
288 iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
289 FLD_DN_ODD | FLD_DN_EVEN |
290 CAP_CONT_EVEN | CAP_CONT_ODD,
291 ipd->regs + CSR1);
292 mmiowb();
293 }
294
295 spin_lock(&ipd->lock);
8ded351a 296 if (ipd->curr_buf) {
0dcb953a 297 v4l2_get_timestamp(&ipd->curr_buf->v4l2_buf.timestamp);
8ded351a
MM
298 ipd->curr_buf->v4l2_buf.sequence = (ipd->field_count) >> 1;
299 vb2_buffer_done(ipd->curr_buf, VB2_BUF_STATE_DONE);
300 }
301
9556be12 302 if (!ipd->vidq.streaming || list_empty(&ipd->dmaq))
d42bffb8 303 goto stop_dma;
8ded351a
MM
304 ivb = list_first_entry(&ipd->dmaq, typeof(*ivb), done_entry);
305 list_del(&ivb->done_entry);
306 ipd->curr_buf = ivb;
1f28291c 307 dma_addr = vb2_dma_contig_plane_dma_addr(ivb, 0);
d42bffb8 308 iowrite32(dma_addr, ipd->regs + EVEN_DMA_START);
8ded351a
MM
309 iowrite32(dma_addr + img_width, ipd->regs + ODD_DMA_START);
310 iowrite32(img_width, ipd->regs + EVEN_DMA_STRIDE);
311 iowrite32(img_width, ipd->regs + ODD_DMA_STRIDE);
d42bffb8
MM
312 mmiowb();
313 /* enable interrupts, clear all irq flags */
314 iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
315 FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR);
316 spin_unlock(&ipd->lock);
317 return IRQ_HANDLED;
318
319stop_dma:
320 ipd->curr_buf = NULL;
321 /* stop the board */
322 write_i2c_reg_nowait(ipd->regs, CSR2, ipd->csr2);
8ded351a
MM
323 iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
324 FLD_DN_ODD | FLD_DN_EVEN, ipd->regs + CSR1);
d42bffb8
MM
325 /* disable interrupts, clear all irq flags */
326 iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR);
327 spin_unlock(&ipd->lock);
328 return IRQ_HANDLED;
329}
330
d42bffb8
MM
331static const struct v4l2_file_operations dt3155_fops = {
332 .owner = THIS_MODULE,
9556be12
HV
333 .open = v4l2_fh_open,
334 .release = vb2_fop_release,
335 .unlocked_ioctl = video_ioctl2,
336 .read = vb2_fop_read,
337 .mmap = vb2_fop_mmap,
338 .poll = vb2_fop_poll
d42bffb8
MM
339};
340
6a11087b 341static int dt3155_querycap(struct file *filp, void *p, struct v4l2_capability *cap)
d42bffb8
MM
342{
343 struct dt3155_priv *pd = video_drvdata(filp);
344
345 strcpy(cap->driver, DT3155_NAME);
346 strcpy(cap->card, DT3155_NAME " frame grabber");
347 sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev));
57e774cc 348 cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
8ded351a 349 DT3155_CAPTURE_METHOD;
57e774cc 350 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
d42bffb8
MM
351 return 0;
352}
353
6a11087b 354static int dt3155_enum_fmt_vid_cap(struct file *filp, void *p, struct v4l2_fmtdesc *f)
d42bffb8
MM
355{
356 if (f->index >= NUM_OF_FORMATS)
357 return -EINVAL;
358 *f = frame_std[f->index];
359 return 0;
360}
361
6a11087b 362static int dt3155_g_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
d42bffb8
MM
363{
364 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
365 return -EINVAL;
366 f->fmt.pix.width = img_width;
367 f->fmt.pix.height = img_height;
368 f->fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;
369 f->fmt.pix.field = V4L2_FIELD_NONE;
370 f->fmt.pix.bytesperline = f->fmt.pix.width;
371 f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height;
372 f->fmt.pix.colorspace = 0;
373 f->fmt.pix.priv = 0;
374 return 0;
375}
376
6a11087b 377static int dt3155_try_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
d42bffb8
MM
378{
379 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
380 return -EINVAL;
381 if (f->fmt.pix.width == img_width &&
382 f->fmt.pix.height == img_height &&
383 f->fmt.pix.pixelformat == V4L2_PIX_FMT_GREY &&
384 f->fmt.pix.field == V4L2_FIELD_NONE &&
385 f->fmt.pix.bytesperline == f->fmt.pix.width &&
386 f->fmt.pix.sizeimage == f->fmt.pix.width * f->fmt.pix.height)
387 return 0;
388 else
389 return -EINVAL;
390}
391
6a11087b 392static int dt3155_s_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
d42bffb8 393{
6a11087b 394 return dt3155_g_fmt_vid_cap(filp, p, f);
d42bffb8
MM
395}
396
6a11087b 397static int dt3155_querystd(struct file *filp, void *p, v4l2_std_id *norm)
d42bffb8
MM
398{
399 *norm = DT3155_CURRENT_NORM;
400 return 0;
401}
402
6a11087b 403static int dt3155_g_std(struct file *filp, void *p, v4l2_std_id *norm)
d42bffb8
MM
404{
405 *norm = DT3155_CURRENT_NORM;
406 return 0;
407}
408
6a11087b 409static int dt3155_s_std(struct file *filp, void *p, v4l2_std_id norm)
d42bffb8 410{
314527ac 411 if (norm & DT3155_CURRENT_NORM)
d42bffb8
MM
412 return 0;
413 return -EINVAL;
414}
415
6a11087b 416static int dt3155_enum_input(struct file *filp, void *p, struct v4l2_input *input)
d42bffb8
MM
417{
418 if (input->index)
419 return -EINVAL;
420 strcpy(input->name, "Coax in");
421 input->type = V4L2_INPUT_TYPE_CAMERA;
fdd2d934
MM
422 /*
423 * FIXME: input->std = 0 according to v4l2 API
424 * VIDIOC_G_STD, VIDIOC_S_STD, VIDIOC_QUERYSTD and VIDIOC_ENUMSTD
425 * should return -EINVAL
426 */
427 input->std = DT3155_CURRENT_NORM;
d42bffb8
MM
428 input->status = 0;/* FIXME: add sync detection & V4L2_IN_ST_NO_H_LOCK */
429 return 0;
430}
431
6a11087b 432static int dt3155_g_input(struct file *filp, void *p, unsigned int *i)
d42bffb8
MM
433{
434 *i = 0;
435 return 0;
436}
437
6a11087b 438static int dt3155_s_input(struct file *filp, void *p, unsigned int i)
d42bffb8
MM
439{
440 if (i)
441 return -EINVAL;
442 return 0;
443}
444
6a11087b 445static int dt3155_g_parm(struct file *filp, void *p, struct v4l2_streamparm *parms)
d42bffb8
MM
446{
447 if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
448 return -EINVAL;
449 parms->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
450 parms->parm.capture.capturemode = 0;
451 parms->parm.capture.timeperframe.numerator = 1001;
452 parms->parm.capture.timeperframe.denominator = frames_per_sec * 1000;
453 parms->parm.capture.extendedmode = 0;
fdd2d934 454 parms->parm.capture.readbuffers = 1; /* FIXME: 2 buffers? */
d42bffb8
MM
455 return 0;
456}
457
6a11087b 458static int dt3155_s_parm(struct file *filp, void *p, struct v4l2_streamparm *parms)
d42bffb8
MM
459{
460 if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
461 return -EINVAL;
462 parms->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
463 parms->parm.capture.capturemode = 0;
464 parms->parm.capture.timeperframe.numerator = 1001;
465 parms->parm.capture.timeperframe.denominator = frames_per_sec * 1000;
466 parms->parm.capture.extendedmode = 0;
fdd2d934 467 parms->parm.capture.readbuffers = 1; /* FIXME: 2 buffers? */
d42bffb8
MM
468 return 0;
469}
470
471static const struct v4l2_ioctl_ops dt3155_ioctl_ops = {
6a11087b
HV
472 .vidioc_querycap = dt3155_querycap,
473 .vidioc_enum_fmt_vid_cap = dt3155_enum_fmt_vid_cap,
474 .vidioc_try_fmt_vid_cap = dt3155_try_fmt_vid_cap,
475 .vidioc_g_fmt_vid_cap = dt3155_g_fmt_vid_cap,
476 .vidioc_s_fmt_vid_cap = dt3155_s_fmt_vid_cap,
9556be12
HV
477 .vidioc_reqbufs = vb2_ioctl_reqbufs,
478 .vidioc_create_bufs = vb2_ioctl_create_bufs,
479 .vidioc_querybuf = vb2_ioctl_querybuf,
480 .vidioc_expbuf = vb2_ioctl_expbuf,
481 .vidioc_qbuf = vb2_ioctl_qbuf,
482 .vidioc_dqbuf = vb2_ioctl_dqbuf,
483 .vidioc_streamon = vb2_ioctl_streamon,
484 .vidioc_streamoff = vb2_ioctl_streamoff,
6a11087b
HV
485 .vidioc_querystd = dt3155_querystd,
486 .vidioc_g_std = dt3155_g_std,
487 .vidioc_s_std = dt3155_s_std,
488 .vidioc_enum_input = dt3155_enum_input,
489 .vidioc_g_input = dt3155_g_input,
490 .vidioc_s_input = dt3155_s_input,
491 .vidioc_g_parm = dt3155_g_parm,
492 .vidioc_s_parm = dt3155_s_parm,
d42bffb8
MM
493};
494
168b5092 495static int dt3155_init_board(struct dt3155_priv *pd)
d42bffb8 496{
168b5092 497 struct pci_dev *pdev = pd->pdev;
d42bffb8 498 int i;
deb28978 499 u8 tmp = 0;
a57941c2 500
8ded351a 501 pci_set_master(pdev); /* dt3155 needs it */
d42bffb8
MM
502
503 /* resetting the adapter */
deb28978
HV
504 iowrite32(ADDR_ERR_ODD | ADDR_ERR_EVEN | FLD_CRPT_ODD | FLD_CRPT_EVEN |
505 FLD_DN_ODD | FLD_DN_EVEN, pd->regs + CSR1);
d42bffb8 506 mmiowb();
8ded351a 507 msleep(20);
d42bffb8 508
6a11087b 509 /* initializing adapter registers */
d42bffb8
MM
510 iowrite32(FIFO_EN | SRST, pd->regs + CSR1);
511 mmiowb();
512 iowrite32(0xEEEEEE01, pd->regs + EVEN_PIXEL_FMT);
513 iowrite32(0xEEEEEE01, pd->regs + ODD_PIXEL_FMT);
514 iowrite32(0x00000020, pd->regs + FIFO_TRIGER);
515 iowrite32(0x00000103, pd->regs + XFER_MODE);
516 iowrite32(0, pd->regs + RETRY_WAIT_CNT);
517 iowrite32(0, pd->regs + INT_CSR);
518 iowrite32(1, pd->regs + EVEN_FLD_MASK);
519 iowrite32(1, pd->regs + ODD_FLD_MASK);
520 iowrite32(0, pd->regs + MASK_LENGTH);
521 iowrite32(0x0005007C, pd->regs + FIFO_FLAG_CNT);
522 iowrite32(0x01010101, pd->regs + IIC_CLK_DUR);
523 mmiowb();
524
525 /* verifying that we have a DT3155 board (not just a SAA7116 chip) */
526 read_i2c_reg(pd->regs, DT_ID, &tmp);
527 if (tmp != DT3155_ID)
528 return -ENODEV;
529
530 /* initialize AD LUT */
531 write_i2c_reg(pd->regs, AD_ADDR, 0);
532 for (i = 0; i < 256; i++)
533 write_i2c_reg(pd->regs, AD_LUT, i);
534
535 /* initialize ADC references */
536 /* FIXME: pos_ref & neg_ref depend on VT_50HZ */
537 write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
538 write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);
539 write_i2c_reg(pd->regs, AD_ADDR, AD_POS_REF);
540 write_i2c_reg(pd->regs, AD_CMD, 34);
541 write_i2c_reg(pd->regs, AD_ADDR, AD_NEG_REF);
542 write_i2c_reg(pd->regs, AD_CMD, 0);
543
544 /* initialize PM LUT */
545 write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM);
546 for (i = 0; i < 256; i++) {
547 write_i2c_reg(pd->regs, PM_LUT_ADDR, i);
548 write_i2c_reg(pd->regs, PM_LUT_DATA, i);
549 }
550 write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM | PM_LUT_SEL);
551 for (i = 0; i < 256; i++) {
552 write_i2c_reg(pd->regs, PM_LUT_ADDR, i);
553 write_i2c_reg(pd->regs, PM_LUT_DATA, i);
554 }
555 write_i2c_reg(pd->regs, CONFIG, pd->config); /* ACQ_MODE_EVEN */
556
6dc8f382 557 /* select channel 1 for input and set sync level */
d42bffb8
MM
558 write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
559 write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);
560
deb28978
HV
561 /* disable all irqs, clear all irq flags */
562 iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD,
563 pd->regs + INT_CSR);
564
d42bffb8
MM
565 return 0;
566}
567
568static struct video_device dt3155_vdev = {
569 .name = DT3155_NAME,
570 .fops = &dt3155_fops,
571 .ioctl_ops = &dt3155_ioctl_ops,
572 .minor = -1,
f91fccde 573 .release = video_device_release_empty,
fdd2d934 574 .tvnorms = DT3155_CURRENT_NORM,
d42bffb8
MM
575};
576
6a11087b 577static int dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id)
d42bffb8 578{
a57941c2 579 int err;
d42bffb8
MM
580 struct dt3155_priv *pd;
581
68788979 582 err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
c94a2e47 583 if (err)
a57941c2 584 return -ENODEV;
92afdc1b 585 pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL);
c94a2e47 586 if (!pd)
d42bffb8 587 return -ENOMEM;
92afdc1b 588
168b5092
HV
589 err = v4l2_device_register(&pdev->dev, &pd->v4l2_dev);
590 if (err)
591 return err;
f91fccde 592 pd->vdev = dt3155_vdev;
168b5092 593 pd->vdev.v4l2_dev = &pd->v4l2_dev;
f91fccde 594 video_set_drvdata(&pd->vdev, pd); /* for use in video_fops */
8ded351a 595 pd->pdev = pdev;
d42bffb8 596 INIT_LIST_HEAD(&pd->dmaq);
d42bffb8 597 mutex_init(&pd->mux);
f91fccde 598 pd->vdev.lock = &pd->mux; /* for locking v4l2_file_operations */
9556be12
HV
599 pd->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
600 pd->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
601 pd->vidq.io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
602 pd->vidq.ops = &q_ops;
603 pd->vidq.mem_ops = &vb2_dma_contig_memops;
604 pd->vidq.drv_priv = pd;
605 pd->vidq.min_buffers_needed = 2;
606 pd->vidq.lock = &pd->mux; /* for locking v4l2_file_operations */
607 pd->vdev.queue = &pd->vidq;
608 err = vb2_queue_init(&pd->vidq);
609 if (err < 0)
610 goto err_v4l2_dev_unreg;
611 pd->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
612 if (IS_ERR(pd->alloc_ctx)) {
613 dev_err(&pdev->dev, "Can't allocate buffer context");
614 err = PTR_ERR(pd->alloc_ctx);
615 goto err_v4l2_dev_unreg;
616 }
8ded351a 617 spin_lock_init(&pd->lock);
d42bffb8
MM
618 pd->csr2 = csr2_init;
619 pd->config = config_init;
8ded351a 620 err = pci_enable_device(pdev);
c94a2e47 621 if (err)
9556be12 622 goto err_free_ctx;
8ded351a 623 err = pci_request_region(pdev, 0, pci_name(pdev));
d42bffb8 624 if (err)
168b5092 625 goto err_pci_disable;
8ded351a 626 pd->regs = pci_iomap(pdev, 0, pci_resource_len(pd->pdev, 0));
aecf33db 627 if (!pd->regs) {
d42bffb8 628 err = -ENOMEM;
168b5092 629 goto err_free_reg;
aecf33db 630 }
168b5092
HV
631 err = dt3155_init_board(pd);
632 if (err)
633 goto err_iounmap;
634 err = request_irq(pd->pdev->irq, dt3155_irq_handler_even,
635 IRQF_SHARED, DT3155_NAME, pd);
c94a2e47 636 if (err)
168b5092 637 goto err_iounmap;
f91fccde 638 err = video_register_device(&pd->vdev, VFL_TYPE_GRABBER, -1);
a57941c2 639 if (err)
168b5092 640 goto err_free_irq;
f91fccde 641 dev_info(&pdev->dev, "/dev/video%i is ready\n", pd->vdev.minor);
d42bffb8
MM
642 return 0; /* success */
643
168b5092
HV
644err_free_irq:
645 free_irq(pd->pdev->irq, pd);
646err_iounmap:
8ded351a 647 pci_iounmap(pdev, pd->regs);
168b5092 648err_free_reg:
8ded351a 649 pci_release_region(pdev, 0);
168b5092 650err_pci_disable:
8ded351a 651 pci_disable_device(pdev);
9556be12
HV
652err_free_ctx:
653 vb2_dma_contig_cleanup_ctx(pd->alloc_ctx);
168b5092
HV
654err_v4l2_dev_unreg:
655 v4l2_device_unregister(&pd->v4l2_dev);
d42bffb8
MM
656 return err;
657}
658
6a11087b 659static void dt3155_remove(struct pci_dev *pdev)
d42bffb8 660{
168b5092
HV
661 struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
662 struct dt3155_priv *pd = container_of(v4l2_dev, struct dt3155_priv, v4l2_dev);
d42bffb8 663
f91fccde 664 video_unregister_device(&pd->vdev);
168b5092 665 free_irq(pd->pdev->irq, pd);
9556be12 666 vb2_queue_release(&pd->vidq);
168b5092 667 v4l2_device_unregister(&pd->v4l2_dev);
8ded351a
MM
668 pci_iounmap(pdev, pd->regs);
669 pci_release_region(pdev, 0);
670 pci_disable_device(pdev);
9556be12 671 vb2_dma_contig_cleanup_ctx(pd->alloc_ctx);
d42bffb8
MM
672}
673
41e043fc 674static const struct pci_device_id pci_ids[] = {
6fb0e403 675 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, DT3155_DEVICE_ID) },
d42bffb8
MM
676 { 0, /* zero marks the end */ },
677};
678MODULE_DEVICE_TABLE(pci, pci_ids);
679
680static struct pci_driver pci_driver = {
681 .name = DT3155_NAME,
682 .id_table = pci_ids,
683 .probe = dt3155_probe,
79fc8d89 684 .remove = dt3155_remove,
d42bffb8
MM
685};
686
1a3acd3d 687module_pci_driver(pci_driver);
d42bffb8
MM
688
689MODULE_DESCRIPTION("video4linux pci-driver for dt3155 frame grabber");
690MODULE_AUTHOR("Marin Mitov <mitov@issp.bas.bg>");
691MODULE_VERSION(DT3155_VERSION);
692MODULE_LICENSE("GPL");