dt3155.c 18.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/***************************************************************************
 *   Copyright (C) 2006-2010 by Marin Mitov                                *
 *   mitov@issp.bas.bg                                                     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 ***************************************************************************/

17
#include <linux/module.h>
18 19
#include <linux/version.h>
#include <linux/stringify.h>
20
#include <linux/delay.h>
21
#include <linux/kthread.h>
22
#include <linux/slab.h>
23 24
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
25
#include <media/v4l2-common.h>
26
#include <media/videobuf2-dma-contig.h>
27

28
#include "dt3155.h"
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44

#define DT3155_DEVICE_ID 0x1223

/**
 * read_i2c_reg - reads an internal i2c register
 *
 * @addr:	dt3155 mmio base address
 * @index:	index (internal address) of register to read
 * @data:	pointer to byte the read data will be placed in
 *
 * returns:	zero on success or error code
 *
 * This function starts reading the specified (by index) register
 * and busy waits for the process to finish. The result is placed
 * in a byte pointed by data.
 */
H
Hans Verkuil 已提交
45
static int read_i2c_reg(void __iomem *addr, u8 index, u8 *data)
46 47 48
{
	u32 tmp = index;

H
Hans Verkuil 已提交
49
	iowrite32((tmp << 17) | IIC_READ, addr + IIC_CSR2);
50 51
	mmiowb();
	udelay(45); /* wait at least 43 usec for NEW_CYCLE to clear */
52 53
	if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
		return -EIO; /* error: NEW_CYCLE not cleared */
54 55 56 57
	tmp = ioread32(addr + IIC_CSR1);
	if (tmp & DIRECT_ABORT) {
		/* reset DIRECT_ABORT bit */
		iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
58
		return -EIO; /* error: DIRECT_ABORT set */
59
	}
H
Hans Verkuil 已提交
60
	*data = tmp >> 24;
61 62 63 64 65 66 67 68 69 70 71 72
	return 0;
}

/**
 * write_i2c_reg - writes to an internal i2c register
 *
 * @addr:	dt3155 mmio base address
 * @index:	index (internal address) of register to read
 * @data:	data to be written
 *
 * returns:	zero on success or error code
 *
H
Hans Verkuil 已提交
73
 * This function starts writing the specified (by index) register
74 75
 * and busy waits for the process to finish.
 */
H
Hans Verkuil 已提交
76
static int write_i2c_reg(void __iomem *addr, u8 index, u8 data)
77 78 79
{
	u32 tmp = index;

H
Hans Verkuil 已提交
80
	iowrite32((tmp << 17) | IIC_WRITE | data, addr + IIC_CSR2);
81 82
	mmiowb();
	udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */
83 84
	if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
		return -EIO; /* error: NEW_CYCLE not cleared */
85 86 87
	if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) {
		/* reset DIRECT_ABORT bit */
		iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
88
		return -EIO; /* error: DIRECT_ABORT set */
89 90 91 92 93 94 95 96 97 98 99
	}
	return 0;
}

/**
 * write_i2c_reg_nowait - writes to an internal i2c register
 *
 * @addr:	dt3155 mmio base address
 * @index:	index (internal address) of register to read
 * @data:	data to be written
 *
H
Hans Verkuil 已提交
100
 * This function starts writing the specified (by index) register
101 102
 * and then returns.
 */
103
static void write_i2c_reg_nowait(void __iomem *addr, u8 index, u8 data)
104 105 106
{
	u32 tmp = index;

H
Hans Verkuil 已提交
107
	iowrite32((tmp << 17) | IIC_WRITE | data, addr + IIC_CSR2);
108 109 110 111 112 113 114 115 116 117
	mmiowb();
}

/**
 * wait_i2c_reg - waits the read/write to finish
 *
 * @addr:	dt3155 mmio base address
 *
 * returns:	zero on success or error code
 *
H
Hans Verkuil 已提交
118
 * This function waits reading/writing to finish.
119
 */
120
static int wait_i2c_reg(void __iomem *addr)
121 122 123
{
	if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
		udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */
124 125
	if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
		return -EIO; /* error: NEW_CYCLE not cleared */
126 127 128
	if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) {
		/* reset DIRECT_ABORT bit */
		iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
129
		return -EIO; /* error: DIRECT_ABORT set */
130 131 132 133 134
	}
	return 0;
}

static int
135 136
dt3155_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
		unsigned int *nbuffers, unsigned int *num_planes,
137 138
		unsigned int sizes[], void *alloc_ctxs[])

139
{
140
	struct dt3155_priv *pd = vb2_get_drv_priv(vq);
141
	unsigned size = pd->width * pd->height;
142

143 144 145 146
	if (vq->num_buffers + *nbuffers < 2)
		*nbuffers = 2 - vq->num_buffers;
	if (fmt && fmt->fmt.pix.sizeimage < size)
		return -EINVAL;
147
	*num_planes = 1;
148 149
	sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size;
	alloc_ctxs[0] = pd->alloc_ctx;
150 151 152
	return 0;
}

H
Hans Verkuil 已提交
153
static int dt3155_buf_prepare(struct vb2_buffer *vb)
154
{
155 156 157
	struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue);

	vb2_set_plane_payload(vb, 0, pd->width * pd->height);
158 159 160
	return 0;
}

161 162 163 164 165 166 167 168 169
static int dt3155_start_streaming(struct vb2_queue *q, unsigned count)
{
	struct dt3155_priv *pd = vb2_get_drv_priv(q);
	struct vb2_buffer *vb = pd->curr_buf;
	dma_addr_t dma_addr;

	pd->sequence = 0;
	dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
	iowrite32(dma_addr, pd->regs + EVEN_DMA_START);
170 171 172
	iowrite32(dma_addr + pd->width, pd->regs + ODD_DMA_START);
	iowrite32(pd->width, pd->regs + EVEN_DMA_STRIDE);
	iowrite32(pd->width, pd->regs + ODD_DMA_STRIDE);
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
	/* enable interrupts, clear all irq flags */
	iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
			FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR);
	iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
		  FLD_DN_ODD | FLD_DN_EVEN | CAP_CONT_EVEN | CAP_CONT_ODD,
							pd->regs + CSR1);
	wait_i2c_reg(pd->regs);
	write_i2c_reg(pd->regs, CONFIG, pd->config);
	write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE);
	write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_DONE);

	/*  start the board  */
	write_i2c_reg(pd->regs, CSR2, pd->csr2 | BUSY_EVEN | BUSY_ODD);
	return 0;
}

H
Hans Verkuil 已提交
189
static void dt3155_stop_streaming(struct vb2_queue *q)
190
{
191 192 193 194
	struct dt3155_priv *pd = vb2_get_drv_priv(q);
	struct vb2_buffer *vb;

	spin_lock_irq(&pd->lock);
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
	/* stop the board */
	write_i2c_reg_nowait(pd->regs, CSR2, pd->csr2);
	iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
		  FLD_DN_ODD | FLD_DN_EVEN, pd->regs + CSR1);
	/* disable interrupts, clear all irq flags */
	iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR);
	spin_unlock_irq(&pd->lock);

	/*
	 * It is not clear whether the DMA stops at once or whether it
	 * will finish the current frame or field first. To be on the
	 * safe side we wait a bit.
	 */
	msleep(45);

	spin_lock_irq(&pd->lock);
	if (pd->curr_buf) {
		vb2_buffer_done(pd->curr_buf, VB2_BUF_STATE_ERROR);
		pd->curr_buf = NULL;
	}

216 217 218 219 220 221
	while (!list_empty(&pd->dmaq)) {
		vb = list_first_entry(&pd->dmaq, typeof(*vb), done_entry);
		list_del(&vb->done_entry);
		vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
	}
	spin_unlock_irq(&pd->lock);
222 223
}

H
Hans Verkuil 已提交
224
static void dt3155_buf_queue(struct vb2_buffer *vb)
225
{
226 227
	struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue);

228
	/*  pd->vidq.streaming = 1 when dt3155_buf_queue() is invoked  */
229 230 231
	spin_lock_irq(&pd->lock);
	if (pd->curr_buf)
		list_add_tail(&vb->done_entry, &pd->dmaq);
232
	else
233 234
		pd->curr_buf = vb;
	spin_unlock_irq(&pd->lock);
235 236
}

237
static const struct vb2_ops q_ops = {
238
	.queue_setup = dt3155_queue_setup,
239 240
	.wait_prepare = vb2_ops_wait_prepare,
	.wait_finish = vb2_ops_wait_finish,
241
	.buf_prepare = dt3155_buf_prepare,
242
	.start_streaming = dt3155_start_streaming,
243
	.stop_streaming = dt3155_stop_streaming,
244 245 246
	.buf_queue = dt3155_buf_queue,
};

H
Hans Verkuil 已提交
247
static irqreturn_t dt3155_irq_handler_even(int irq, void *dev_id)
248 249
{
	struct dt3155_priv *ipd = dev_id;
250
	struct vb2_buffer *ivb;
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
	dma_addr_t dma_addr;
	u32 tmp;

	tmp = ioread32(ipd->regs + INT_CSR) & (FLD_START | FLD_END_ODD);
	if (!tmp)
		return IRQ_NONE;  /* not our irq */
	if ((tmp & FLD_START) && !(tmp & FLD_END_ODD)) {
		iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START,
							ipd->regs + INT_CSR);
		return IRQ_HANDLED; /* start of field irq */
	}
	tmp = ioread32(ipd->regs + CSR1) & (FLD_CRPT_EVEN | FLD_CRPT_ODD);
	if (tmp) {
		iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
						FLD_DN_ODD | FLD_DN_EVEN |
						CAP_CONT_EVEN | CAP_CONT_ODD,
							ipd->regs + CSR1);
		mmiowb();
	}

	spin_lock(&ipd->lock);
272
	if (ipd->curr_buf && !list_empty(&ipd->dmaq)) {
273
		v4l2_get_timestamp(&ipd->curr_buf->v4l2_buf.timestamp);
274 275
		ipd->curr_buf->v4l2_buf.sequence = ipd->sequence++;
		ipd->curr_buf->v4l2_buf.field = V4L2_FIELD_NONE;
276
		vb2_buffer_done(ipd->curr_buf, VB2_BUF_STATE_DONE);
277 278 279 280 281 282

		ivb = list_first_entry(&ipd->dmaq, typeof(*ivb), done_entry);
		list_del(&ivb->done_entry);
		ipd->curr_buf = ivb;
		dma_addr = vb2_dma_contig_plane_dma_addr(ivb, 0);
		iowrite32(dma_addr, ipd->regs + EVEN_DMA_START);
283 284 285
		iowrite32(dma_addr + ipd->width, ipd->regs + ODD_DMA_START);
		iowrite32(ipd->width, ipd->regs + EVEN_DMA_STRIDE);
		iowrite32(ipd->width, ipd->regs + ODD_DMA_STRIDE);
286
		mmiowb();
287 288
	}

289 290 291 292 293 294 295 296 297
	/* enable interrupts, clear all irq flags */
	iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
			FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR);
	spin_unlock(&ipd->lock);
	return IRQ_HANDLED;
}

static const struct v4l2_file_operations dt3155_fops = {
	.owner = THIS_MODULE,
298 299 300 301 302 303
	.open = v4l2_fh_open,
	.release = vb2_fop_release,
	.unlocked_ioctl = video_ioctl2,
	.read = vb2_fop_read,
	.mmap = vb2_fop_mmap,
	.poll = vb2_fop_poll
304 305
};

H
Hans Verkuil 已提交
306
static int dt3155_querycap(struct file *filp, void *p, struct v4l2_capability *cap)
307 308 309 310 311 312
{
	struct dt3155_priv *pd = video_drvdata(filp);

	strcpy(cap->driver, DT3155_NAME);
	strcpy(cap->card, DT3155_NAME " frame grabber");
	sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev));
H
Hans Verkuil 已提交
313
	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
314
		V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
H
Hans Verkuil 已提交
315
	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
316 317 318
	return 0;
}

H
Hans Verkuil 已提交
319
static int dt3155_enum_fmt_vid_cap(struct file *filp, void *p, struct v4l2_fmtdesc *f)
320
{
321
	if (f->index)
322
		return -EINVAL;
323 324
	f->pixelformat = V4L2_PIX_FMT_GREY;
	strcpy(f->description, "8-bit Greyscale");
325 326 327
	return 0;
}

328
static int dt3155_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
329
{
330 331 332 333
	struct dt3155_priv *pd = video_drvdata(filp);

	f->fmt.pix.width = pd->width;
	f->fmt.pix.height = pd->height;
334 335 336 337
	f->fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;
	f->fmt.pix.field = V4L2_FIELD_NONE;
	f->fmt.pix.bytesperline = f->fmt.pix.width;
	f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height;
338
	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
339 340 341
	return 0;
}

H
Hans Verkuil 已提交
342
static int dt3155_g_std(struct file *filp, void *p, v4l2_std_id *norm)
343
{
344 345 346
	struct dt3155_priv *pd = video_drvdata(filp);

	*norm = pd->std;
347 348 349
	return 0;
}

H
Hans Verkuil 已提交
350
static int dt3155_s_std(struct file *filp, void *p, v4l2_std_id norm)
351
{
352 353 354
	struct dt3155_priv *pd = video_drvdata(filp);

	if (pd->std == norm)
355
		return 0;
356 357 358 359 360 361 362 363 364 365 366 367 368
	if (vb2_is_busy(&pd->vidq))
		return -EBUSY;
	pd->std = norm;
	if (pd->std & V4L2_STD_525_60) {
		pd->csr2 = VT_60HZ;
		pd->width = 640;
		pd->height = 480;
	} else {
		pd->csr2 = VT_50HZ;
		pd->width = 768;
		pd->height = 576;
	}
	return 0;
369 370
}

H
Hans Verkuil 已提交
371
static int dt3155_enum_input(struct file *filp, void *p, struct v4l2_input *input)
372
{
373
	if (input->index > 3)
374
		return -EINVAL;
375 376 377 378
	if (input->index)
		snprintf(input->name, sizeof(input->name), "VID%d", input->index);
	else
		strlcpy(input->name, "J2/VID0", sizeof(input->name));
379
	input->type = V4L2_INPUT_TYPE_CAMERA;
380 381
	input->std = V4L2_STD_ALL;
	input->status = 0;
382 383 384
	return 0;
}

H
Hans Verkuil 已提交
385
static int dt3155_g_input(struct file *filp, void *p, unsigned int *i)
386
{
387 388 389
	struct dt3155_priv *pd = video_drvdata(filp);

	*i = pd->input;
390 391 392
	return 0;
}

H
Hans Verkuil 已提交
393
static int dt3155_s_input(struct file *filp, void *p, unsigned int i)
394
{
395 396 397
	struct dt3155_priv *pd = video_drvdata(filp);

	if (i > 3)
398
		return -EINVAL;
399 400 401
	pd->input = i;
	write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
	write_i2c_reg(pd->regs, AD_CMD, (i << 6) | (i << 4) | SYNC_LVL_3);
402 403 404 405
	return 0;
}

static const struct v4l2_ioctl_ops dt3155_ioctl_ops = {
H
Hans Verkuil 已提交
406 407
	.vidioc_querycap = dt3155_querycap,
	.vidioc_enum_fmt_vid_cap = dt3155_enum_fmt_vid_cap,
408 409 410
	.vidioc_try_fmt_vid_cap = dt3155_fmt_vid_cap,
	.vidioc_g_fmt_vid_cap = dt3155_fmt_vid_cap,
	.vidioc_s_fmt_vid_cap = dt3155_fmt_vid_cap,
411 412 413 414 415 416 417 418
	.vidioc_reqbufs = vb2_ioctl_reqbufs,
	.vidioc_create_bufs = vb2_ioctl_create_bufs,
	.vidioc_querybuf = vb2_ioctl_querybuf,
	.vidioc_expbuf = vb2_ioctl_expbuf,
	.vidioc_qbuf = vb2_ioctl_qbuf,
	.vidioc_dqbuf = vb2_ioctl_dqbuf,
	.vidioc_streamon = vb2_ioctl_streamon,
	.vidioc_streamoff = vb2_ioctl_streamoff,
H
Hans Verkuil 已提交
419 420 421 422 423
	.vidioc_g_std = dt3155_g_std,
	.vidioc_s_std = dt3155_s_std,
	.vidioc_enum_input = dt3155_enum_input,
	.vidioc_g_input = dt3155_g_input,
	.vidioc_s_input = dt3155_s_input,
424 425
};

426
static int dt3155_init_board(struct dt3155_priv *pd)
427
{
428
	struct pci_dev *pdev = pd->pdev;
429
	int i;
430
	u8 tmp = 0;
431

432
	pci_set_master(pdev); /* dt3155 needs it */
433 434

	/*  resetting the adapter  */
435 436
	iowrite32(ADDR_ERR_ODD | ADDR_ERR_EVEN | FLD_CRPT_ODD | FLD_CRPT_EVEN |
			FLD_DN_ODD | FLD_DN_EVEN, pd->regs + CSR1);
437
	mmiowb();
438
	msleep(20);
439

H
Hans Verkuil 已提交
440
	/*  initializing adapter registers  */
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
	iowrite32(FIFO_EN | SRST, pd->regs + CSR1);
	mmiowb();
	iowrite32(0xEEEEEE01, pd->regs + EVEN_PIXEL_FMT);
	iowrite32(0xEEEEEE01, pd->regs + ODD_PIXEL_FMT);
	iowrite32(0x00000020, pd->regs + FIFO_TRIGER);
	iowrite32(0x00000103, pd->regs + XFER_MODE);
	iowrite32(0, pd->regs + RETRY_WAIT_CNT);
	iowrite32(0, pd->regs + INT_CSR);
	iowrite32(1, pd->regs + EVEN_FLD_MASK);
	iowrite32(1, pd->regs + ODD_FLD_MASK);
	iowrite32(0, pd->regs + MASK_LENGTH);
	iowrite32(0x0005007C, pd->regs + FIFO_FLAG_CNT);
	iowrite32(0x01010101, pd->regs + IIC_CLK_DUR);
	mmiowb();

	/* verifying that we have a DT3155 board (not just a SAA7116 chip) */
	read_i2c_reg(pd->regs, DT_ID, &tmp);
	if (tmp != DT3155_ID)
		return -ENODEV;

	/* initialize AD LUT */
	write_i2c_reg(pd->regs, AD_ADDR, 0);
	for (i = 0; i < 256; i++)
		write_i2c_reg(pd->regs, AD_LUT, i);

	/* initialize ADC references */
	/* FIXME: pos_ref & neg_ref depend on VT_50HZ */
	write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
	write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);
	write_i2c_reg(pd->regs, AD_ADDR, AD_POS_REF);
	write_i2c_reg(pd->regs, AD_CMD, 34);
	write_i2c_reg(pd->regs, AD_ADDR, AD_NEG_REF);
	write_i2c_reg(pd->regs, AD_CMD, 0);

	/* initialize PM LUT */
	write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM);
	for (i = 0; i < 256; i++) {
		write_i2c_reg(pd->regs, PM_LUT_ADDR, i);
		write_i2c_reg(pd->regs, PM_LUT_DATA, i);
	}
	write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM | PM_LUT_SEL);
	for (i = 0; i < 256; i++) {
		write_i2c_reg(pd->regs, PM_LUT_ADDR, i);
		write_i2c_reg(pd->regs, PM_LUT_DATA, i);
	}
	write_i2c_reg(pd->regs, CONFIG, pd->config); /*  ACQ_MODE_EVEN  */

488
	/* select channel 1 for input and set sync level */
489 490 491
	write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
	write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);

492 493 494 495
	/* disable all irqs, clear all irq flags */
	iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD,
			pd->regs + INT_CSR);

496 497 498 499 500 501 502 503
	return 0;
}

static struct video_device dt3155_vdev = {
	.name = DT3155_NAME,
	.fops = &dt3155_fops,
	.ioctl_ops = &dt3155_ioctl_ops,
	.minor = -1,
504
	.release = video_device_release_empty,
505
	.tvnorms = V4L2_STD_ALL,
506 507
};

H
Hans Verkuil 已提交
508
static int dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id)
509
{
510
	int err;
511 512
	struct dt3155_priv *pd;

513
	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
514
	if (err)
515
		return -ENODEV;
516
	pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL);
517
	if (!pd)
518
		return -ENOMEM;
519

520 521 522
	err = v4l2_device_register(&pdev->dev, &pd->v4l2_dev);
	if (err)
		return err;
523
	pd->vdev = dt3155_vdev;
524
	pd->vdev.v4l2_dev = &pd->v4l2_dev;
525
	video_set_drvdata(&pd->vdev, pd);  /* for use in video_fops */
526
	pd->pdev = pdev;
527 528 529 530
	pd->std = V4L2_STD_625_50;
	pd->csr2 = VT_50HZ;
	pd->width = 768;
	pd->height = 576;
531 532
	INIT_LIST_HEAD(&pd->dmaq);
	mutex_init(&pd->mux);
533
	pd->vdev.lock = &pd->mux; /* for locking v4l2_file_operations */
534 535 536 537 538 539 540
	pd->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	pd->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
	pd->vidq.io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
	pd->vidq.ops = &q_ops;
	pd->vidq.mem_ops = &vb2_dma_contig_memops;
	pd->vidq.drv_priv = pd;
	pd->vidq.min_buffers_needed = 2;
541
	pd->vidq.gfp_flags = GFP_DMA32;
542 543 544 545 546 547 548 549 550 551 552
	pd->vidq.lock = &pd->mux; /* for locking v4l2_file_operations */
	pd->vdev.queue = &pd->vidq;
	err = vb2_queue_init(&pd->vidq);
	if (err < 0)
		goto err_v4l2_dev_unreg;
	pd->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
	if (IS_ERR(pd->alloc_ctx)) {
		dev_err(&pdev->dev, "Can't allocate buffer context");
		err = PTR_ERR(pd->alloc_ctx);
		goto err_v4l2_dev_unreg;
	}
553
	spin_lock_init(&pd->lock);
554
	pd->config = ACQ_MODE_EVEN;
555
	err = pci_enable_device(pdev);
556
	if (err)
557
		goto err_free_ctx;
558
	err = pci_request_region(pdev, 0, pci_name(pdev));
559
	if (err)
560
		goto err_pci_disable;
561
	pd->regs = pci_iomap(pdev, 0, pci_resource_len(pd->pdev, 0));
562
	if (!pd->regs) {
563
		err = -ENOMEM;
564
		goto err_free_reg;
565
	}
566 567 568 569 570
	err = dt3155_init_board(pd);
	if (err)
		goto err_iounmap;
	err = request_irq(pd->pdev->irq, dt3155_irq_handler_even,
					IRQF_SHARED, DT3155_NAME, pd);
571
	if (err)
572
		goto err_iounmap;
573
	err = video_register_device(&pd->vdev, VFL_TYPE_GRABBER, -1);
574
	if (err)
575
		goto err_free_irq;
576
	dev_info(&pdev->dev, "/dev/video%i is ready\n", pd->vdev.minor);
577 578
	return 0;  /*   success   */

579 580 581
err_free_irq:
	free_irq(pd->pdev->irq, pd);
err_iounmap:
582
	pci_iounmap(pdev, pd->regs);
583
err_free_reg:
584
	pci_release_region(pdev, 0);
585
err_pci_disable:
586
	pci_disable_device(pdev);
587 588
err_free_ctx:
	vb2_dma_contig_cleanup_ctx(pd->alloc_ctx);
589 590
err_v4l2_dev_unreg:
	v4l2_device_unregister(&pd->v4l2_dev);
591 592 593
	return err;
}

H
Hans Verkuil 已提交
594
static void dt3155_remove(struct pci_dev *pdev)
595
{
596 597
	struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
	struct dt3155_priv *pd = container_of(v4l2_dev, struct dt3155_priv, v4l2_dev);
598

599
	video_unregister_device(&pd->vdev);
600
	free_irq(pd->pdev->irq, pd);
601
	vb2_queue_release(&pd->vidq);
602
	v4l2_device_unregister(&pd->v4l2_dev);
603 604 605
	pci_iounmap(pdev, pd->regs);
	pci_release_region(pdev, 0);
	pci_disable_device(pdev);
606
	vb2_dma_contig_cleanup_ctx(pd->alloc_ctx);
607 608
}

609
static const struct pci_device_id pci_ids[] = {
610
	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, DT3155_DEVICE_ID) },
611 612 613 614 615 616 617 618
	{ 0, /* zero marks the end */ },
};
MODULE_DEVICE_TABLE(pci, pci_ids);

static struct pci_driver pci_driver = {
	.name = DT3155_NAME,
	.id_table = pci_ids,
	.probe = dt3155_probe,
619
	.remove = dt3155_remove,
620 621
};

622
module_pci_driver(pci_driver);
623 624 625 626 627

MODULE_DESCRIPTION("video4linux pci-driver for dt3155 frame grabber");
MODULE_AUTHOR("Marin Mitov <mitov@issp.bas.bg>");
MODULE_VERSION(DT3155_VERSION);
MODULE_LICENSE("GPL");