18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * pluto2.c - Satelco Easywatch Mobile Terrestrial Receiver [DVB-T] 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2005 Andreas Oberritter <obi@linuxtv.org> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * based on pluto2.c 1.10 - http://instinct-wp8.no-ip.org/pluto/ 88c2ecf20Sopenharmony_ci * by Dany Salman <salmandany@yahoo.fr> 98c2ecf20Sopenharmony_ci * Copyright (c) 2004 TDF 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/i2c.h> 138c2ecf20Sopenharmony_ci#include <linux/i2c-algo-bit.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/pci.h> 198c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <media/demux.h> 238c2ecf20Sopenharmony_ci#include <media/dmxdev.h> 248c2ecf20Sopenharmony_ci#include <media/dvb_demux.h> 258c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 268c2ecf20Sopenharmony_ci#include <media/dvb_net.h> 278c2ecf20Sopenharmony_ci#include <media/dvbdev.h> 288c2ecf20Sopenharmony_ci#include "tda1004x.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define DRIVER_NAME "pluto2" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define REG_PIDn(n) ((n) << 2) /* PID n pattern registers */ 358c2ecf20Sopenharmony_ci#define REG_PCAR 0x0020 /* PC address register */ 368c2ecf20Sopenharmony_ci#define REG_TSCR 0x0024 /* TS ctrl & status */ 378c2ecf20Sopenharmony_ci#define REG_MISC 0x0028 /* miscellaneous */ 388c2ecf20Sopenharmony_ci#define REG_MMAC 0x002c /* MSB MAC address */ 398c2ecf20Sopenharmony_ci#define REG_IMAC 0x0030 /* ISB MAC address */ 408c2ecf20Sopenharmony_ci#define REG_LMAC 0x0034 /* LSB MAC address */ 418c2ecf20Sopenharmony_ci#define REG_SPID 0x0038 /* SPI data */ 428c2ecf20Sopenharmony_ci#define REG_SLCS 0x003c /* serial links ctrl/status */ 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define PID0_NOFIL (0x0001 << 16) 458c2ecf20Sopenharmony_ci#define PIDn_ENP (0x0001 << 15) 468c2ecf20Sopenharmony_ci#define PID0_END (0x0001 << 14) 478c2ecf20Sopenharmony_ci#define PID0_AFIL (0x0001 << 13) 488c2ecf20Sopenharmony_ci#define PIDn_PID (0x1fff << 0) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define TSCR_NBPACKETS (0x00ff << 24) 518c2ecf20Sopenharmony_ci#define TSCR_DEM (0x0001 << 17) 528c2ecf20Sopenharmony_ci#define TSCR_DE (0x0001 << 16) 538c2ecf20Sopenharmony_ci#define TSCR_RSTN (0x0001 << 15) 548c2ecf20Sopenharmony_ci#define TSCR_MSKO (0x0001 << 14) 558c2ecf20Sopenharmony_ci#define TSCR_MSKA (0x0001 << 13) 568c2ecf20Sopenharmony_ci#define TSCR_MSKL (0x0001 << 12) 578c2ecf20Sopenharmony_ci#define TSCR_OVR (0x0001 << 11) 588c2ecf20Sopenharmony_ci#define TSCR_AFUL (0x0001 << 10) 598c2ecf20Sopenharmony_ci#define TSCR_LOCK (0x0001 << 9) 608c2ecf20Sopenharmony_ci#define TSCR_IACK (0x0001 << 8) 618c2ecf20Sopenharmony_ci#define TSCR_ADEF (0x007f << 0) 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define MISC_DVR (0x0fff << 4) 648c2ecf20Sopenharmony_ci#define MISC_ALED (0x0001 << 3) 658c2ecf20Sopenharmony_ci#define MISC_FRST (0x0001 << 2) 668c2ecf20Sopenharmony_ci#define MISC_LED1 (0x0001 << 1) 678c2ecf20Sopenharmony_ci#define MISC_LED0 (0x0001 << 0) 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define SPID_SPIDR (0x00ff << 0) 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define SLCS_SCL (0x0001 << 7) 728c2ecf20Sopenharmony_ci#define SLCS_SDA (0x0001 << 6) 738c2ecf20Sopenharmony_ci#define SLCS_CSN (0x0001 << 2) 748c2ecf20Sopenharmony_ci#define SLCS_OVR (0x0001 << 1) 758c2ecf20Sopenharmony_ci#define SLCS_SWC (0x0001 << 0) 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define TS_DMA_PACKETS (8) 788c2ecf20Sopenharmony_ci#define TS_DMA_BYTES (188 * TS_DMA_PACKETS) 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#define I2C_ADDR_TDA10046 0x10 818c2ecf20Sopenharmony_ci#define I2C_ADDR_TUA6034 0xc2 828c2ecf20Sopenharmony_ci#define NHWFILTERS 8 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistruct pluto { 858c2ecf20Sopenharmony_ci /* pci */ 868c2ecf20Sopenharmony_ci struct pci_dev *pdev; 878c2ecf20Sopenharmony_ci u8 __iomem *io_mem; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* dvb */ 908c2ecf20Sopenharmony_ci struct dmx_frontend hw_frontend; 918c2ecf20Sopenharmony_ci struct dmx_frontend mem_frontend; 928c2ecf20Sopenharmony_ci struct dmxdev dmxdev; 938c2ecf20Sopenharmony_ci struct dvb_adapter dvb_adapter; 948c2ecf20Sopenharmony_ci struct dvb_demux demux; 958c2ecf20Sopenharmony_ci struct dvb_frontend *fe; 968c2ecf20Sopenharmony_ci struct dvb_net dvbnet; 978c2ecf20Sopenharmony_ci unsigned int full_ts_users; 988c2ecf20Sopenharmony_ci unsigned int users; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* i2c */ 1018c2ecf20Sopenharmony_ci struct i2c_algo_bit_data i2c_bit; 1028c2ecf20Sopenharmony_ci struct i2c_adapter i2c_adap; 1038c2ecf20Sopenharmony_ci unsigned int i2cbug; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* irq */ 1068c2ecf20Sopenharmony_ci unsigned int overflow; 1078c2ecf20Sopenharmony_ci unsigned int dead; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* dma */ 1108c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 1118c2ecf20Sopenharmony_ci u8 dma_buf[TS_DMA_BYTES]; 1128c2ecf20Sopenharmony_ci u8 dummy[4096]; 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic inline struct pluto *feed_to_pluto(struct dvb_demux_feed *feed) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci return container_of(feed->demux, struct pluto, demux); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic inline struct pluto *frontend_to_pluto(struct dvb_frontend *fe) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci return container_of(fe->dvb, struct pluto, dvb_adapter); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic inline u32 pluto_readreg(struct pluto *pluto, u32 reg) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci return readl(&pluto->io_mem[reg]); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic inline void pluto_writereg(struct pluto *pluto, u32 reg, u32 val) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci writel(val, &pluto->io_mem[reg]); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic inline void pluto_rw(struct pluto *pluto, u32 reg, u32 mask, u32 bits) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci u32 val = readl(&pluto->io_mem[reg]); 1388c2ecf20Sopenharmony_ci val &= ~mask; 1398c2ecf20Sopenharmony_ci val |= bits; 1408c2ecf20Sopenharmony_ci writel(val, &pluto->io_mem[reg]); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void pluto_write_tscr(struct pluto *pluto, u32 val) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci /* set the number of packets */ 1468c2ecf20Sopenharmony_ci val &= ~TSCR_ADEF; 1478c2ecf20Sopenharmony_ci val |= TS_DMA_PACKETS / 2; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci pluto_writereg(pluto, REG_TSCR, val); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic void pluto_setsda(void *data, int state) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct pluto *pluto = data; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (state) 1578c2ecf20Sopenharmony_ci pluto_rw(pluto, REG_SLCS, SLCS_SDA, SLCS_SDA); 1588c2ecf20Sopenharmony_ci else 1598c2ecf20Sopenharmony_ci pluto_rw(pluto, REG_SLCS, SLCS_SDA, 0); 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic void pluto_setscl(void *data, int state) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct pluto *pluto = data; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (state) 1678c2ecf20Sopenharmony_ci pluto_rw(pluto, REG_SLCS, SLCS_SCL, SLCS_SCL); 1688c2ecf20Sopenharmony_ci else 1698c2ecf20Sopenharmony_ci pluto_rw(pluto, REG_SLCS, SLCS_SCL, 0); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* try to detect i2c_inb() to workaround hardware bug: 1728c2ecf20Sopenharmony_ci * reset SDA to high after SCL has been set to low */ 1738c2ecf20Sopenharmony_ci if ((state) && (pluto->i2cbug == 0)) { 1748c2ecf20Sopenharmony_ci pluto->i2cbug = 1; 1758c2ecf20Sopenharmony_ci } else { 1768c2ecf20Sopenharmony_ci if ((!state) && (pluto->i2cbug == 1)) 1778c2ecf20Sopenharmony_ci pluto_setsda(pluto, 1); 1788c2ecf20Sopenharmony_ci pluto->i2cbug = 0; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic int pluto_getsda(void *data) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct pluto *pluto = data; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return pluto_readreg(pluto, REG_SLCS) & SLCS_SDA; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic int pluto_getscl(void *data) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct pluto *pluto = data; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci return pluto_readreg(pluto, REG_SLCS) & SLCS_SCL; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic void pluto_reset_frontend(struct pluto *pluto, int reenable) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci u32 val = pluto_readreg(pluto, REG_MISC); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (val & MISC_FRST) { 2018c2ecf20Sopenharmony_ci val &= ~MISC_FRST; 2028c2ecf20Sopenharmony_ci pluto_writereg(pluto, REG_MISC, val); 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci if (reenable) { 2058c2ecf20Sopenharmony_ci val |= MISC_FRST; 2068c2ecf20Sopenharmony_ci pluto_writereg(pluto, REG_MISC, val); 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic void pluto_reset_ts(struct pluto *pluto, int reenable) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci u32 val = pluto_readreg(pluto, REG_TSCR); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (val & TSCR_RSTN) { 2158c2ecf20Sopenharmony_ci val &= ~TSCR_RSTN; 2168c2ecf20Sopenharmony_ci pluto_write_tscr(pluto, val); 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci if (reenable) { 2198c2ecf20Sopenharmony_ci val |= TSCR_RSTN; 2208c2ecf20Sopenharmony_ci pluto_write_tscr(pluto, val); 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic void pluto_set_dma_addr(struct pluto *pluto) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci pluto_writereg(pluto, REG_PCAR, pluto->dma_addr); 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic int pluto_dma_map(struct pluto *pluto) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf, 2328c2ecf20Sopenharmony_ci TS_DMA_BYTES, PCI_DMA_FROMDEVICE); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return pci_dma_mapping_error(pluto->pdev, pluto->dma_addr); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic void pluto_dma_unmap(struct pluto *pluto) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci pci_unmap_single(pluto->pdev, pluto->dma_addr, 2408c2ecf20Sopenharmony_ci TS_DMA_BYTES, PCI_DMA_FROMDEVICE); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic int pluto_start_feed(struct dvb_demux_feed *f) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci struct pluto *pluto = feed_to_pluto(f); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* enable PID filtering */ 2488c2ecf20Sopenharmony_ci if (pluto->users++ == 0) 2498c2ecf20Sopenharmony_ci pluto_rw(pluto, REG_PIDn(0), PID0_AFIL | PID0_NOFIL, 0); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if ((f->pid < 0x2000) && (f->index < NHWFILTERS)) 2528c2ecf20Sopenharmony_ci pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, PIDn_ENP | f->pid); 2538c2ecf20Sopenharmony_ci else if (pluto->full_ts_users++ == 0) 2548c2ecf20Sopenharmony_ci pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, PID0_NOFIL); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return 0; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int pluto_stop_feed(struct dvb_demux_feed *f) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct pluto *pluto = feed_to_pluto(f); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* disable PID filtering */ 2648c2ecf20Sopenharmony_ci if (--pluto->users == 0) 2658c2ecf20Sopenharmony_ci pluto_rw(pluto, REG_PIDn(0), PID0_AFIL, PID0_AFIL); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if ((f->pid < 0x2000) && (f->index < NHWFILTERS)) 2688c2ecf20Sopenharmony_ci pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, 0x1fff); 2698c2ecf20Sopenharmony_ci else if (--pluto->full_ts_users == 0) 2708c2ecf20Sopenharmony_ci pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, 0); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return 0; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci /* synchronize the DMA transfer with the CPU 2788c2ecf20Sopenharmony_ci * first so that we see updated contents. */ 2798c2ecf20Sopenharmony_ci pci_dma_sync_single_for_cpu(pluto->pdev, pluto->dma_addr, 2808c2ecf20Sopenharmony_ci TS_DMA_BYTES, PCI_DMA_FROMDEVICE); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* Workaround for broken hardware: 2838c2ecf20Sopenharmony_ci * [1] On startup NBPACKETS seems to contain an uninitialized value, 2848c2ecf20Sopenharmony_ci * but no packets have been transferred. 2858c2ecf20Sopenharmony_ci * [2] Sometimes (actually very often) NBPACKETS stays at zero 2868c2ecf20Sopenharmony_ci * although one packet has been transferred. 2878c2ecf20Sopenharmony_ci * [3] Sometimes (actually rarely), the card gets into an erroneous 2888c2ecf20Sopenharmony_ci * mode where it continuously generates interrupts, claiming it 2898c2ecf20Sopenharmony_ci * has received nbpackets>TS_DMA_PACKETS packets, but no packet 2908c2ecf20Sopenharmony_ci * has been transferred. Only a reset seems to solve this 2918c2ecf20Sopenharmony_ci */ 2928c2ecf20Sopenharmony_ci if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) { 2938c2ecf20Sopenharmony_ci unsigned int i = 0; 2948c2ecf20Sopenharmony_ci while (pluto->dma_buf[i] == 0x47) 2958c2ecf20Sopenharmony_ci i += 188; 2968c2ecf20Sopenharmony_ci nbpackets = i / 188; 2978c2ecf20Sopenharmony_ci if (i == 0) { 2988c2ecf20Sopenharmony_ci pluto_reset_ts(pluto, 1); 2998c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &pluto->pdev->dev, "resetting TS because of invalid packet counter\n"); 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* clear the dma buffer. this is needed to be able to identify 3068c2ecf20Sopenharmony_ci * new valid ts packets above */ 3078c2ecf20Sopenharmony_ci memset(pluto->dma_buf, 0, nbpackets * 188); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* reset the dma address */ 3108c2ecf20Sopenharmony_ci pluto_set_dma_addr(pluto); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* sync the buffer and give it back to the card */ 3138c2ecf20Sopenharmony_ci pci_dma_sync_single_for_device(pluto->pdev, pluto->dma_addr, 3148c2ecf20Sopenharmony_ci TS_DMA_BYTES, PCI_DMA_FROMDEVICE); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic irqreturn_t pluto_irq(int irq, void *dev_id) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct pluto *pluto = dev_id; 3208c2ecf20Sopenharmony_ci u32 tscr; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* check whether an interrupt occurred on this device */ 3238c2ecf20Sopenharmony_ci tscr = pluto_readreg(pluto, REG_TSCR); 3248c2ecf20Sopenharmony_ci if (!(tscr & (TSCR_DE | TSCR_OVR))) 3258c2ecf20Sopenharmony_ci return IRQ_NONE; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (tscr == 0xffffffff) { 3288c2ecf20Sopenharmony_ci if (pluto->dead == 0) 3298c2ecf20Sopenharmony_ci dev_err(&pluto->pdev->dev, "card has hung or been ejected.\n"); 3308c2ecf20Sopenharmony_ci /* It's dead Jim */ 3318c2ecf20Sopenharmony_ci pluto->dead = 1; 3328c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* dma end interrupt */ 3368c2ecf20Sopenharmony_ci if (tscr & TSCR_DE) { 3378c2ecf20Sopenharmony_ci pluto_dma_end(pluto, (tscr & TSCR_NBPACKETS) >> 24); 3388c2ecf20Sopenharmony_ci /* overflow interrupt */ 3398c2ecf20Sopenharmony_ci if (tscr & TSCR_OVR) 3408c2ecf20Sopenharmony_ci pluto->overflow++; 3418c2ecf20Sopenharmony_ci if (pluto->overflow) { 3428c2ecf20Sopenharmony_ci dev_err(&pluto->pdev->dev, "overflow irq (%d)\n", 3438c2ecf20Sopenharmony_ci pluto->overflow); 3448c2ecf20Sopenharmony_ci pluto_reset_ts(pluto, 1); 3458c2ecf20Sopenharmony_ci pluto->overflow = 0; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci } else if (tscr & TSCR_OVR) { 3488c2ecf20Sopenharmony_ci pluto->overflow++; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* ACK the interrupt */ 3528c2ecf20Sopenharmony_ci pluto_write_tscr(pluto, tscr | TSCR_IACK); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic void pluto_enable_irqs(struct pluto *pluto) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci u32 val = pluto_readreg(pluto, REG_TSCR); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* disable AFUL and LOCK interrupts */ 3628c2ecf20Sopenharmony_ci val |= (TSCR_MSKA | TSCR_MSKL); 3638c2ecf20Sopenharmony_ci /* enable DMA and OVERFLOW interrupts */ 3648c2ecf20Sopenharmony_ci val &= ~(TSCR_DEM | TSCR_MSKO); 3658c2ecf20Sopenharmony_ci /* clear pending interrupts */ 3668c2ecf20Sopenharmony_ci val |= TSCR_IACK; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci pluto_write_tscr(pluto, val); 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic void pluto_disable_irqs(struct pluto *pluto) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci u32 val = pluto_readreg(pluto, REG_TSCR); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* disable all interrupts */ 3768c2ecf20Sopenharmony_ci val |= (TSCR_DEM | TSCR_MSKO | TSCR_MSKA | TSCR_MSKL); 3778c2ecf20Sopenharmony_ci /* clear pending interrupts */ 3788c2ecf20Sopenharmony_ci val |= TSCR_IACK; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci pluto_write_tscr(pluto, val); 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic int pluto_hw_init(struct pluto *pluto) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci pluto_reset_frontend(pluto, 1); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* set automatic LED control by FPGA */ 3888c2ecf20Sopenharmony_ci pluto_rw(pluto, REG_MISC, MISC_ALED, MISC_ALED); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* set data endianness */ 3918c2ecf20Sopenharmony_ci#ifdef __LITTLE_ENDIAN 3928c2ecf20Sopenharmony_ci pluto_rw(pluto, REG_PIDn(0), PID0_END, PID0_END); 3938c2ecf20Sopenharmony_ci#else 3948c2ecf20Sopenharmony_ci pluto_rw(pluto, REG_PIDn(0), PID0_END, 0); 3958c2ecf20Sopenharmony_ci#endif 3968c2ecf20Sopenharmony_ci /* map DMA and set address */ 3978c2ecf20Sopenharmony_ci pluto_dma_map(pluto); 3988c2ecf20Sopenharmony_ci pluto_set_dma_addr(pluto); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* enable interrupts */ 4018c2ecf20Sopenharmony_ci pluto_enable_irqs(pluto); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* reset TS logic */ 4048c2ecf20Sopenharmony_ci pluto_reset_ts(pluto, 1); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci return 0; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic void pluto_hw_exit(struct pluto *pluto) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci /* disable interrupts */ 4128c2ecf20Sopenharmony_ci pluto_disable_irqs(pluto); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci pluto_reset_ts(pluto, 0); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* LED: disable automatic control, enable yellow, disable green */ 4178c2ecf20Sopenharmony_ci pluto_rw(pluto, REG_MISC, MISC_ALED | MISC_LED1 | MISC_LED0, MISC_LED1); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* unmap DMA */ 4208c2ecf20Sopenharmony_ci pluto_dma_unmap(pluto); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci pluto_reset_frontend(pluto, 0); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic inline u32 divide(u32 numerator, u32 denominator) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci if (denominator == 0) 4288c2ecf20Sopenharmony_ci return ~0; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci return DIV_ROUND_CLOSEST(numerator, denominator); 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci/* LG Innotek TDTE-E001P (Infineon TUA6034) */ 4348c2ecf20Sopenharmony_cistatic int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 4378c2ecf20Sopenharmony_ci struct pluto *pluto = frontend_to_pluto(fe); 4388c2ecf20Sopenharmony_ci struct i2c_msg msg; 4398c2ecf20Sopenharmony_ci int ret; 4408c2ecf20Sopenharmony_ci u8 buf[4]; 4418c2ecf20Sopenharmony_ci u32 div; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci // Fref = 166.667 Hz 4448c2ecf20Sopenharmony_ci // Fref * 3 = 500.000 Hz 4458c2ecf20Sopenharmony_ci // IF = 36166667 4468c2ecf20Sopenharmony_ci // IF / Fref = 217 4478c2ecf20Sopenharmony_ci //div = divide(p->frequency + 36166667, 166667); 4488c2ecf20Sopenharmony_ci div = divide(p->frequency * 3, 500000) + 217; 4498c2ecf20Sopenharmony_ci buf[0] = (div >> 8) & 0x7f; 4508c2ecf20Sopenharmony_ci buf[1] = (div >> 0) & 0xff; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (p->frequency < 611000000) 4538c2ecf20Sopenharmony_ci buf[2] = 0xb4; 4548c2ecf20Sopenharmony_ci else if (p->frequency < 811000000) 4558c2ecf20Sopenharmony_ci buf[2] = 0xbc; 4568c2ecf20Sopenharmony_ci else 4578c2ecf20Sopenharmony_ci buf[2] = 0xf4; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci // VHF: 174-230 MHz 4608c2ecf20Sopenharmony_ci // center: 350 MHz 4618c2ecf20Sopenharmony_ci // UHF: 470-862 MHz 4628c2ecf20Sopenharmony_ci if (p->frequency < 350000000) 4638c2ecf20Sopenharmony_ci buf[3] = 0x02; 4648c2ecf20Sopenharmony_ci else 4658c2ecf20Sopenharmony_ci buf[3] = 0x04; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if (p->bandwidth_hz == 8000000) 4688c2ecf20Sopenharmony_ci buf[3] |= 0x08; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci msg.addr = I2C_ADDR_TUA6034 >> 1; 4718c2ecf20Sopenharmony_ci msg.flags = 0; 4728c2ecf20Sopenharmony_ci msg.buf = buf; 4738c2ecf20Sopenharmony_ci msg.len = sizeof(buf); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 4768c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 4778c2ecf20Sopenharmony_ci ret = i2c_transfer(&pluto->i2c_adap, &msg, 1); 4788c2ecf20Sopenharmony_ci if (ret < 0) 4798c2ecf20Sopenharmony_ci return ret; 4808c2ecf20Sopenharmony_ci else if (ret == 0) 4818c2ecf20Sopenharmony_ci return -EREMOTEIO; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci return 0; 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic int pluto2_request_firmware(struct dvb_frontend *fe, 4878c2ecf20Sopenharmony_ci const struct firmware **fw, char *name) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci struct pluto *pluto = frontend_to_pluto(fe); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return request_firmware(fw, name, &pluto->pdev->dev); 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic struct tda1004x_config pluto2_fe_config = { 4958c2ecf20Sopenharmony_ci .demod_address = I2C_ADDR_TDA10046 >> 1, 4968c2ecf20Sopenharmony_ci .invert = 1, 4978c2ecf20Sopenharmony_ci .invert_oclk = 0, 4988c2ecf20Sopenharmony_ci .xtal_freq = TDA10046_XTAL_16M, 4998c2ecf20Sopenharmony_ci .agc_config = TDA10046_AGC_DEFAULT, 5008c2ecf20Sopenharmony_ci .if_freq = TDA10046_FREQ_3617, 5018c2ecf20Sopenharmony_ci .request_firmware = pluto2_request_firmware, 5028c2ecf20Sopenharmony_ci}; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic int frontend_init(struct pluto *pluto) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci int ret; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci pluto->fe = tda10046_attach(&pluto2_fe_config, &pluto->i2c_adap); 5098c2ecf20Sopenharmony_ci if (!pluto->fe) { 5108c2ecf20Sopenharmony_ci dev_err(&pluto->pdev->dev, "could not attach frontend\n"); 5118c2ecf20Sopenharmony_ci return -ENODEV; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci pluto->fe->ops.tuner_ops.set_params = lg_tdtpe001p_tuner_set_params; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe); 5168c2ecf20Sopenharmony_ci if (ret < 0) { 5178c2ecf20Sopenharmony_ci if (pluto->fe->ops.release) 5188c2ecf20Sopenharmony_ci pluto->fe->ops.release(pluto->fe); 5198c2ecf20Sopenharmony_ci return ret; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci return 0; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic void pluto_read_rev(struct pluto *pluto) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci u32 val = pluto_readreg(pluto, REG_MISC) & MISC_DVR; 5288c2ecf20Sopenharmony_ci dev_info(&pluto->pdev->dev, "board revision %d.%d\n", 5298c2ecf20Sopenharmony_ci (val >> 12) & 0x0f, (val >> 4) & 0xff); 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic void pluto_read_mac(struct pluto *pluto, u8 *mac) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci u32 val = pluto_readreg(pluto, REG_MMAC); 5358c2ecf20Sopenharmony_ci mac[0] = (val >> 8) & 0xff; 5368c2ecf20Sopenharmony_ci mac[1] = (val >> 0) & 0xff; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci val = pluto_readreg(pluto, REG_IMAC); 5398c2ecf20Sopenharmony_ci mac[2] = (val >> 8) & 0xff; 5408c2ecf20Sopenharmony_ci mac[3] = (val >> 0) & 0xff; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci val = pluto_readreg(pluto, REG_LMAC); 5438c2ecf20Sopenharmony_ci mac[4] = (val >> 8) & 0xff; 5448c2ecf20Sopenharmony_ci mac[5] = (val >> 0) & 0xff; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci dev_info(&pluto->pdev->dev, "MAC %pM\n", mac); 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_cistatic int pluto_read_serial(struct pluto *pluto) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci struct pci_dev *pdev = pluto->pdev; 5528c2ecf20Sopenharmony_ci unsigned int i, j; 5538c2ecf20Sopenharmony_ci u8 __iomem *cis; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci cis = pci_iomap(pdev, 1, 0); 5568c2ecf20Sopenharmony_ci if (!cis) 5578c2ecf20Sopenharmony_ci return -EIO; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "S/N "); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci for (i = 0xe0; i < 0x100; i += 4) { 5628c2ecf20Sopenharmony_ci u32 val = readl(&cis[i]); 5638c2ecf20Sopenharmony_ci for (j = 0; j < 32; j += 8) { 5648c2ecf20Sopenharmony_ci if ((val & 0xff) == 0xff) 5658c2ecf20Sopenharmony_ci goto out; 5668c2ecf20Sopenharmony_ci printk(KERN_CONT "%c", val & 0xff); 5678c2ecf20Sopenharmony_ci val >>= 8; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ciout: 5718c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 5728c2ecf20Sopenharmony_ci pci_iounmap(pdev, cis); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci return 0; 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_cistatic int pluto2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci struct pluto *pluto; 5808c2ecf20Sopenharmony_ci struct dvb_adapter *dvb_adapter; 5818c2ecf20Sopenharmony_ci struct dvb_demux *dvbdemux; 5828c2ecf20Sopenharmony_ci struct dmx_demux *dmx; 5838c2ecf20Sopenharmony_ci int ret = -ENOMEM; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci pluto = kzalloc(sizeof(struct pluto), GFP_KERNEL); 5868c2ecf20Sopenharmony_ci if (!pluto) 5878c2ecf20Sopenharmony_ci goto out; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci pluto->pdev = pdev; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci ret = pci_enable_device(pdev); 5928c2ecf20Sopenharmony_ci if (ret < 0) 5938c2ecf20Sopenharmony_ci goto err_kfree; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci /* enable interrupts */ 5968c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, 0x6c, 0x8000); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 5998c2ecf20Sopenharmony_ci if (ret < 0) 6008c2ecf20Sopenharmony_ci goto err_pci_disable_device; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci pci_set_master(pdev); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci ret = pci_request_regions(pdev, DRIVER_NAME); 6058c2ecf20Sopenharmony_ci if (ret < 0) 6068c2ecf20Sopenharmony_ci goto err_pci_disable_device; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci pluto->io_mem = pci_iomap(pdev, 0, 0x40); 6098c2ecf20Sopenharmony_ci if (!pluto->io_mem) { 6108c2ecf20Sopenharmony_ci ret = -EIO; 6118c2ecf20Sopenharmony_ci goto err_pci_release_regions; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, pluto); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci ret = request_irq(pdev->irq, pluto_irq, IRQF_SHARED, DRIVER_NAME, pluto); 6178c2ecf20Sopenharmony_ci if (ret < 0) 6188c2ecf20Sopenharmony_ci goto err_pci_iounmap; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci ret = pluto_hw_init(pluto); 6218c2ecf20Sopenharmony_ci if (ret < 0) 6228c2ecf20Sopenharmony_ci goto err_free_irq; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* i2c */ 6258c2ecf20Sopenharmony_ci i2c_set_adapdata(&pluto->i2c_adap, pluto); 6268c2ecf20Sopenharmony_ci strscpy(pluto->i2c_adap.name, DRIVER_NAME, sizeof(pluto->i2c_adap.name)); 6278c2ecf20Sopenharmony_ci pluto->i2c_adap.owner = THIS_MODULE; 6288c2ecf20Sopenharmony_ci pluto->i2c_adap.dev.parent = &pdev->dev; 6298c2ecf20Sopenharmony_ci pluto->i2c_adap.algo_data = &pluto->i2c_bit; 6308c2ecf20Sopenharmony_ci pluto->i2c_bit.data = pluto; 6318c2ecf20Sopenharmony_ci pluto->i2c_bit.setsda = pluto_setsda; 6328c2ecf20Sopenharmony_ci pluto->i2c_bit.setscl = pluto_setscl; 6338c2ecf20Sopenharmony_ci pluto->i2c_bit.getsda = pluto_getsda; 6348c2ecf20Sopenharmony_ci pluto->i2c_bit.getscl = pluto_getscl; 6358c2ecf20Sopenharmony_ci pluto->i2c_bit.udelay = 10; 6368c2ecf20Sopenharmony_ci pluto->i2c_bit.timeout = 10; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci /* Raise SCL and SDA */ 6398c2ecf20Sopenharmony_ci pluto_setsda(pluto, 1); 6408c2ecf20Sopenharmony_ci pluto_setscl(pluto, 1); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci ret = i2c_bit_add_bus(&pluto->i2c_adap); 6438c2ecf20Sopenharmony_ci if (ret < 0) 6448c2ecf20Sopenharmony_ci goto err_pluto_hw_exit; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci /* dvb */ 6478c2ecf20Sopenharmony_ci ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, 6488c2ecf20Sopenharmony_ci THIS_MODULE, &pdev->dev, adapter_nr); 6498c2ecf20Sopenharmony_ci if (ret < 0) 6508c2ecf20Sopenharmony_ci goto err_i2c_del_adapter; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci dvb_adapter = &pluto->dvb_adapter; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci pluto_read_rev(pluto); 6558c2ecf20Sopenharmony_ci pluto_read_serial(pluto); 6568c2ecf20Sopenharmony_ci pluto_read_mac(pluto, dvb_adapter->proposed_mac); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci dvbdemux = &pluto->demux; 6598c2ecf20Sopenharmony_ci dvbdemux->filternum = 256; 6608c2ecf20Sopenharmony_ci dvbdemux->feednum = 256; 6618c2ecf20Sopenharmony_ci dvbdemux->start_feed = pluto_start_feed; 6628c2ecf20Sopenharmony_ci dvbdemux->stop_feed = pluto_stop_feed; 6638c2ecf20Sopenharmony_ci dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | 6648c2ecf20Sopenharmony_ci DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); 6658c2ecf20Sopenharmony_ci ret = dvb_dmx_init(dvbdemux); 6668c2ecf20Sopenharmony_ci if (ret < 0) 6678c2ecf20Sopenharmony_ci goto err_dvb_unregister_adapter; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci dmx = &dvbdemux->dmx; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci pluto->hw_frontend.source = DMX_FRONTEND_0; 6728c2ecf20Sopenharmony_ci pluto->mem_frontend.source = DMX_MEMORY_FE; 6738c2ecf20Sopenharmony_ci pluto->dmxdev.filternum = NHWFILTERS; 6748c2ecf20Sopenharmony_ci pluto->dmxdev.demux = dmx; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci ret = dvb_dmxdev_init(&pluto->dmxdev, dvb_adapter); 6778c2ecf20Sopenharmony_ci if (ret < 0) 6788c2ecf20Sopenharmony_ci goto err_dvb_dmx_release; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci ret = dmx->add_frontend(dmx, &pluto->hw_frontend); 6818c2ecf20Sopenharmony_ci if (ret < 0) 6828c2ecf20Sopenharmony_ci goto err_dvb_dmxdev_release; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci ret = dmx->add_frontend(dmx, &pluto->mem_frontend); 6858c2ecf20Sopenharmony_ci if (ret < 0) 6868c2ecf20Sopenharmony_ci goto err_remove_hw_frontend; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci ret = dmx->connect_frontend(dmx, &pluto->hw_frontend); 6898c2ecf20Sopenharmony_ci if (ret < 0) 6908c2ecf20Sopenharmony_ci goto err_remove_mem_frontend; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci ret = frontend_init(pluto); 6938c2ecf20Sopenharmony_ci if (ret < 0) 6948c2ecf20Sopenharmony_ci goto err_disconnect_frontend; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci dvb_net_init(dvb_adapter, &pluto->dvbnet, dmx); 6978c2ecf20Sopenharmony_ciout: 6988c2ecf20Sopenharmony_ci return ret; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cierr_disconnect_frontend: 7018c2ecf20Sopenharmony_ci dmx->disconnect_frontend(dmx); 7028c2ecf20Sopenharmony_cierr_remove_mem_frontend: 7038c2ecf20Sopenharmony_ci dmx->remove_frontend(dmx, &pluto->mem_frontend); 7048c2ecf20Sopenharmony_cierr_remove_hw_frontend: 7058c2ecf20Sopenharmony_ci dmx->remove_frontend(dmx, &pluto->hw_frontend); 7068c2ecf20Sopenharmony_cierr_dvb_dmxdev_release: 7078c2ecf20Sopenharmony_ci dvb_dmxdev_release(&pluto->dmxdev); 7088c2ecf20Sopenharmony_cierr_dvb_dmx_release: 7098c2ecf20Sopenharmony_ci dvb_dmx_release(dvbdemux); 7108c2ecf20Sopenharmony_cierr_dvb_unregister_adapter: 7118c2ecf20Sopenharmony_ci dvb_unregister_adapter(dvb_adapter); 7128c2ecf20Sopenharmony_cierr_i2c_del_adapter: 7138c2ecf20Sopenharmony_ci i2c_del_adapter(&pluto->i2c_adap); 7148c2ecf20Sopenharmony_cierr_pluto_hw_exit: 7158c2ecf20Sopenharmony_ci pluto_hw_exit(pluto); 7168c2ecf20Sopenharmony_cierr_free_irq: 7178c2ecf20Sopenharmony_ci free_irq(pdev->irq, pluto); 7188c2ecf20Sopenharmony_cierr_pci_iounmap: 7198c2ecf20Sopenharmony_ci pci_iounmap(pdev, pluto->io_mem); 7208c2ecf20Sopenharmony_cierr_pci_release_regions: 7218c2ecf20Sopenharmony_ci pci_release_regions(pdev); 7228c2ecf20Sopenharmony_cierr_pci_disable_device: 7238c2ecf20Sopenharmony_ci pci_disable_device(pdev); 7248c2ecf20Sopenharmony_cierr_kfree: 7258c2ecf20Sopenharmony_ci kfree(pluto); 7268c2ecf20Sopenharmony_ci goto out; 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic void pluto2_remove(struct pci_dev *pdev) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct pluto *pluto = pci_get_drvdata(pdev); 7328c2ecf20Sopenharmony_ci struct dvb_adapter *dvb_adapter = &pluto->dvb_adapter; 7338c2ecf20Sopenharmony_ci struct dvb_demux *dvbdemux = &pluto->demux; 7348c2ecf20Sopenharmony_ci struct dmx_demux *dmx = &dvbdemux->dmx; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci dmx->close(dmx); 7378c2ecf20Sopenharmony_ci dvb_net_release(&pluto->dvbnet); 7388c2ecf20Sopenharmony_ci if (pluto->fe) 7398c2ecf20Sopenharmony_ci dvb_unregister_frontend(pluto->fe); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci dmx->disconnect_frontend(dmx); 7428c2ecf20Sopenharmony_ci dmx->remove_frontend(dmx, &pluto->mem_frontend); 7438c2ecf20Sopenharmony_ci dmx->remove_frontend(dmx, &pluto->hw_frontend); 7448c2ecf20Sopenharmony_ci dvb_dmxdev_release(&pluto->dmxdev); 7458c2ecf20Sopenharmony_ci dvb_dmx_release(dvbdemux); 7468c2ecf20Sopenharmony_ci dvb_unregister_adapter(dvb_adapter); 7478c2ecf20Sopenharmony_ci i2c_del_adapter(&pluto->i2c_adap); 7488c2ecf20Sopenharmony_ci pluto_hw_exit(pluto); 7498c2ecf20Sopenharmony_ci free_irq(pdev->irq, pluto); 7508c2ecf20Sopenharmony_ci pci_iounmap(pdev, pluto->io_mem); 7518c2ecf20Sopenharmony_ci pci_release_regions(pdev); 7528c2ecf20Sopenharmony_ci pci_disable_device(pdev); 7538c2ecf20Sopenharmony_ci kfree(pluto); 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci#ifndef PCI_VENDOR_ID_SCM 7578c2ecf20Sopenharmony_ci#define PCI_VENDOR_ID_SCM 0x0432 7588c2ecf20Sopenharmony_ci#endif 7598c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_PLUTO2 7608c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_PLUTO2 0x0001 7618c2ecf20Sopenharmony_ci#endif 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cistatic const struct pci_device_id pluto2_id_table[] = { 7648c2ecf20Sopenharmony_ci { 7658c2ecf20Sopenharmony_ci .vendor = PCI_VENDOR_ID_SCM, 7668c2ecf20Sopenharmony_ci .device = PCI_DEVICE_ID_PLUTO2, 7678c2ecf20Sopenharmony_ci .subvendor = PCI_ANY_ID, 7688c2ecf20Sopenharmony_ci .subdevice = PCI_ANY_ID, 7698c2ecf20Sopenharmony_ci }, { 7708c2ecf20Sopenharmony_ci /* empty */ 7718c2ecf20Sopenharmony_ci }, 7728c2ecf20Sopenharmony_ci}; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pluto2_id_table); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_cistatic struct pci_driver pluto2_driver = { 7778c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 7788c2ecf20Sopenharmony_ci .id_table = pluto2_id_table, 7798c2ecf20Sopenharmony_ci .probe = pluto2_probe, 7808c2ecf20Sopenharmony_ci .remove = pluto2_remove, 7818c2ecf20Sopenharmony_ci}; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cimodule_pci_driver(pluto2_driver); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>"); 7868c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Pluto2 driver"); 7878c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 788