11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    saa7146.o - driver for generic saa7146-based hardware
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is free software; you can redistribute it and/or modify
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    it under the terms of the GNU General Public License as published by
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    the Free Software Foundation; either version 2 of the License, or
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    (at your option) any later version.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is distributed in the hope that it will be useful,
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    but WITHOUT ANY WARRANTY; without even the implied warranty of
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    GNU General Public License for more details.
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    You should have received a copy of the GNU General Public License
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    along with this program; if not, write to the Free Software
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2144d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2244d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <media/saa7146.h>
247a707b89202f905bd9f9fbde326933c59a81214cPaul Gortmaker#include <linux/module.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsLIST_HEAD(saa7146_devices);
273593cab5d62c4c7abced1076710f9bc2d8847433Ingo MolnarDEFINE_MUTEX(saa7146_devices_lock);
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29c2c62d81430e907b6599d4be43a7ee6f74d2bd69Johannes Stezenbachstatic int saa7146_num;
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31c2c62d81430e907b6599d4be43a7ee6f74d2bd69Johannes Stezenbachunsigned int saa7146_debug;
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33804b4458943f14bf144d3c3ba50097ced9b27b29Oliver Endrissmodule_param(saa7146_debug, uint, 0644);
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dump_registers(struct saa7146_dev* dev)
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 0;
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4144d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches	pr_info(" @ %li jiffies:\n", jiffies);
4244d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches	for (i = 0; i <= 0x148; i += 4)
4344d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches		pr_info("0x%03x: 0x%08x\n", i, saa7146_read(dev, i));
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/****************************************************************************
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * gpio and debi helper functions
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ****************************************************************************/
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 value = 0;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON(port > 3);
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	value = saa7146_read(dev, GPIO_CTRL);
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	value &= ~(0xff << (8*port));
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	value |= (data << (8*port));
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_write(dev, GPIO_CTRL, value);
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */
6426ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endrissstatic inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,
6526ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss				unsigned long us1, unsigned long us2)
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6726ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss	unsigned long timeout;
6825de192660627e1e8dc8ee6a120ff8b54d108593Oliver Endriss	int err;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* wait for registers to be programmed */
7126ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss	timeout = jiffies + usecs_to_jiffies(us1);
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (1) {
7326ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss		err = time_after(jiffies, timeout);
7425de192660627e1e8dc8ee6a120ff8b54d108593Oliver Endriss		if (saa7146_read(dev, MC2) & 2)
7525de192660627e1e8dc8ee6a120ff8b54d108593Oliver Endriss			break;
7625de192660627e1e8dc8ee6a120ff8b54d108593Oliver Endriss		if (err) {
7744d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches			pr_err("%s: %s timed out while waiting for registers getting programmed\n",
7844d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches			       dev->name, __func__);
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ETIMEDOUT;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8126ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss		msleep(1);
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* wait for transfer to complete */
8526ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss	timeout = jiffies + usecs_to_jiffies(us2);
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (1) {
8726ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss		err = time_after(jiffies, timeout);
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		saa7146_read(dev, MC2);
9125de192660627e1e8dc8ee6a120ff8b54d108593Oliver Endriss		if (err) {
9244d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches			DEB_S("%s: %s timed out while waiting for transfer completion\n",
9344d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches			      dev->name, __func__);
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ETIMEDOUT;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9626ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss		msleep(1);
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10226ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endrissstatic inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev,
10326ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss				unsigned long us1, unsigned long us2)
10426ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss{
10526ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss	unsigned long loops;
10626ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss
10726ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss	/* wait for registers to be programmed */
10826ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss	loops = us1;
10926ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss	while (1) {
11026ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss		if (saa7146_read(dev, MC2) & 2)
11126ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss			break;
11226ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss		if (!loops--) {
11344d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches			pr_err("%s: %s timed out while waiting for registers getting programmed\n",
11444d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches			       dev->name, __func__);
11526ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss			return -ETIMEDOUT;
11626ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss		}
11726ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss		udelay(1);
11826ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss	}
11926ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss
12026ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss	/* wait for transfer to complete */
12126ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss	loops = us2 / 5;
12226ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss	while (1) {
12326ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss		if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
12426ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss			break;
12526ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss		saa7146_read(dev, MC2);
12626ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss		if (!loops--) {
12744d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches			DEB_S("%s: %s timed out while waiting for transfer completion\n",
12844d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches			      dev->name, __func__);
12926ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss			return -ETIMEDOUT;
13026ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss		}
13126ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss		udelay(5);
13226ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss	}
13326ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss
13426ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss	return 0;
13526ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss}
13626ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss
13726ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endrissint saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
13826ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss{
13926ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss	if (nobusyloop)
14026ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss		return saa7146_wait_for_debi_done_sleep(dev, 50000, 250000);
14126ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss	else
14226ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss		return saa7146_wait_for_debi_done_busyloop(dev, 50000, 250000);
14326ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss}
14426ac14e24f3c84ed7a619639c2027f03b52bd64bOliver Endriss
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/****************************************************************************
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * general helper functions
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ****************************************************************************/
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
149c1accaa21bdef38ec0f36eaaf7ce3384fff9d0c5Mauro Carvalho Chehab/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   make sure virt has been allocated with vmalloc_32(), otherwise the BUG()
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   may be triggered on highmem machines */
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scatterlist *sglist;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct page *pg;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1587408187d223f63d46a13b6a35b8f96b032c2f623Panagiotis Issaris	sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (NULL == sglist)
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
16145711f1af6eff1a6d010703b4862e0d2b9afd056Jens Axboe	sg_init_table(sglist, nr_pages);
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pg = vmalloc_to_page(virt);
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (NULL == pg)
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err;
166ae24601b47c3f4a56545ef4cd4e7c821ac1db598Eric Sesterhenn		BUG_ON(PageHighMem(pg));
167642f149031d70415d9318b919d50b71e4724adbdJens Axboe		sg_set_page(&sglist[i], pg, PAGE_SIZE, 0);
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sglist;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err:
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(sglist);
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********************************************************************************/
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* common page table functions */
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
179804b4458943f14bf144d3c3ba50097ced9b27b29Oliver Endrissvoid *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
182804b4458943f14bf144d3c3ba50097ced9b27b29Oliver Endriss	void *mem = vmalloc_32(length);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int slen = 0;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18587c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	if (NULL == mem)
18687c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess		goto err_null;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18887c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	if (!(pt->slist = vmalloc_to_sg(mem, pages)))
18987c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess		goto err_free_mem;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19187c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	if (saa7146_pgtable_alloc(pci, pt))
19287c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess		goto err_free_slist;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19487c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	pt->nents = pages;
19587c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE);
19687c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	if (0 == slen)
19787c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess		goto err_free_pgtable;
19887c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess
19987c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen))
20087c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess		goto err_unmap_sg;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return mem;
20387c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess
20487c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgesserr_unmap_sg:
20587c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
20687c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgesserr_free_pgtable:
20787c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	saa7146_pgtable_free(pci, pt);
20887c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgesserr_free_slist:
20987c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	kfree(pt->slist);
21087c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	pt->slist = NULL;
21187c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgesserr_free_mem:
21287c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	vfree(mem);
21387c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgesserr_null:
21487c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	return NULL;
21587c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess}
21687c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess
217804b4458943f14bf144d3c3ba50097ced9b27b29Oliver Endrissvoid saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt)
21887c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess{
21987c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
22087c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	saa7146_pgtable_free(pci, pt);
22187c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	kfree(pt->slist);
22287c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	pt->slist = NULL;
22387c3019d7b1acb7704a257d78c482112e9b0c227Jon Burgess	vfree(mem);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt)
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (NULL == pt->cpu)
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_free_consistent(pci, pt->size, pt->cpu, pt->dma);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pt->cpu = NULL;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
236a36ef6b1e09d06d4f1ac769eee4bd7e6cf3e0faeAl Viro	__le32       *cpu;
237614b147b4f8f38a090f88ac02f67b01225bb5d54Hans Verkuil	dma_addr_t   dma_addr = 0;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (NULL == cpu) {
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pt->size = PAGE_SIZE;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pt->cpu  = cpu;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pt->dma  = dma_addr;
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt,
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scatterlist *list, int sglen  )
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
253a36ef6b1e09d06d4f1ac769eee4bd7e6cf3e0faeAl Viro	__le32 *ptr, fill;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int nr_pages = 0;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i,p;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON(0 == sglen);
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON(list->offset > PAGE_SIZE);
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if we have a user buffer, the first page may not be
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   aligned to a page boundary. */
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pt->offset = list->offset;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ptr = pt->cpu;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < sglen; i++, list++) {
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
26744d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches		pr_debug("i:%d, adr:0x%08x, len:%d, offset:%d\n",
26844d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches			 i, sg_dma_address(list), sg_dma_len(list),
26944d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches			 list->offset);
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (p = 0; p * 4096 < list->length; p++, ptr++) {
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*ptr = cpu_to_le32(sg_dma_address(list) + p * 4096);
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nr_pages++;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* safety; fill the page table up with the last valid page */
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fill = *(ptr-1);
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(i=nr_pages;i<1024;i++) {
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*ptr++ = fill;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ptr = pt->cpu;
28644d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches	pr_debug("offset: %d\n", pt->offset);
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(i=0;i<5;i++) {
28844d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches		pr_debug("ptr1 %d: 0x%08x\n", i, ptr[i]);
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********************************************************************************/
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* interrupt handler */
2967d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t interrupt_hw(int irq, void *dev_id)
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct saa7146_dev *dev = dev_id;
299276e49a01a7e6c4a7bfb78618cf2f5befbf9f5deOliver Endriss	u32 isr;
300276e49a01a7e6c4a7bfb78618cf2f5befbf9f5deOliver Endriss	u32 ack_isr;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* read out the interrupt status register */
303276e49a01a7e6c4a7bfb78618cf2f5befbf9f5deOliver Endriss	ack_isr = isr = saa7146_read(dev, ISR);
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* is this our interrupt? */
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( 0 == isr ) {
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* nope, some other device */
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_NONE;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3115fa1247a2b56f33f88432c24e109deaf91ef8281Al Viro	if (dev->ext) {
3125fa1247a2b56f33f88432c24e109deaf91ef8281Al Viro		if (dev->ext->irq_mask & isr) {
3135fa1247a2b56f33f88432c24e109deaf91ef8281Al Viro			if (dev->ext->irq_func)
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev->ext->irq_func(dev, &isr);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			isr &= ~dev->ext->irq_mask;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (0 != (isr & (MASK_27))) {
31944d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches		DEB_INT("irq: RPS0 (0x%08x)\n", isr);
3205fa1247a2b56f33f88432c24e109deaf91ef8281Al Viro		if (dev->vv_data && dev->vv_callback)
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->vv_callback(dev,isr);
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		isr &= ~MASK_27;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (0 != (isr & (MASK_28))) {
3255fa1247a2b56f33f88432c24e109deaf91ef8281Al Viro		if (dev->vv_data && dev->vv_callback)
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->vv_callback(dev,isr);
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		isr &= ~MASK_28;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (0 != (isr & (MASK_16|MASK_17))) {
330276e49a01a7e6c4a7bfb78618cf2f5befbf9f5deOliver Endriss		SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
331276e49a01a7e6c4a7bfb78618cf2f5befbf9f5deOliver Endriss		/* only wake up if we expect something */
332276e49a01a7e6c4a7bfb78618cf2f5befbf9f5deOliver Endriss		if (0 != dev->i2c_op) {
333276e49a01a7e6c4a7bfb78618cf2f5befbf9f5deOliver Endriss			dev->i2c_op = 0;
334276e49a01a7e6c4a7bfb78618cf2f5befbf9f5deOliver Endriss			wake_up(&dev->i2c_wq);
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
336276e49a01a7e6c4a7bfb78618cf2f5befbf9f5deOliver Endriss			u32 psr = saa7146_read(dev, PSR);
337276e49a01a7e6c4a7bfb78618cf2f5befbf9f5deOliver Endriss			u32 ssr = saa7146_read(dev, SSR);
33844d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches			pr_warn("%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
33944d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches				dev->name, isr, psr, ssr);
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		isr &= ~(MASK_16|MASK_17);
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if( 0 != isr ) {
34444d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches		ERR("warning: interrupt enabled, but not handled properly.(0x%08x)\n",
34544d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches		    isr);
34644d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches		ERR("disabling interrupt source(s)!\n");
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SAA7146_IER_DISABLE(dev,isr);
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
349276e49a01a7e6c4a7bfb78618cf2f5befbf9f5deOliver Endriss	saa7146_write(dev, ISR, ack_isr);
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*********************************************************************************/
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* configuration-functions                                                       */
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent)
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data;
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct saa7146_extension *ext = pci_ext->ext;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct saa7146_dev *dev;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENOMEM;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3637408187d223f63d46a13b6a35b8f96b032c2f623Panagiotis Issaris	/* clear out mem for sure */
3647408187d223f63d46a13b6a35b8f96b032c2f623Panagiotis Issaris	dev = kzalloc(sizeof(struct saa7146_dev), GFP_KERNEL);
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev) {
36644d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches		ERR("out of memory\n");
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37044d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches	DEB_EE("pci:%p\n", pci);
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = pci_enable_device(pci);
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err < 0) {
37444d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches		ERR("pci_enable_device() failed\n");
375230b65f9945b468c23188572144b4f066af8f98cHans Verkuil		goto err_free;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* enable bus-mastering */
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_set_master(pci);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->pci = pci;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* get chip-revision; this is needed to enable bug-fixes */
384abd34d8d6b213c792c1a06fd75488595c5fb6d3fBjørn Mork	dev->revision = pci->revision;
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
386c84e6036ba7177a404cc860cb5a440e06fad92ddJoe Perches	/* remap the memory from virtual to physical address */
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = pci_request_region(pci, 0, "saa7146");
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err < 0)
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_disable;
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->mem = ioremap(pci_resource_start(pci, 0),
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   pci_resource_len(pci, 0));
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev->mem) {
39544d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches		ERR("ioremap() failed\n");
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENODEV;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_release;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* we don't do a master reset here anymore, it screws up
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   some boards that don't have an i2c-eeprom for configuration
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   values */
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_write(dev, MC1, MASK_31);
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* disable all irqs */
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_write(dev, IER, 0);
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* shut down all dma transfers and rps tasks */
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_write(dev, MC1, 0x30ff0000);
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* clear out any rps-signals pending */
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_write(dev, MC2, 0xf8000000);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* request an interrupt for the saa7146 */
4178076fe32a7db9a6628589ffa372808e4ba25d222Thomas Gleixner	err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED,
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  dev->name, dev);
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err < 0) {
42044d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches		ERR("request_irq() failed\n");
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_unmap;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = -ENOMEM;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* get memory for various stuff */
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->d_rps0.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    &dev->d_rps0.dma_handle);
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev->d_rps0.cpu_addr)
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_free_irq;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(dev->d_rps0.cpu_addr, 0x0, SAA7146_RPS_MEM);
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->d_rps1.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    &dev->d_rps1.dma_handle);
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev->d_rps1.cpu_addr)
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_free_rps0;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(dev->d_rps1.cpu_addr, 0x0, SAA7146_RPS_MEM);
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->d_i2c.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   &dev->d_i2c.dma_handle);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev->d_i2c.cpu_addr)
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_free_rps1;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(dev->d_i2c.cpu_addr, 0x0, SAA7146_RPS_MEM);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* the rest + print status message */
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* create a nice device name */
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sprintf(dev->name, "saa7146 (%d)", saa7146_num);
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45044d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches	pr_info("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x)\n",
45144d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches		dev->mem, dev->revision, pci->irq,
45244d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches		pci->subsystem_vendor, pci->subsystem_device);
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->ext = ext;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4559af39713feb53da96ba23fa94a73ffd0de50a815Hans Verkuil	mutex_init(&dev->v4l2_lock);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&dev->int_slock);
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&dev->slock);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4593593cab5d62c4c7abced1076710f9bc2d8847433Ingo Molnar	mutex_init(&dev->i2c_lock);
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->module = THIS_MODULE;
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_waitqueue_head(&dev->i2c_wq);
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set some sane pci arbitrition values */
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* TODO: use the status code of the callback */
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = -ENODEV;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ext->probe && ext->probe(dev)) {
47244d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches		DEB_D("ext->probe() failed for %p. skipping device.\n", dev);
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_free_i2c;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ext->attach(dev, pci_ext)) {
47744d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches		DEB_D("ext->attach() failed for %p. skipping device.\n", dev);
478ef77a26be1883366bb78741d1808e5c86a14ec76Hans Verkuil		goto err_free_i2c;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
480230b65f9945b468c23188572144b4f066af8f98cHans Verkuil	/* V4L extensions will set the pci drvdata to the v4l2_device in the
481230b65f9945b468c23188572144b4f066af8f98cHans Verkuil	   attach() above. So for those cards that do not use V4L we have to
482230b65f9945b468c23188572144b4f066af8f98cHans Verkuil	   set it explicitly. */
483230b65f9945b468c23188572144b4f066af8f98cHans Verkuil	pci_set_drvdata(pci, &dev->v4l2_dev);
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD(&dev->item);
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail(&dev->item,&saa7146_devices);
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_num++;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = 0;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_free_i2c:
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr,
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    dev->d_i2c.dma_handle);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_free_rps1:
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr,
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    dev->d_rps1.dma_handle);
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_free_rps0:
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr,
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    dev->d_rps0.dma_handle);
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_free_irq:
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(pci->irq, (void *)dev);
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_unmap:
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iounmap(dev->mem);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_release:
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_release_region(pci, 0);
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_disable:
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_disable_device(pci);
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_free:
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(dev);
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto out;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void saa7146_remove_one(struct pci_dev *pdev)
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
517ef77a26be1883366bb78741d1808e5c86a14ec76Hans Verkuil	struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
51845d809431daaa3ab01f877388d09676d05b469beHans Verkuil	struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev);
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct {
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		void *addr;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dma_addr_t dma;
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} dev_map[] = {
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle },
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle },
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle },
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ NULL, 0 }
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}, *p;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52944d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches	DEB_EE("dev:%p\n", dev);
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->ext->detach(dev);
532230b65f9945b468c23188572144b4f066af8f98cHans Verkuil	/* Zero the PCI drvdata after use. */
533230b65f9945b468c23188572144b4f066af8f98cHans Verkuil	pci_set_drvdata(pdev, NULL);
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* shut down all video dma transfers */
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_write(dev, MC1, 0x00ff0000);
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* disable all irqs, release irq-routine */
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_write(dev, IER, 0);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(pdev->irq, dev);
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (p = dev_map; p->addr; p++)
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_free_consistent(pdev, SAA7146_RPS_MEM, p->addr, p->dma);
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iounmap(dev->mem);
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_release_region(pdev, 0);
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_del(&dev->item);
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_disable_device(pdev);
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(dev);
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_num--;
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*********************************************************************************/
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* extension handling functions                                                  */
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint saa7146_register_extension(struct saa7146_extension* ext)
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
56044d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches	DEB_EE("ext:%p\n", ext);
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ext->driver.name = ext->name;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ext->driver.id_table = ext->pci_tbl;
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ext->driver.probe = saa7146_init_one;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ext->driver.remove = saa7146_remove_one;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
56744d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches	pr_info("register extension '%s'\n", ext->name);
568178c6efcd8435644028bf3f079c1e82107e72dfdChristophe Lucas	return pci_register_driver(&ext->driver);
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint saa7146_unregister_extension(struct saa7146_extension* ext)
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
57344d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches	DEB_EE("ext:%p\n", ext);
57444d0b80e5ff741d502a6ccc8685a18bda1ac9da4Joe Perches	pr_info("unregister extension '%s'\n", ext->name);
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_unregister_driver(&ext->driver);
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(saa7146_register_extension);
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(saa7146_unregister_extension);
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* misc functions used by extension modules */
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(saa7146_pgtable_alloc);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(saa7146_pgtable_free);
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(saa7146_pgtable_build_single);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable);
58787c3019d7b1acb7704a257d78c482112e9b0c227Jon BurgessEXPORT_SYMBOL_GPL(saa7146_vfree_destroy_pgtable);
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done);
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(saa7146_setgpio);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare);
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(saa7146_debug);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(saa7146_devices);
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(saa7146_devices_lock);
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("driver for generic saa7146-based hardware");
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
601