18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * device driver for philips saa7134 based TV cards
58c2ecf20Sopenharmony_ci * video4linux video interface
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "saa7134.h"
118c2ecf20Sopenharmony_ci#include "saa7134-reg.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/list.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/kernel.h>
178c2ecf20Sopenharmony_ci#include <linux/delay.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic unsigned int ts_debug;
228c2ecf20Sopenharmony_cimodule_param(ts_debug, int, 0644);
238c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ts_debug,"enable debug messages [ts]");
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define ts_dbg(fmt, arg...) do { \
268c2ecf20Sopenharmony_ci	if (ts_debug) \
278c2ecf20Sopenharmony_ci		printk(KERN_DEBUG pr_fmt("ts: " fmt), ## arg); \
288c2ecf20Sopenharmony_ci	} while (0)
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */
318c2ecf20Sopenharmony_cistatic int buffer_activate(struct saa7134_dev *dev,
328c2ecf20Sopenharmony_ci			   struct saa7134_buf *buf,
338c2ecf20Sopenharmony_ci			   struct saa7134_buf *next)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	ts_dbg("buffer_activate [%p]", buf);
378c2ecf20Sopenharmony_ci	buf->top_seen = 0;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	if (!dev->ts_started)
408c2ecf20Sopenharmony_ci		dev->ts_field = V4L2_FIELD_TOP;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	if (NULL == next)
438c2ecf20Sopenharmony_ci		next = buf;
448c2ecf20Sopenharmony_ci	if (V4L2_FIELD_TOP == dev->ts_field) {
458c2ecf20Sopenharmony_ci		ts_dbg("- [top]     buf=%p next=%p\n", buf, next);
468c2ecf20Sopenharmony_ci		saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(buf));
478c2ecf20Sopenharmony_ci		saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(next));
488c2ecf20Sopenharmony_ci		dev->ts_field = V4L2_FIELD_BOTTOM;
498c2ecf20Sopenharmony_ci	} else {
508c2ecf20Sopenharmony_ci		ts_dbg("- [bottom]  buf=%p next=%p\n", buf, next);
518c2ecf20Sopenharmony_ci		saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next));
528c2ecf20Sopenharmony_ci		saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf));
538c2ecf20Sopenharmony_ci		dev->ts_field = V4L2_FIELD_TOP;
548c2ecf20Sopenharmony_ci	}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	/* start DMA */
578c2ecf20Sopenharmony_ci	saa7134_set_dmabits(dev);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	mod_timer(&dev->ts_q.timeout, jiffies+TS_BUFFER_TIMEOUT);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	if (!dev->ts_started)
628c2ecf20Sopenharmony_ci		saa7134_ts_start(dev);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	return 0;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ciint saa7134_ts_buffer_init(struct vb2_buffer *vb2)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
708c2ecf20Sopenharmony_ci	struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
718c2ecf20Sopenharmony_ci	struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	dmaq->curr = NULL;
748c2ecf20Sopenharmony_ci	buf->activate = buffer_activate;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	return 0;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(saa7134_ts_buffer_init);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ciint saa7134_ts_buffer_prepare(struct vb2_buffer *vb2)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
838c2ecf20Sopenharmony_ci	struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
848c2ecf20Sopenharmony_ci	struct saa7134_dev *dev = dmaq->dev;
858c2ecf20Sopenharmony_ci	struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2);
868c2ecf20Sopenharmony_ci	struct sg_table *dma = vb2_dma_sg_plane_desc(vb2, 0);
878c2ecf20Sopenharmony_ci	unsigned int lines, llength, size;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	ts_dbg("buffer_prepare [%p]\n", buf);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	llength = TS_PACKET_SIZE;
928c2ecf20Sopenharmony_ci	lines = dev->ts.nr_packets;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	size = lines * llength;
958c2ecf20Sopenharmony_ci	if (vb2_plane_size(vb2, 0) < size)
968c2ecf20Sopenharmony_ci		return -EINVAL;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	vb2_set_plane_payload(vb2, 0, size);
998c2ecf20Sopenharmony_ci	vbuf->field = dev->field;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents,
1028c2ecf20Sopenharmony_ci				    saa7134_buffer_startpage(buf));
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(saa7134_ts_buffer_prepare);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ciint saa7134_ts_queue_setup(struct vb2_queue *q,
1078c2ecf20Sopenharmony_ci			   unsigned int *nbuffers, unsigned int *nplanes,
1088c2ecf20Sopenharmony_ci			   unsigned int sizes[], struct device *alloc_devs[])
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct saa7134_dmaqueue *dmaq = q->drv_priv;
1118c2ecf20Sopenharmony_ci	struct saa7134_dev *dev = dmaq->dev;
1128c2ecf20Sopenharmony_ci	int size = TS_PACKET_SIZE * dev->ts.nr_packets;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	if (0 == *nbuffers)
1158c2ecf20Sopenharmony_ci		*nbuffers = dev->ts.nr_bufs;
1168c2ecf20Sopenharmony_ci	*nbuffers = saa7134_buffer_count(size, *nbuffers);
1178c2ecf20Sopenharmony_ci	if (*nbuffers < 3)
1188c2ecf20Sopenharmony_ci		*nbuffers = 3;
1198c2ecf20Sopenharmony_ci	*nplanes = 1;
1208c2ecf20Sopenharmony_ci	sizes[0] = size;
1218c2ecf20Sopenharmony_ci	return 0;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(saa7134_ts_queue_setup);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ciint saa7134_ts_start_streaming(struct vb2_queue *vq, unsigned int count)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct saa7134_dmaqueue *dmaq = vq->drv_priv;
1288c2ecf20Sopenharmony_ci	struct saa7134_dev *dev = dmaq->dev;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	/*
1318c2ecf20Sopenharmony_ci	 * Planar video capture and TS share the same DMA channel,
1328c2ecf20Sopenharmony_ci	 * so only one can be active at a time.
1338c2ecf20Sopenharmony_ci	 */
1348c2ecf20Sopenharmony_ci	if (vb2_is_busy(&dev->video_vbq) && dev->fmt->planar) {
1358c2ecf20Sopenharmony_ci		struct saa7134_buf *buf, *tmp;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci		list_for_each_entry_safe(buf, tmp, &dmaq->queue, entry) {
1388c2ecf20Sopenharmony_ci			list_del(&buf->entry);
1398c2ecf20Sopenharmony_ci			vb2_buffer_done(&buf->vb2.vb2_buf,
1408c2ecf20Sopenharmony_ci					VB2_BUF_STATE_QUEUED);
1418c2ecf20Sopenharmony_ci		}
1428c2ecf20Sopenharmony_ci		if (dmaq->curr) {
1438c2ecf20Sopenharmony_ci			vb2_buffer_done(&dmaq->curr->vb2.vb2_buf,
1448c2ecf20Sopenharmony_ci					VB2_BUF_STATE_QUEUED);
1458c2ecf20Sopenharmony_ci			dmaq->curr = NULL;
1468c2ecf20Sopenharmony_ci		}
1478c2ecf20Sopenharmony_ci		return -EBUSY;
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci	dmaq->seq_nr = 0;
1508c2ecf20Sopenharmony_ci	return 0;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(saa7134_ts_start_streaming);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_civoid saa7134_ts_stop_streaming(struct vb2_queue *vq)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	struct saa7134_dmaqueue *dmaq = vq->drv_priv;
1578c2ecf20Sopenharmony_ci	struct saa7134_dev *dev = dmaq->dev;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	saa7134_ts_stop(dev);
1608c2ecf20Sopenharmony_ci	saa7134_stop_streaming(dev, dmaq);
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(saa7134_ts_stop_streaming);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistruct vb2_ops saa7134_ts_qops = {
1658c2ecf20Sopenharmony_ci	.queue_setup	= saa7134_ts_queue_setup,
1668c2ecf20Sopenharmony_ci	.buf_init	= saa7134_ts_buffer_init,
1678c2ecf20Sopenharmony_ci	.buf_prepare	= saa7134_ts_buffer_prepare,
1688c2ecf20Sopenharmony_ci	.buf_queue	= saa7134_vb2_buffer_queue,
1698c2ecf20Sopenharmony_ci	.wait_prepare	= vb2_ops_wait_prepare,
1708c2ecf20Sopenharmony_ci	.wait_finish	= vb2_ops_wait_finish,
1718c2ecf20Sopenharmony_ci	.stop_streaming = saa7134_ts_stop_streaming,
1728c2ecf20Sopenharmony_ci};
1738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(saa7134_ts_qops);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci/* ----------------------------------------------------------- */
1768c2ecf20Sopenharmony_ci/* exported stuff                                              */
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic unsigned int tsbufs = 8;
1798c2ecf20Sopenharmony_cimodule_param(tsbufs, int, 0444);
1808c2ecf20Sopenharmony_ciMODULE_PARM_DESC(tsbufs, "number of ts buffers for read/write IO, range 2-32");
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic unsigned int ts_nr_packets = 64;
1838c2ecf20Sopenharmony_cimodule_param(ts_nr_packets, int, 0444);
1848c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)");
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ciint saa7134_ts_init_hw(struct saa7134_dev *dev)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	/* deactivate TS softreset */
1898c2ecf20Sopenharmony_ci	saa_writeb(SAA7134_TS_SERIAL1, 0x00);
1908c2ecf20Sopenharmony_ci	/* TSSOP high active, TSVAL high active, TSLOCK ignored */
1918c2ecf20Sopenharmony_ci	saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
1928c2ecf20Sopenharmony_ci	saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1));
1938c2ecf20Sopenharmony_ci	saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff));
1948c2ecf20Sopenharmony_ci	saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff));
1958c2ecf20Sopenharmony_ci	/* TSNOPIT=0, TSCOLAP=0 */
1968c2ecf20Sopenharmony_ci	saa_writeb(SAA7134_TS_DMA2,
1978c2ecf20Sopenharmony_ci		((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00));
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	return 0;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ciint saa7134_ts_init1(struct saa7134_dev *dev)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	/* sanitycheck insmod options */
2058c2ecf20Sopenharmony_ci	if (tsbufs < 2)
2068c2ecf20Sopenharmony_ci		tsbufs = 2;
2078c2ecf20Sopenharmony_ci	if (tsbufs > VIDEO_MAX_FRAME)
2088c2ecf20Sopenharmony_ci		tsbufs = VIDEO_MAX_FRAME;
2098c2ecf20Sopenharmony_ci	if (ts_nr_packets < 4)
2108c2ecf20Sopenharmony_ci		ts_nr_packets = 4;
2118c2ecf20Sopenharmony_ci	if (ts_nr_packets > 312)
2128c2ecf20Sopenharmony_ci		ts_nr_packets = 312;
2138c2ecf20Sopenharmony_ci	dev->ts.nr_bufs    = tsbufs;
2148c2ecf20Sopenharmony_ci	dev->ts.nr_packets = ts_nr_packets;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dev->ts_q.queue);
2178c2ecf20Sopenharmony_ci	timer_setup(&dev->ts_q.timeout, saa7134_buffer_timeout, 0);
2188c2ecf20Sopenharmony_ci	dev->ts_q.dev              = dev;
2198c2ecf20Sopenharmony_ci	dev->ts_q.need_two         = 1;
2208c2ecf20Sopenharmony_ci	dev->ts_started            = 0;
2218c2ecf20Sopenharmony_ci	saa7134_pgtable_alloc(dev->pci, &dev->ts_q.pt);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	/* init TS hw */
2248c2ecf20Sopenharmony_ci	saa7134_ts_init_hw(dev);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	return 0;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci/* Function for stop TS */
2308c2ecf20Sopenharmony_ciint saa7134_ts_stop(struct saa7134_dev *dev)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	ts_dbg("TS stop\n");
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	if (!dev->ts_started)
2358c2ecf20Sopenharmony_ci		return 0;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	/* Stop TS stream */
2388c2ecf20Sopenharmony_ci	switch (saa7134_boards[dev->board].ts_type) {
2398c2ecf20Sopenharmony_ci	case SAA7134_MPEG_TS_PARALLEL:
2408c2ecf20Sopenharmony_ci		saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
2418c2ecf20Sopenharmony_ci		dev->ts_started = 0;
2428c2ecf20Sopenharmony_ci		break;
2438c2ecf20Sopenharmony_ci	case SAA7134_MPEG_TS_SERIAL:
2448c2ecf20Sopenharmony_ci		saa_writeb(SAA7134_TS_SERIAL0, 0x40);
2458c2ecf20Sopenharmony_ci		dev->ts_started = 0;
2468c2ecf20Sopenharmony_ci		break;
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci	return 0;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci/* Function for start TS */
2528c2ecf20Sopenharmony_ciint saa7134_ts_start(struct saa7134_dev *dev)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	ts_dbg("TS start\n");
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	if (WARN_ON(dev->ts_started))
2578c2ecf20Sopenharmony_ci		return 0;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	/* dma: setup channel 5 (= TS) */
2608c2ecf20Sopenharmony_ci	saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff);
2618c2ecf20Sopenharmony_ci	saa_writeb(SAA7134_TS_DMA1,
2628c2ecf20Sopenharmony_ci		((dev->ts.nr_packets - 1) >> 8) & 0xff);
2638c2ecf20Sopenharmony_ci	/* TSNOPIT=0, TSCOLAP=0 */
2648c2ecf20Sopenharmony_ci	saa_writeb(SAA7134_TS_DMA2,
2658c2ecf20Sopenharmony_ci		(((dev->ts.nr_packets - 1) >> 16) & 0x3f) | 0x00);
2668c2ecf20Sopenharmony_ci	saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE);
2678c2ecf20Sopenharmony_ci	saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_16 |
2688c2ecf20Sopenharmony_ci					  SAA7134_RS_CONTROL_ME |
2698c2ecf20Sopenharmony_ci					  (dev->ts_q.pt.dma >> 12));
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	/* reset hardware TS buffers */
2728c2ecf20Sopenharmony_ci	saa_writeb(SAA7134_TS_SERIAL1, 0x00);
2738c2ecf20Sopenharmony_ci	saa_writeb(SAA7134_TS_SERIAL1, 0x03);
2748c2ecf20Sopenharmony_ci	saa_writeb(SAA7134_TS_SERIAL1, 0x00);
2758c2ecf20Sopenharmony_ci	saa_writeb(SAA7134_TS_SERIAL1, 0x01);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	/* TS clock non-inverted */
2788c2ecf20Sopenharmony_ci	saa_writeb(SAA7134_TS_SERIAL1, 0x00);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	/* Start TS stream */
2818c2ecf20Sopenharmony_ci	switch (saa7134_boards[dev->board].ts_type) {
2828c2ecf20Sopenharmony_ci	case SAA7134_MPEG_TS_PARALLEL:
2838c2ecf20Sopenharmony_ci		saa_writeb(SAA7134_TS_SERIAL0, 0x40);
2848c2ecf20Sopenharmony_ci		saa_writeb(SAA7134_TS_PARALLEL, 0xec |
2858c2ecf20Sopenharmony_ci			(saa7134_boards[dev->board].ts_force_val << 4));
2868c2ecf20Sopenharmony_ci		break;
2878c2ecf20Sopenharmony_ci	case SAA7134_MPEG_TS_SERIAL:
2888c2ecf20Sopenharmony_ci		saa_writeb(SAA7134_TS_SERIAL0, 0xd8);
2898c2ecf20Sopenharmony_ci		saa_writeb(SAA7134_TS_PARALLEL, 0x6c |
2908c2ecf20Sopenharmony_ci			(saa7134_boards[dev->board].ts_force_val << 4));
2918c2ecf20Sopenharmony_ci		saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 0xbc);
2928c2ecf20Sopenharmony_ci		saa_writeb(SAA7134_TS_SERIAL1, 0x02);
2938c2ecf20Sopenharmony_ci		break;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	dev->ts_started = 1;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	return 0;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ciint saa7134_ts_fini(struct saa7134_dev *dev)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	del_timer_sync(&dev->ts_q.timeout);
3048c2ecf20Sopenharmony_ci	saa7134_pgtable_free(dev->pci, &dev->ts_q.pt);
3058c2ecf20Sopenharmony_ci	return 0;
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_civoid saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	enum v4l2_field field;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	spin_lock(&dev->slock);
3138c2ecf20Sopenharmony_ci	if (dev->ts_q.curr) {
3148c2ecf20Sopenharmony_ci		field = dev->ts_field;
3158c2ecf20Sopenharmony_ci		if (field != V4L2_FIELD_TOP) {
3168c2ecf20Sopenharmony_ci			if ((status & 0x100000) != 0x000000)
3178c2ecf20Sopenharmony_ci				goto done;
3188c2ecf20Sopenharmony_ci		} else {
3198c2ecf20Sopenharmony_ci			if ((status & 0x100000) != 0x100000)
3208c2ecf20Sopenharmony_ci				goto done;
3218c2ecf20Sopenharmony_ci		}
3228c2ecf20Sopenharmony_ci		saa7134_buffer_finish(dev, &dev->ts_q, VB2_BUF_STATE_DONE);
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci	saa7134_buffer_next(dev,&dev->ts_q);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci done:
3278c2ecf20Sopenharmony_ci	spin_unlock(&dev->slock);
3288c2ecf20Sopenharmony_ci}
329