18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/***************************************************************************
38c2ecf20Sopenharmony_ci *   Copyright (C) 2006-2010 by Marin Mitov                                *
48c2ecf20Sopenharmony_ci *   mitov@issp.bas.bg                                                     *
58c2ecf20Sopenharmony_ci *                                                                         *
68c2ecf20Sopenharmony_ci *                                                                         *
78c2ecf20Sopenharmony_ci ***************************************************************************/
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/stringify.h>
118c2ecf20Sopenharmony_ci#include <linux/delay.h>
128c2ecf20Sopenharmony_ci#include <linux/kthread.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci#include <media/v4l2-dev.h>
158c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h>
168c2ecf20Sopenharmony_ci#include <media/v4l2-common.h>
178c2ecf20Sopenharmony_ci#include <media/videobuf2-dma-contig.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "dt3155.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define DT3155_DEVICE_ID 0x1223
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/**
248c2ecf20Sopenharmony_ci * read_i2c_reg - reads an internal i2c register
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * @addr:	dt3155 mmio base address
278c2ecf20Sopenharmony_ci * @index:	index (internal address) of register to read
288c2ecf20Sopenharmony_ci * @data:	pointer to byte the read data will be placed in
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci * returns:	zero on success or error code
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci * This function starts reading the specified (by index) register
338c2ecf20Sopenharmony_ci * and busy waits for the process to finish. The result is placed
348c2ecf20Sopenharmony_ci * in a byte pointed by data.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_cistatic int read_i2c_reg(void __iomem *addr, u8 index, u8 *data)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	u32 tmp = index;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	iowrite32((tmp << 17) | IIC_READ, addr + IIC_CSR2);
418c2ecf20Sopenharmony_ci	udelay(45); /* wait at least 43 usec for NEW_CYCLE to clear */
428c2ecf20Sopenharmony_ci	if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
438c2ecf20Sopenharmony_ci		return -EIO; /* error: NEW_CYCLE not cleared */
448c2ecf20Sopenharmony_ci	tmp = ioread32(addr + IIC_CSR1);
458c2ecf20Sopenharmony_ci	if (tmp & DIRECT_ABORT) {
468c2ecf20Sopenharmony_ci		/* reset DIRECT_ABORT bit */
478c2ecf20Sopenharmony_ci		iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
488c2ecf20Sopenharmony_ci		return -EIO; /* error: DIRECT_ABORT set */
498c2ecf20Sopenharmony_ci	}
508c2ecf20Sopenharmony_ci	*data = tmp >> 24;
518c2ecf20Sopenharmony_ci	return 0;
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/**
558c2ecf20Sopenharmony_ci * write_i2c_reg - writes to an internal i2c register
568c2ecf20Sopenharmony_ci *
578c2ecf20Sopenharmony_ci * @addr:	dt3155 mmio base address
588c2ecf20Sopenharmony_ci * @index:	index (internal address) of register to read
598c2ecf20Sopenharmony_ci * @data:	data to be written
608c2ecf20Sopenharmony_ci *
618c2ecf20Sopenharmony_ci * returns:	zero on success or error code
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci * This function starts writing the specified (by index) register
648c2ecf20Sopenharmony_ci * and busy waits for the process to finish.
658c2ecf20Sopenharmony_ci */
668c2ecf20Sopenharmony_cistatic int write_i2c_reg(void __iomem *addr, u8 index, u8 data)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	u32 tmp = index;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	iowrite32((tmp << 17) | IIC_WRITE | data, addr + IIC_CSR2);
718c2ecf20Sopenharmony_ci	udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */
728c2ecf20Sopenharmony_ci	if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
738c2ecf20Sopenharmony_ci		return -EIO; /* error: NEW_CYCLE not cleared */
748c2ecf20Sopenharmony_ci	if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) {
758c2ecf20Sopenharmony_ci		/* reset DIRECT_ABORT bit */
768c2ecf20Sopenharmony_ci		iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
778c2ecf20Sopenharmony_ci		return -EIO; /* error: DIRECT_ABORT set */
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci	return 0;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci/**
838c2ecf20Sopenharmony_ci * write_i2c_reg_nowait - writes to an internal i2c register
848c2ecf20Sopenharmony_ci *
858c2ecf20Sopenharmony_ci * @addr:	dt3155 mmio base address
868c2ecf20Sopenharmony_ci * @index:	index (internal address) of register to read
878c2ecf20Sopenharmony_ci * @data:	data to be written
888c2ecf20Sopenharmony_ci *
898c2ecf20Sopenharmony_ci * This function starts writing the specified (by index) register
908c2ecf20Sopenharmony_ci * and then returns.
918c2ecf20Sopenharmony_ci */
928c2ecf20Sopenharmony_cistatic void write_i2c_reg_nowait(void __iomem *addr, u8 index, u8 data)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	u32 tmp = index;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	iowrite32((tmp << 17) | IIC_WRITE | data, addr + IIC_CSR2);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci/**
1008c2ecf20Sopenharmony_ci * wait_i2c_reg - waits the read/write to finish
1018c2ecf20Sopenharmony_ci *
1028c2ecf20Sopenharmony_ci * @addr:	dt3155 mmio base address
1038c2ecf20Sopenharmony_ci *
1048c2ecf20Sopenharmony_ci * returns:	zero on success or error code
1058c2ecf20Sopenharmony_ci *
1068c2ecf20Sopenharmony_ci * This function waits reading/writing to finish.
1078c2ecf20Sopenharmony_ci */
1088c2ecf20Sopenharmony_cistatic int wait_i2c_reg(void __iomem *addr)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
1118c2ecf20Sopenharmony_ci		udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */
1128c2ecf20Sopenharmony_ci	if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
1138c2ecf20Sopenharmony_ci		return -EIO; /* error: NEW_CYCLE not cleared */
1148c2ecf20Sopenharmony_ci	if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) {
1158c2ecf20Sopenharmony_ci		/* reset DIRECT_ABORT bit */
1168c2ecf20Sopenharmony_ci		iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
1178c2ecf20Sopenharmony_ci		return -EIO; /* error: DIRECT_ABORT set */
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci	return 0;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic int
1238c2ecf20Sopenharmony_cidt3155_queue_setup(struct vb2_queue *vq,
1248c2ecf20Sopenharmony_ci		unsigned int *nbuffers, unsigned int *num_planes,
1258c2ecf20Sopenharmony_ci		unsigned int sizes[], struct device *alloc_devs[])
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	struct dt3155_priv *pd = vb2_get_drv_priv(vq);
1298c2ecf20Sopenharmony_ci	unsigned size = pd->width * pd->height;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	if (vq->num_buffers + *nbuffers < 2)
1328c2ecf20Sopenharmony_ci		*nbuffers = 2 - vq->num_buffers;
1338c2ecf20Sopenharmony_ci	if (*num_planes)
1348c2ecf20Sopenharmony_ci		return sizes[0] < size ? -EINVAL : 0;
1358c2ecf20Sopenharmony_ci	*num_planes = 1;
1368c2ecf20Sopenharmony_ci	sizes[0] = size;
1378c2ecf20Sopenharmony_ci	return 0;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic int dt3155_buf_prepare(struct vb2_buffer *vb)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	vb2_set_plane_payload(vb, 0, pd->width * pd->height);
1458c2ecf20Sopenharmony_ci	return 0;
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic int dt3155_start_streaming(struct vb2_queue *q, unsigned count)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	struct dt3155_priv *pd = vb2_get_drv_priv(q);
1518c2ecf20Sopenharmony_ci	struct vb2_buffer *vb = &pd->curr_buf->vb2_buf;
1528c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	pd->sequence = 0;
1558c2ecf20Sopenharmony_ci	dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
1568c2ecf20Sopenharmony_ci	iowrite32(dma_addr, pd->regs + EVEN_DMA_START);
1578c2ecf20Sopenharmony_ci	iowrite32(dma_addr + pd->width, pd->regs + ODD_DMA_START);
1588c2ecf20Sopenharmony_ci	iowrite32(pd->width, pd->regs + EVEN_DMA_STRIDE);
1598c2ecf20Sopenharmony_ci	iowrite32(pd->width, pd->regs + ODD_DMA_STRIDE);
1608c2ecf20Sopenharmony_ci	/* enable interrupts, clear all irq flags */
1618c2ecf20Sopenharmony_ci	iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
1628c2ecf20Sopenharmony_ci			FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR);
1638c2ecf20Sopenharmony_ci	iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
1648c2ecf20Sopenharmony_ci		  FLD_DN_ODD | FLD_DN_EVEN | CAP_CONT_EVEN | CAP_CONT_ODD,
1658c2ecf20Sopenharmony_ci							pd->regs + CSR1);
1668c2ecf20Sopenharmony_ci	wait_i2c_reg(pd->regs);
1678c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, CONFIG, pd->config);
1688c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE);
1698c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_DONE);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	/*  start the board  */
1728c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, CSR2, pd->csr2 | BUSY_EVEN | BUSY_ODD);
1738c2ecf20Sopenharmony_ci	return 0;
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic void dt3155_stop_streaming(struct vb2_queue *q)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	struct dt3155_priv *pd = vb2_get_drv_priv(q);
1798c2ecf20Sopenharmony_ci	struct vb2_buffer *vb;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	spin_lock_irq(&pd->lock);
1828c2ecf20Sopenharmony_ci	/* stop the board */
1838c2ecf20Sopenharmony_ci	write_i2c_reg_nowait(pd->regs, CSR2, pd->csr2);
1848c2ecf20Sopenharmony_ci	iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
1858c2ecf20Sopenharmony_ci		  FLD_DN_ODD | FLD_DN_EVEN, pd->regs + CSR1);
1868c2ecf20Sopenharmony_ci	/* disable interrupts, clear all irq flags */
1878c2ecf20Sopenharmony_ci	iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR);
1888c2ecf20Sopenharmony_ci	spin_unlock_irq(&pd->lock);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	/*
1918c2ecf20Sopenharmony_ci	 * It is not clear whether the DMA stops at once or whether it
1928c2ecf20Sopenharmony_ci	 * will finish the current frame or field first. To be on the
1938c2ecf20Sopenharmony_ci	 * safe side we wait a bit.
1948c2ecf20Sopenharmony_ci	 */
1958c2ecf20Sopenharmony_ci	msleep(45);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	spin_lock_irq(&pd->lock);
1988c2ecf20Sopenharmony_ci	if (pd->curr_buf) {
1998c2ecf20Sopenharmony_ci		vb2_buffer_done(&pd->curr_buf->vb2_buf, VB2_BUF_STATE_ERROR);
2008c2ecf20Sopenharmony_ci		pd->curr_buf = NULL;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	while (!list_empty(&pd->dmaq)) {
2048c2ecf20Sopenharmony_ci		vb = list_first_entry(&pd->dmaq, typeof(*vb), done_entry);
2058c2ecf20Sopenharmony_ci		list_del(&vb->done_entry);
2068c2ecf20Sopenharmony_ci		vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
2078c2ecf20Sopenharmony_ci	}
2088c2ecf20Sopenharmony_ci	spin_unlock_irq(&pd->lock);
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic void dt3155_buf_queue(struct vb2_buffer *vb)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
2148c2ecf20Sopenharmony_ci	struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	/*  pd->vidq.streaming = 1 when dt3155_buf_queue() is invoked  */
2178c2ecf20Sopenharmony_ci	spin_lock_irq(&pd->lock);
2188c2ecf20Sopenharmony_ci	if (pd->curr_buf)
2198c2ecf20Sopenharmony_ci		list_add_tail(&vb->done_entry, &pd->dmaq);
2208c2ecf20Sopenharmony_ci	else
2218c2ecf20Sopenharmony_ci		pd->curr_buf = vbuf;
2228c2ecf20Sopenharmony_ci	spin_unlock_irq(&pd->lock);
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic const struct vb2_ops q_ops = {
2268c2ecf20Sopenharmony_ci	.queue_setup = dt3155_queue_setup,
2278c2ecf20Sopenharmony_ci	.wait_prepare = vb2_ops_wait_prepare,
2288c2ecf20Sopenharmony_ci	.wait_finish = vb2_ops_wait_finish,
2298c2ecf20Sopenharmony_ci	.buf_prepare = dt3155_buf_prepare,
2308c2ecf20Sopenharmony_ci	.start_streaming = dt3155_start_streaming,
2318c2ecf20Sopenharmony_ci	.stop_streaming = dt3155_stop_streaming,
2328c2ecf20Sopenharmony_ci	.buf_queue = dt3155_buf_queue,
2338c2ecf20Sopenharmony_ci};
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic irqreturn_t dt3155_irq_handler_even(int irq, void *dev_id)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	struct dt3155_priv *ipd = dev_id;
2388c2ecf20Sopenharmony_ci	struct vb2_buffer *ivb;
2398c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
2408c2ecf20Sopenharmony_ci	u32 tmp;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	tmp = ioread32(ipd->regs + INT_CSR) & (FLD_START | FLD_END_ODD);
2438c2ecf20Sopenharmony_ci	if (!tmp)
2448c2ecf20Sopenharmony_ci		return IRQ_NONE;  /* not our irq */
2458c2ecf20Sopenharmony_ci	if ((tmp & FLD_START) && !(tmp & FLD_END_ODD)) {
2468c2ecf20Sopenharmony_ci		iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START,
2478c2ecf20Sopenharmony_ci							ipd->regs + INT_CSR);
2488c2ecf20Sopenharmony_ci		return IRQ_HANDLED; /* start of field irq */
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci	tmp = ioread32(ipd->regs + CSR1) & (FLD_CRPT_EVEN | FLD_CRPT_ODD);
2518c2ecf20Sopenharmony_ci	if (tmp) {
2528c2ecf20Sopenharmony_ci		iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
2538c2ecf20Sopenharmony_ci						FLD_DN_ODD | FLD_DN_EVEN |
2548c2ecf20Sopenharmony_ci						CAP_CONT_EVEN | CAP_CONT_ODD,
2558c2ecf20Sopenharmony_ci							ipd->regs + CSR1);
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	spin_lock(&ipd->lock);
2598c2ecf20Sopenharmony_ci	if (ipd->curr_buf && !list_empty(&ipd->dmaq)) {
2608c2ecf20Sopenharmony_ci		ipd->curr_buf->vb2_buf.timestamp = ktime_get_ns();
2618c2ecf20Sopenharmony_ci		ipd->curr_buf->sequence = ipd->sequence++;
2628c2ecf20Sopenharmony_ci		ipd->curr_buf->field = V4L2_FIELD_NONE;
2638c2ecf20Sopenharmony_ci		vb2_buffer_done(&ipd->curr_buf->vb2_buf, VB2_BUF_STATE_DONE);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci		ivb = list_first_entry(&ipd->dmaq, typeof(*ivb), done_entry);
2668c2ecf20Sopenharmony_ci		list_del(&ivb->done_entry);
2678c2ecf20Sopenharmony_ci		ipd->curr_buf = to_vb2_v4l2_buffer(ivb);
2688c2ecf20Sopenharmony_ci		dma_addr = vb2_dma_contig_plane_dma_addr(ivb, 0);
2698c2ecf20Sopenharmony_ci		iowrite32(dma_addr, ipd->regs + EVEN_DMA_START);
2708c2ecf20Sopenharmony_ci		iowrite32(dma_addr + ipd->width, ipd->regs + ODD_DMA_START);
2718c2ecf20Sopenharmony_ci		iowrite32(ipd->width, ipd->regs + EVEN_DMA_STRIDE);
2728c2ecf20Sopenharmony_ci		iowrite32(ipd->width, ipd->regs + ODD_DMA_STRIDE);
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	/* enable interrupts, clear all irq flags */
2768c2ecf20Sopenharmony_ci	iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
2778c2ecf20Sopenharmony_ci			FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR);
2788c2ecf20Sopenharmony_ci	spin_unlock(&ipd->lock);
2798c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations dt3155_fops = {
2838c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
2848c2ecf20Sopenharmony_ci	.open = v4l2_fh_open,
2858c2ecf20Sopenharmony_ci	.release = vb2_fop_release,
2868c2ecf20Sopenharmony_ci	.unlocked_ioctl = video_ioctl2,
2878c2ecf20Sopenharmony_ci	.read = vb2_fop_read,
2888c2ecf20Sopenharmony_ci	.mmap = vb2_fop_mmap,
2898c2ecf20Sopenharmony_ci	.poll = vb2_fop_poll
2908c2ecf20Sopenharmony_ci};
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic int dt3155_querycap(struct file *filp, void *p,
2938c2ecf20Sopenharmony_ci			   struct v4l2_capability *cap)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	struct dt3155_priv *pd = video_drvdata(filp);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	strscpy(cap->driver, DT3155_NAME, sizeof(cap->driver));
2988c2ecf20Sopenharmony_ci	strscpy(cap->card, DT3155_NAME " frame grabber", sizeof(cap->card));
2998c2ecf20Sopenharmony_ci	sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev));
3008c2ecf20Sopenharmony_ci	return 0;
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic int dt3155_enum_fmt_vid_cap(struct file *filp,
3048c2ecf20Sopenharmony_ci				   void *p, struct v4l2_fmtdesc *f)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	if (f->index)
3078c2ecf20Sopenharmony_ci		return -EINVAL;
3088c2ecf20Sopenharmony_ci	f->pixelformat = V4L2_PIX_FMT_GREY;
3098c2ecf20Sopenharmony_ci	return 0;
3108c2ecf20Sopenharmony_ci}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_cistatic int dt3155_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	struct dt3155_priv *pd = video_drvdata(filp);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	f->fmt.pix.width = pd->width;
3178c2ecf20Sopenharmony_ci	f->fmt.pix.height = pd->height;
3188c2ecf20Sopenharmony_ci	f->fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;
3198c2ecf20Sopenharmony_ci	f->fmt.pix.field = V4L2_FIELD_NONE;
3208c2ecf20Sopenharmony_ci	f->fmt.pix.bytesperline = f->fmt.pix.width;
3218c2ecf20Sopenharmony_ci	f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height;
3228c2ecf20Sopenharmony_ci	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
3238c2ecf20Sopenharmony_ci	return 0;
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_cistatic int dt3155_g_std(struct file *filp, void *p, v4l2_std_id *norm)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	struct dt3155_priv *pd = video_drvdata(filp);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	*norm = pd->std;
3318c2ecf20Sopenharmony_ci	return 0;
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic int dt3155_s_std(struct file *filp, void *p, v4l2_std_id norm)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	struct dt3155_priv *pd = video_drvdata(filp);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	if (pd->std == norm)
3398c2ecf20Sopenharmony_ci		return 0;
3408c2ecf20Sopenharmony_ci	if (vb2_is_busy(&pd->vidq))
3418c2ecf20Sopenharmony_ci		return -EBUSY;
3428c2ecf20Sopenharmony_ci	pd->std = norm;
3438c2ecf20Sopenharmony_ci	if (pd->std & V4L2_STD_525_60) {
3448c2ecf20Sopenharmony_ci		pd->csr2 = VT_60HZ;
3458c2ecf20Sopenharmony_ci		pd->width = 640;
3468c2ecf20Sopenharmony_ci		pd->height = 480;
3478c2ecf20Sopenharmony_ci	} else {
3488c2ecf20Sopenharmony_ci		pd->csr2 = VT_50HZ;
3498c2ecf20Sopenharmony_ci		pd->width = 768;
3508c2ecf20Sopenharmony_ci		pd->height = 576;
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci	return 0;
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic int dt3155_enum_input(struct file *filp, void *p,
3568c2ecf20Sopenharmony_ci			     struct v4l2_input *input)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	if (input->index > 3)
3598c2ecf20Sopenharmony_ci		return -EINVAL;
3608c2ecf20Sopenharmony_ci	if (input->index)
3618c2ecf20Sopenharmony_ci		snprintf(input->name, sizeof(input->name), "VID%d",
3628c2ecf20Sopenharmony_ci			 input->index);
3638c2ecf20Sopenharmony_ci	else
3648c2ecf20Sopenharmony_ci		strscpy(input->name, "J2/VID0", sizeof(input->name));
3658c2ecf20Sopenharmony_ci	input->type = V4L2_INPUT_TYPE_CAMERA;
3668c2ecf20Sopenharmony_ci	input->std = V4L2_STD_ALL;
3678c2ecf20Sopenharmony_ci	input->status = 0;
3688c2ecf20Sopenharmony_ci	return 0;
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cistatic int dt3155_g_input(struct file *filp, void *p, unsigned int *i)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	struct dt3155_priv *pd = video_drvdata(filp);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	*i = pd->input;
3768c2ecf20Sopenharmony_ci	return 0;
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic int dt3155_s_input(struct file *filp, void *p, unsigned int i)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	struct dt3155_priv *pd = video_drvdata(filp);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	if (i > 3)
3848c2ecf20Sopenharmony_ci		return -EINVAL;
3858c2ecf20Sopenharmony_ci	pd->input = i;
3868c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
3878c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, AD_CMD, (i << 6) | (i << 4) | SYNC_LVL_3);
3888c2ecf20Sopenharmony_ci	return 0;
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops dt3155_ioctl_ops = {
3928c2ecf20Sopenharmony_ci	.vidioc_querycap = dt3155_querycap,
3938c2ecf20Sopenharmony_ci	.vidioc_enum_fmt_vid_cap = dt3155_enum_fmt_vid_cap,
3948c2ecf20Sopenharmony_ci	.vidioc_try_fmt_vid_cap = dt3155_fmt_vid_cap,
3958c2ecf20Sopenharmony_ci	.vidioc_g_fmt_vid_cap = dt3155_fmt_vid_cap,
3968c2ecf20Sopenharmony_ci	.vidioc_s_fmt_vid_cap = dt3155_fmt_vid_cap,
3978c2ecf20Sopenharmony_ci	.vidioc_reqbufs = vb2_ioctl_reqbufs,
3988c2ecf20Sopenharmony_ci	.vidioc_create_bufs = vb2_ioctl_create_bufs,
3998c2ecf20Sopenharmony_ci	.vidioc_querybuf = vb2_ioctl_querybuf,
4008c2ecf20Sopenharmony_ci	.vidioc_expbuf = vb2_ioctl_expbuf,
4018c2ecf20Sopenharmony_ci	.vidioc_qbuf = vb2_ioctl_qbuf,
4028c2ecf20Sopenharmony_ci	.vidioc_dqbuf = vb2_ioctl_dqbuf,
4038c2ecf20Sopenharmony_ci	.vidioc_streamon = vb2_ioctl_streamon,
4048c2ecf20Sopenharmony_ci	.vidioc_streamoff = vb2_ioctl_streamoff,
4058c2ecf20Sopenharmony_ci	.vidioc_g_std = dt3155_g_std,
4068c2ecf20Sopenharmony_ci	.vidioc_s_std = dt3155_s_std,
4078c2ecf20Sopenharmony_ci	.vidioc_enum_input = dt3155_enum_input,
4088c2ecf20Sopenharmony_ci	.vidioc_g_input = dt3155_g_input,
4098c2ecf20Sopenharmony_ci	.vidioc_s_input = dt3155_s_input,
4108c2ecf20Sopenharmony_ci};
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic int dt3155_init_board(struct dt3155_priv *pd)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	struct pci_dev *pdev = pd->pdev;
4158c2ecf20Sopenharmony_ci	int i;
4168c2ecf20Sopenharmony_ci	u8 tmp = 0;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	pci_set_master(pdev); /* dt3155 needs it */
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	/*  resetting the adapter  */
4218c2ecf20Sopenharmony_ci	iowrite32(ADDR_ERR_ODD | ADDR_ERR_EVEN | FLD_CRPT_ODD | FLD_CRPT_EVEN |
4228c2ecf20Sopenharmony_ci			FLD_DN_ODD | FLD_DN_EVEN, pd->regs + CSR1);
4238c2ecf20Sopenharmony_ci	msleep(20);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	/*  initializing adapter registers  */
4268c2ecf20Sopenharmony_ci	iowrite32(FIFO_EN | SRST, pd->regs + CSR1);
4278c2ecf20Sopenharmony_ci	iowrite32(0xEEEEEE01, pd->regs + EVEN_PIXEL_FMT);
4288c2ecf20Sopenharmony_ci	iowrite32(0xEEEEEE01, pd->regs + ODD_PIXEL_FMT);
4298c2ecf20Sopenharmony_ci	iowrite32(0x00000020, pd->regs + FIFO_TRIGGER);
4308c2ecf20Sopenharmony_ci	iowrite32(0x00000103, pd->regs + XFER_MODE);
4318c2ecf20Sopenharmony_ci	iowrite32(0, pd->regs + RETRY_WAIT_CNT);
4328c2ecf20Sopenharmony_ci	iowrite32(0, pd->regs + INT_CSR);
4338c2ecf20Sopenharmony_ci	iowrite32(1, pd->regs + EVEN_FLD_MASK);
4348c2ecf20Sopenharmony_ci	iowrite32(1, pd->regs + ODD_FLD_MASK);
4358c2ecf20Sopenharmony_ci	iowrite32(0, pd->regs + MASK_LENGTH);
4368c2ecf20Sopenharmony_ci	iowrite32(0x0005007C, pd->regs + FIFO_FLAG_CNT);
4378c2ecf20Sopenharmony_ci	iowrite32(0x01010101, pd->regs + IIC_CLK_DUR);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	/* verifying that we have a DT3155 board (not just a SAA7116 chip) */
4408c2ecf20Sopenharmony_ci	read_i2c_reg(pd->regs, DT_ID, &tmp);
4418c2ecf20Sopenharmony_ci	if (tmp != DT3155_ID)
4428c2ecf20Sopenharmony_ci		return -ENODEV;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	/* initialize AD LUT */
4458c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, AD_ADDR, 0);
4468c2ecf20Sopenharmony_ci	for (i = 0; i < 256; i++)
4478c2ecf20Sopenharmony_ci		write_i2c_reg(pd->regs, AD_LUT, i);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	/* initialize ADC references */
4508c2ecf20Sopenharmony_ci	/* FIXME: pos_ref & neg_ref depend on VT_50HZ */
4518c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
4528c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);
4538c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, AD_ADDR, AD_POS_REF);
4548c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, AD_CMD, 34);
4558c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, AD_ADDR, AD_NEG_REF);
4568c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, AD_CMD, 0);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	/* initialize PM LUT */
4598c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM);
4608c2ecf20Sopenharmony_ci	for (i = 0; i < 256; i++) {
4618c2ecf20Sopenharmony_ci		write_i2c_reg(pd->regs, PM_LUT_ADDR, i);
4628c2ecf20Sopenharmony_ci		write_i2c_reg(pd->regs, PM_LUT_DATA, i);
4638c2ecf20Sopenharmony_ci	}
4648c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM | PM_LUT_SEL);
4658c2ecf20Sopenharmony_ci	for (i = 0; i < 256; i++) {
4668c2ecf20Sopenharmony_ci		write_i2c_reg(pd->regs, PM_LUT_ADDR, i);
4678c2ecf20Sopenharmony_ci		write_i2c_reg(pd->regs, PM_LUT_DATA, i);
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, CONFIG, pd->config); /*  ACQ_MODE_EVEN  */
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	/* select channel 1 for input and set sync level */
4728c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
4738c2ecf20Sopenharmony_ci	write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	/* disable all irqs, clear all irq flags */
4768c2ecf20Sopenharmony_ci	iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD,
4778c2ecf20Sopenharmony_ci			pd->regs + INT_CSR);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	return 0;
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_cistatic const struct video_device dt3155_vdev = {
4838c2ecf20Sopenharmony_ci	.name = DT3155_NAME,
4848c2ecf20Sopenharmony_ci	.fops = &dt3155_fops,
4858c2ecf20Sopenharmony_ci	.ioctl_ops = &dt3155_ioctl_ops,
4868c2ecf20Sopenharmony_ci	.minor = -1,
4878c2ecf20Sopenharmony_ci	.release = video_device_release_empty,
4888c2ecf20Sopenharmony_ci	.tvnorms = V4L2_STD_ALL,
4898c2ecf20Sopenharmony_ci	.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
4908c2ecf20Sopenharmony_ci		       V4L2_CAP_READWRITE,
4918c2ecf20Sopenharmony_ci};
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_cistatic int dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4948c2ecf20Sopenharmony_ci{
4958c2ecf20Sopenharmony_ci	int err;
4968c2ecf20Sopenharmony_ci	struct dt3155_priv *pd;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
4998c2ecf20Sopenharmony_ci	if (err)
5008c2ecf20Sopenharmony_ci		return -ENODEV;
5018c2ecf20Sopenharmony_ci	pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL);
5028c2ecf20Sopenharmony_ci	if (!pd)
5038c2ecf20Sopenharmony_ci		return -ENOMEM;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	err = v4l2_device_register(&pdev->dev, &pd->v4l2_dev);
5068c2ecf20Sopenharmony_ci	if (err)
5078c2ecf20Sopenharmony_ci		return err;
5088c2ecf20Sopenharmony_ci	pd->vdev = dt3155_vdev;
5098c2ecf20Sopenharmony_ci	pd->vdev.v4l2_dev = &pd->v4l2_dev;
5108c2ecf20Sopenharmony_ci	video_set_drvdata(&pd->vdev, pd);  /* for use in video_fops */
5118c2ecf20Sopenharmony_ci	pd->pdev = pdev;
5128c2ecf20Sopenharmony_ci	pd->std = V4L2_STD_625_50;
5138c2ecf20Sopenharmony_ci	pd->csr2 = VT_50HZ;
5148c2ecf20Sopenharmony_ci	pd->width = 768;
5158c2ecf20Sopenharmony_ci	pd->height = 576;
5168c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&pd->dmaq);
5178c2ecf20Sopenharmony_ci	mutex_init(&pd->mux);
5188c2ecf20Sopenharmony_ci	pd->vdev.lock = &pd->mux; /* for locking v4l2_file_operations */
5198c2ecf20Sopenharmony_ci	pd->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
5208c2ecf20Sopenharmony_ci	pd->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
5218c2ecf20Sopenharmony_ci	pd->vidq.io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
5228c2ecf20Sopenharmony_ci	pd->vidq.ops = &q_ops;
5238c2ecf20Sopenharmony_ci	pd->vidq.mem_ops = &vb2_dma_contig_memops;
5248c2ecf20Sopenharmony_ci	pd->vidq.drv_priv = pd;
5258c2ecf20Sopenharmony_ci	pd->vidq.min_buffers_needed = 2;
5268c2ecf20Sopenharmony_ci	pd->vidq.gfp_flags = GFP_DMA32;
5278c2ecf20Sopenharmony_ci	pd->vidq.lock = &pd->mux; /* for locking v4l2_file_operations */
5288c2ecf20Sopenharmony_ci	pd->vidq.dev = &pdev->dev;
5298c2ecf20Sopenharmony_ci	pd->vdev.queue = &pd->vidq;
5308c2ecf20Sopenharmony_ci	err = vb2_queue_init(&pd->vidq);
5318c2ecf20Sopenharmony_ci	if (err < 0)
5328c2ecf20Sopenharmony_ci		goto err_v4l2_dev_unreg;
5338c2ecf20Sopenharmony_ci	spin_lock_init(&pd->lock);
5348c2ecf20Sopenharmony_ci	pd->config = ACQ_MODE_EVEN;
5358c2ecf20Sopenharmony_ci	err = pci_enable_device(pdev);
5368c2ecf20Sopenharmony_ci	if (err)
5378c2ecf20Sopenharmony_ci		goto err_v4l2_dev_unreg;
5388c2ecf20Sopenharmony_ci	err = pci_request_region(pdev, 0, pci_name(pdev));
5398c2ecf20Sopenharmony_ci	if (err)
5408c2ecf20Sopenharmony_ci		goto err_pci_disable;
5418c2ecf20Sopenharmony_ci	pd->regs = pci_iomap(pdev, 0, pci_resource_len(pd->pdev, 0));
5428c2ecf20Sopenharmony_ci	if (!pd->regs) {
5438c2ecf20Sopenharmony_ci		err = -ENOMEM;
5448c2ecf20Sopenharmony_ci		goto err_free_reg;
5458c2ecf20Sopenharmony_ci	}
5468c2ecf20Sopenharmony_ci	err = dt3155_init_board(pd);
5478c2ecf20Sopenharmony_ci	if (err)
5488c2ecf20Sopenharmony_ci		goto err_iounmap;
5498c2ecf20Sopenharmony_ci	err = request_irq(pd->pdev->irq, dt3155_irq_handler_even,
5508c2ecf20Sopenharmony_ci					IRQF_SHARED, DT3155_NAME, pd);
5518c2ecf20Sopenharmony_ci	if (err)
5528c2ecf20Sopenharmony_ci		goto err_iounmap;
5538c2ecf20Sopenharmony_ci	err = video_register_device(&pd->vdev, VFL_TYPE_VIDEO, -1);
5548c2ecf20Sopenharmony_ci	if (err)
5558c2ecf20Sopenharmony_ci		goto err_free_irq;
5568c2ecf20Sopenharmony_ci	dev_info(&pdev->dev, "/dev/video%i is ready\n", pd->vdev.minor);
5578c2ecf20Sopenharmony_ci	return 0;  /*   success   */
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_cierr_free_irq:
5608c2ecf20Sopenharmony_ci	free_irq(pd->pdev->irq, pd);
5618c2ecf20Sopenharmony_cierr_iounmap:
5628c2ecf20Sopenharmony_ci	pci_iounmap(pdev, pd->regs);
5638c2ecf20Sopenharmony_cierr_free_reg:
5648c2ecf20Sopenharmony_ci	pci_release_region(pdev, 0);
5658c2ecf20Sopenharmony_cierr_pci_disable:
5668c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
5678c2ecf20Sopenharmony_cierr_v4l2_dev_unreg:
5688c2ecf20Sopenharmony_ci	v4l2_device_unregister(&pd->v4l2_dev);
5698c2ecf20Sopenharmony_ci	return err;
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_cistatic void dt3155_remove(struct pci_dev *pdev)
5738c2ecf20Sopenharmony_ci{
5748c2ecf20Sopenharmony_ci	struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
5758c2ecf20Sopenharmony_ci	struct dt3155_priv *pd = container_of(v4l2_dev, struct dt3155_priv,
5768c2ecf20Sopenharmony_ci					      v4l2_dev);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	vb2_video_unregister_device(&pd->vdev);
5798c2ecf20Sopenharmony_ci	free_irq(pd->pdev->irq, pd);
5808c2ecf20Sopenharmony_ci	v4l2_device_unregister(&pd->v4l2_dev);
5818c2ecf20Sopenharmony_ci	pci_iounmap(pdev, pd->regs);
5828c2ecf20Sopenharmony_ci	pci_release_region(pdev, 0);
5838c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
5848c2ecf20Sopenharmony_ci}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cistatic const struct pci_device_id pci_ids[] = {
5878c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, DT3155_DEVICE_ID) },
5888c2ecf20Sopenharmony_ci	{ 0, /* zero marks the end */ },
5898c2ecf20Sopenharmony_ci};
5908c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pci_ids);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_cistatic struct pci_driver pci_driver = {
5938c2ecf20Sopenharmony_ci	.name = DT3155_NAME,
5948c2ecf20Sopenharmony_ci	.id_table = pci_ids,
5958c2ecf20Sopenharmony_ci	.probe = dt3155_probe,
5968c2ecf20Sopenharmony_ci	.remove = dt3155_remove,
5978c2ecf20Sopenharmony_ci};
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_cimodule_pci_driver(pci_driver);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("video4linux pci-driver for dt3155 frame grabber");
6028c2ecf20Sopenharmony_ciMODULE_AUTHOR("Marin Mitov <mitov@issp.bas.bg>");
6038c2ecf20Sopenharmony_ciMODULE_VERSION(DT3155_VERSION);
6048c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
605