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