162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * pluto2.c - Satelco Easywatch Mobile Terrestrial Receiver [DVB-T] 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2005 Andreas Oberritter <obi@linuxtv.org> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * based on pluto2.c 1.10 - http://instinct-wp8.no-ip.org/pluto/ 862306a36Sopenharmony_ci * by Dany Salman <salmandany@yahoo.fr> 962306a36Sopenharmony_ci * Copyright (c) 2004 TDF 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/i2c.h> 1362306a36Sopenharmony_ci#include <linux/i2c-algo-bit.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/interrupt.h> 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/pci.h> 1962306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <media/demux.h> 2362306a36Sopenharmony_ci#include <media/dmxdev.h> 2462306a36Sopenharmony_ci#include <media/dvb_demux.h> 2562306a36Sopenharmony_ci#include <media/dvb_frontend.h> 2662306a36Sopenharmony_ci#include <media/dvb_net.h> 2762306a36Sopenharmony_ci#include <media/dvbdev.h> 2862306a36Sopenharmony_ci#include "tda1004x.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define DRIVER_NAME "pluto2" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define REG_PIDn(n) ((n) << 2) /* PID n pattern registers */ 3562306a36Sopenharmony_ci#define REG_PCAR 0x0020 /* PC address register */ 3662306a36Sopenharmony_ci#define REG_TSCR 0x0024 /* TS ctrl & status */ 3762306a36Sopenharmony_ci#define REG_MISC 0x0028 /* miscellaneous */ 3862306a36Sopenharmony_ci#define REG_MMAC 0x002c /* MSB MAC address */ 3962306a36Sopenharmony_ci#define REG_IMAC 0x0030 /* ISB MAC address */ 4062306a36Sopenharmony_ci#define REG_LMAC 0x0034 /* LSB MAC address */ 4162306a36Sopenharmony_ci#define REG_SPID 0x0038 /* SPI data */ 4262306a36Sopenharmony_ci#define REG_SLCS 0x003c /* serial links ctrl/status */ 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define PID0_NOFIL (0x0001 << 16) 4562306a36Sopenharmony_ci#define PIDn_ENP (0x0001 << 15) 4662306a36Sopenharmony_ci#define PID0_END (0x0001 << 14) 4762306a36Sopenharmony_ci#define PID0_AFIL (0x0001 << 13) 4862306a36Sopenharmony_ci#define PIDn_PID (0x1fff << 0) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define TSCR_NBPACKETS (0x00ff << 24) 5162306a36Sopenharmony_ci#define TSCR_DEM (0x0001 << 17) 5262306a36Sopenharmony_ci#define TSCR_DE (0x0001 << 16) 5362306a36Sopenharmony_ci#define TSCR_RSTN (0x0001 << 15) 5462306a36Sopenharmony_ci#define TSCR_MSKO (0x0001 << 14) 5562306a36Sopenharmony_ci#define TSCR_MSKA (0x0001 << 13) 5662306a36Sopenharmony_ci#define TSCR_MSKL (0x0001 << 12) 5762306a36Sopenharmony_ci#define TSCR_OVR (0x0001 << 11) 5862306a36Sopenharmony_ci#define TSCR_AFUL (0x0001 << 10) 5962306a36Sopenharmony_ci#define TSCR_LOCK (0x0001 << 9) 6062306a36Sopenharmony_ci#define TSCR_IACK (0x0001 << 8) 6162306a36Sopenharmony_ci#define TSCR_ADEF (0x007f << 0) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define MISC_DVR (0x0fff << 4) 6462306a36Sopenharmony_ci#define MISC_ALED (0x0001 << 3) 6562306a36Sopenharmony_ci#define MISC_FRST (0x0001 << 2) 6662306a36Sopenharmony_ci#define MISC_LED1 (0x0001 << 1) 6762306a36Sopenharmony_ci#define MISC_LED0 (0x0001 << 0) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define SPID_SPIDR (0x00ff << 0) 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define SLCS_SCL (0x0001 << 7) 7262306a36Sopenharmony_ci#define SLCS_SDA (0x0001 << 6) 7362306a36Sopenharmony_ci#define SLCS_CSN (0x0001 << 2) 7462306a36Sopenharmony_ci#define SLCS_OVR (0x0001 << 1) 7562306a36Sopenharmony_ci#define SLCS_SWC (0x0001 << 0) 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define TS_DMA_PACKETS (8) 7862306a36Sopenharmony_ci#define TS_DMA_BYTES (188 * TS_DMA_PACKETS) 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define I2C_ADDR_TDA10046 0x10 8162306a36Sopenharmony_ci#define I2C_ADDR_TUA6034 0xc2 8262306a36Sopenharmony_ci#define NHWFILTERS 8 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistruct pluto { 8562306a36Sopenharmony_ci /* pci */ 8662306a36Sopenharmony_ci struct pci_dev *pdev; 8762306a36Sopenharmony_ci u8 __iomem *io_mem; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* dvb */ 9062306a36Sopenharmony_ci struct dmx_frontend hw_frontend; 9162306a36Sopenharmony_ci struct dmx_frontend mem_frontend; 9262306a36Sopenharmony_ci struct dmxdev dmxdev; 9362306a36Sopenharmony_ci struct dvb_adapter dvb_adapter; 9462306a36Sopenharmony_ci struct dvb_demux demux; 9562306a36Sopenharmony_ci struct dvb_frontend *fe; 9662306a36Sopenharmony_ci struct dvb_net dvbnet; 9762306a36Sopenharmony_ci unsigned int full_ts_users; 9862306a36Sopenharmony_ci unsigned int users; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* i2c */ 10162306a36Sopenharmony_ci struct i2c_algo_bit_data i2c_bit; 10262306a36Sopenharmony_ci struct i2c_adapter i2c_adap; 10362306a36Sopenharmony_ci unsigned int i2cbug; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* irq */ 10662306a36Sopenharmony_ci unsigned int overflow; 10762306a36Sopenharmony_ci unsigned int dead; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* dma */ 11062306a36Sopenharmony_ci dma_addr_t dma_addr; 11162306a36Sopenharmony_ci u8 dma_buf[TS_DMA_BYTES]; 11262306a36Sopenharmony_ci u8 dummy[4096]; 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic inline struct pluto *feed_to_pluto(struct dvb_demux_feed *feed) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci return container_of(feed->demux, struct pluto, demux); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic inline struct pluto *frontend_to_pluto(struct dvb_frontend *fe) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci return container_of(fe->dvb, struct pluto, dvb_adapter); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic inline u32 pluto_readreg(struct pluto *pluto, u32 reg) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci return readl(&pluto->io_mem[reg]); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic inline void pluto_writereg(struct pluto *pluto, u32 reg, u32 val) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci writel(val, &pluto->io_mem[reg]); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic inline void pluto_rw(struct pluto *pluto, u32 reg, u32 mask, u32 bits) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci u32 val = readl(&pluto->io_mem[reg]); 13862306a36Sopenharmony_ci val &= ~mask; 13962306a36Sopenharmony_ci val |= bits; 14062306a36Sopenharmony_ci writel(val, &pluto->io_mem[reg]); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic void pluto_write_tscr(struct pluto *pluto, u32 val) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci /* set the number of packets */ 14662306a36Sopenharmony_ci val &= ~TSCR_ADEF; 14762306a36Sopenharmony_ci val |= TS_DMA_PACKETS / 2; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci pluto_writereg(pluto, REG_TSCR, val); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic void pluto_setsda(void *data, int state) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct pluto *pluto = data; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (state) 15762306a36Sopenharmony_ci pluto_rw(pluto, REG_SLCS, SLCS_SDA, SLCS_SDA); 15862306a36Sopenharmony_ci else 15962306a36Sopenharmony_ci pluto_rw(pluto, REG_SLCS, SLCS_SDA, 0); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic void pluto_setscl(void *data, int state) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct pluto *pluto = data; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (state) 16762306a36Sopenharmony_ci pluto_rw(pluto, REG_SLCS, SLCS_SCL, SLCS_SCL); 16862306a36Sopenharmony_ci else 16962306a36Sopenharmony_ci pluto_rw(pluto, REG_SLCS, SLCS_SCL, 0); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* try to detect i2c_inb() to workaround hardware bug: 17262306a36Sopenharmony_ci * reset SDA to high after SCL has been set to low */ 17362306a36Sopenharmony_ci if ((state) && (pluto->i2cbug == 0)) { 17462306a36Sopenharmony_ci pluto->i2cbug = 1; 17562306a36Sopenharmony_ci } else { 17662306a36Sopenharmony_ci if ((!state) && (pluto->i2cbug == 1)) 17762306a36Sopenharmony_ci pluto_setsda(pluto, 1); 17862306a36Sopenharmony_ci pluto->i2cbug = 0; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic int pluto_getsda(void *data) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci struct pluto *pluto = data; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return pluto_readreg(pluto, REG_SLCS) & SLCS_SDA; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int pluto_getscl(void *data) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct pluto *pluto = data; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci return pluto_readreg(pluto, REG_SLCS) & SLCS_SCL; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic void pluto_reset_frontend(struct pluto *pluto, int reenable) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci u32 val = pluto_readreg(pluto, REG_MISC); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (val & MISC_FRST) { 20162306a36Sopenharmony_ci val &= ~MISC_FRST; 20262306a36Sopenharmony_ci pluto_writereg(pluto, REG_MISC, val); 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci if (reenable) { 20562306a36Sopenharmony_ci val |= MISC_FRST; 20662306a36Sopenharmony_ci pluto_writereg(pluto, REG_MISC, val); 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic void pluto_reset_ts(struct pluto *pluto, int reenable) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci u32 val = pluto_readreg(pluto, REG_TSCR); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (val & TSCR_RSTN) { 21562306a36Sopenharmony_ci val &= ~TSCR_RSTN; 21662306a36Sopenharmony_ci pluto_write_tscr(pluto, val); 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci if (reenable) { 21962306a36Sopenharmony_ci val |= TSCR_RSTN; 22062306a36Sopenharmony_ci pluto_write_tscr(pluto, val); 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic void pluto_set_dma_addr(struct pluto *pluto) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci pluto_writereg(pluto, REG_PCAR, pluto->dma_addr); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic int pluto_dma_map(struct pluto *pluto) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci pluto->dma_addr = dma_map_single(&pluto->pdev->dev, pluto->dma_buf, 23262306a36Sopenharmony_ci TS_DMA_BYTES, DMA_FROM_DEVICE); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return dma_mapping_error(&pluto->pdev->dev, pluto->dma_addr); 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic void pluto_dma_unmap(struct pluto *pluto) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci dma_unmap_single(&pluto->pdev->dev, pluto->dma_addr, TS_DMA_BYTES, 24062306a36Sopenharmony_ci DMA_FROM_DEVICE); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic int pluto_start_feed(struct dvb_demux_feed *f) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci struct pluto *pluto = feed_to_pluto(f); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* enable PID filtering */ 24862306a36Sopenharmony_ci if (pluto->users++ == 0) 24962306a36Sopenharmony_ci pluto_rw(pluto, REG_PIDn(0), PID0_AFIL | PID0_NOFIL, 0); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if ((f->pid < 0x2000) && (f->index < NHWFILTERS)) 25262306a36Sopenharmony_ci pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, PIDn_ENP | f->pid); 25362306a36Sopenharmony_ci else if (pluto->full_ts_users++ == 0) 25462306a36Sopenharmony_ci pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, PID0_NOFIL); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return 0; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic int pluto_stop_feed(struct dvb_demux_feed *f) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct pluto *pluto = feed_to_pluto(f); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* disable PID filtering */ 26462306a36Sopenharmony_ci if (--pluto->users == 0) 26562306a36Sopenharmony_ci pluto_rw(pluto, REG_PIDn(0), PID0_AFIL, PID0_AFIL); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if ((f->pid < 0x2000) && (f->index < NHWFILTERS)) 26862306a36Sopenharmony_ci pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, 0x1fff); 26962306a36Sopenharmony_ci else if (--pluto->full_ts_users == 0) 27062306a36Sopenharmony_ci pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, 0); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci return 0; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci /* synchronize the DMA transfer with the CPU 27862306a36Sopenharmony_ci * first so that we see updated contents. */ 27962306a36Sopenharmony_ci dma_sync_single_for_cpu(&pluto->pdev->dev, pluto->dma_addr, 28062306a36Sopenharmony_ci TS_DMA_BYTES, DMA_FROM_DEVICE); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* Workaround for broken hardware: 28362306a36Sopenharmony_ci * [1] On startup NBPACKETS seems to contain an uninitialized value, 28462306a36Sopenharmony_ci * but no packets have been transferred. 28562306a36Sopenharmony_ci * [2] Sometimes (actually very often) NBPACKETS stays at zero 28662306a36Sopenharmony_ci * although one packet has been transferred. 28762306a36Sopenharmony_ci * [3] Sometimes (actually rarely), the card gets into an erroneous 28862306a36Sopenharmony_ci * mode where it continuously generates interrupts, claiming it 28962306a36Sopenharmony_ci * has received nbpackets>TS_DMA_PACKETS packets, but no packet 29062306a36Sopenharmony_ci * has been transferred. Only a reset seems to solve this 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_ci if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) { 29362306a36Sopenharmony_ci unsigned int i = 0; 29462306a36Sopenharmony_ci while (pluto->dma_buf[i] == 0x47) 29562306a36Sopenharmony_ci i += 188; 29662306a36Sopenharmony_ci nbpackets = i / 188; 29762306a36Sopenharmony_ci if (i == 0) { 29862306a36Sopenharmony_ci pluto_reset_ts(pluto, 1); 29962306a36Sopenharmony_ci dev_printk(KERN_DEBUG, &pluto->pdev->dev, "resetting TS because of invalid packet counter\n"); 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* clear the dma buffer. this is needed to be able to identify 30662306a36Sopenharmony_ci * new valid ts packets above */ 30762306a36Sopenharmony_ci memset(pluto->dma_buf, 0, nbpackets * 188); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* reset the dma address */ 31062306a36Sopenharmony_ci pluto_set_dma_addr(pluto); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* sync the buffer and give it back to the card */ 31362306a36Sopenharmony_ci dma_sync_single_for_device(&pluto->pdev->dev, pluto->dma_addr, 31462306a36Sopenharmony_ci TS_DMA_BYTES, DMA_FROM_DEVICE); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic irqreturn_t pluto_irq(int irq, void *dev_id) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct pluto *pluto = dev_id; 32062306a36Sopenharmony_ci u32 tscr; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* check whether an interrupt occurred on this device */ 32362306a36Sopenharmony_ci tscr = pluto_readreg(pluto, REG_TSCR); 32462306a36Sopenharmony_ci if (!(tscr & (TSCR_DE | TSCR_OVR))) 32562306a36Sopenharmony_ci return IRQ_NONE; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (tscr == 0xffffffff) { 32862306a36Sopenharmony_ci if (pluto->dead == 0) 32962306a36Sopenharmony_ci dev_err(&pluto->pdev->dev, "card has hung or been ejected.\n"); 33062306a36Sopenharmony_ci /* It's dead Jim */ 33162306a36Sopenharmony_ci pluto->dead = 1; 33262306a36Sopenharmony_ci return IRQ_HANDLED; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* dma end interrupt */ 33662306a36Sopenharmony_ci if (tscr & TSCR_DE) { 33762306a36Sopenharmony_ci pluto_dma_end(pluto, (tscr & TSCR_NBPACKETS) >> 24); 33862306a36Sopenharmony_ci /* overflow interrupt */ 33962306a36Sopenharmony_ci if (tscr & TSCR_OVR) 34062306a36Sopenharmony_ci pluto->overflow++; 34162306a36Sopenharmony_ci if (pluto->overflow) { 34262306a36Sopenharmony_ci dev_err(&pluto->pdev->dev, "overflow irq (%d)\n", 34362306a36Sopenharmony_ci pluto->overflow); 34462306a36Sopenharmony_ci pluto_reset_ts(pluto, 1); 34562306a36Sopenharmony_ci pluto->overflow = 0; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci } else if (tscr & TSCR_OVR) { 34862306a36Sopenharmony_ci pluto->overflow++; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* ACK the interrupt */ 35262306a36Sopenharmony_ci pluto_write_tscr(pluto, tscr | TSCR_IACK); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci return IRQ_HANDLED; 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic void pluto_enable_irqs(struct pluto *pluto) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci u32 val = pluto_readreg(pluto, REG_TSCR); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* disable AFUL and LOCK interrupts */ 36262306a36Sopenharmony_ci val |= (TSCR_MSKA | TSCR_MSKL); 36362306a36Sopenharmony_ci /* enable DMA and OVERFLOW interrupts */ 36462306a36Sopenharmony_ci val &= ~(TSCR_DEM | TSCR_MSKO); 36562306a36Sopenharmony_ci /* clear pending interrupts */ 36662306a36Sopenharmony_ci val |= TSCR_IACK; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci pluto_write_tscr(pluto, val); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic void pluto_disable_irqs(struct pluto *pluto) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci u32 val = pluto_readreg(pluto, REG_TSCR); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* disable all interrupts */ 37662306a36Sopenharmony_ci val |= (TSCR_DEM | TSCR_MSKO | TSCR_MSKA | TSCR_MSKL); 37762306a36Sopenharmony_ci /* clear pending interrupts */ 37862306a36Sopenharmony_ci val |= TSCR_IACK; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci pluto_write_tscr(pluto, val); 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic int pluto_hw_init(struct pluto *pluto) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci pluto_reset_frontend(pluto, 1); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* set automatic LED control by FPGA */ 38862306a36Sopenharmony_ci pluto_rw(pluto, REG_MISC, MISC_ALED, MISC_ALED); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* set data endianness */ 39162306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN 39262306a36Sopenharmony_ci pluto_rw(pluto, REG_PIDn(0), PID0_END, PID0_END); 39362306a36Sopenharmony_ci#else 39462306a36Sopenharmony_ci pluto_rw(pluto, REG_PIDn(0), PID0_END, 0); 39562306a36Sopenharmony_ci#endif 39662306a36Sopenharmony_ci /* map DMA and set address */ 39762306a36Sopenharmony_ci pluto_dma_map(pluto); 39862306a36Sopenharmony_ci pluto_set_dma_addr(pluto); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* enable interrupts */ 40162306a36Sopenharmony_ci pluto_enable_irqs(pluto); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* reset TS logic */ 40462306a36Sopenharmony_ci pluto_reset_ts(pluto, 1); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci return 0; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic void pluto_hw_exit(struct pluto *pluto) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci /* disable interrupts */ 41262306a36Sopenharmony_ci pluto_disable_irqs(pluto); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci pluto_reset_ts(pluto, 0); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* LED: disable automatic control, enable yellow, disable green */ 41762306a36Sopenharmony_ci pluto_rw(pluto, REG_MISC, MISC_ALED | MISC_LED1 | MISC_LED0, MISC_LED1); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* unmap DMA */ 42062306a36Sopenharmony_ci pluto_dma_unmap(pluto); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci pluto_reset_frontend(pluto, 0); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic inline u32 divide(u32 numerator, u32 denominator) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci if (denominator == 0) 42862306a36Sopenharmony_ci return ~0; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci return DIV_ROUND_CLOSEST(numerator, denominator); 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci/* LG Innotek TDTE-E001P (Infineon TUA6034) */ 43462306a36Sopenharmony_cistatic int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 43762306a36Sopenharmony_ci struct pluto *pluto = frontend_to_pluto(fe); 43862306a36Sopenharmony_ci struct i2c_msg msg; 43962306a36Sopenharmony_ci int ret; 44062306a36Sopenharmony_ci u8 buf[4]; 44162306a36Sopenharmony_ci u32 div; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci // Fref = 166.667 Hz 44462306a36Sopenharmony_ci // Fref * 3 = 500.000 Hz 44562306a36Sopenharmony_ci // IF = 36166667 44662306a36Sopenharmony_ci // IF / Fref = 217 44762306a36Sopenharmony_ci //div = divide(p->frequency + 36166667, 166667); 44862306a36Sopenharmony_ci div = divide(p->frequency * 3, 500000) + 217; 44962306a36Sopenharmony_ci buf[0] = (div >> 8) & 0x7f; 45062306a36Sopenharmony_ci buf[1] = (div >> 0) & 0xff; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (p->frequency < 611000000) 45362306a36Sopenharmony_ci buf[2] = 0xb4; 45462306a36Sopenharmony_ci else if (p->frequency < 811000000) 45562306a36Sopenharmony_ci buf[2] = 0xbc; 45662306a36Sopenharmony_ci else 45762306a36Sopenharmony_ci buf[2] = 0xf4; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci // VHF: 174-230 MHz 46062306a36Sopenharmony_ci // center: 350 MHz 46162306a36Sopenharmony_ci // UHF: 470-862 MHz 46262306a36Sopenharmony_ci if (p->frequency < 350000000) 46362306a36Sopenharmony_ci buf[3] = 0x02; 46462306a36Sopenharmony_ci else 46562306a36Sopenharmony_ci buf[3] = 0x04; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (p->bandwidth_hz == 8000000) 46862306a36Sopenharmony_ci buf[3] |= 0x08; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci msg.addr = I2C_ADDR_TUA6034 >> 1; 47162306a36Sopenharmony_ci msg.flags = 0; 47262306a36Sopenharmony_ci msg.buf = buf; 47362306a36Sopenharmony_ci msg.len = sizeof(buf); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 47662306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 47762306a36Sopenharmony_ci ret = i2c_transfer(&pluto->i2c_adap, &msg, 1); 47862306a36Sopenharmony_ci if (ret < 0) 47962306a36Sopenharmony_ci return ret; 48062306a36Sopenharmony_ci else if (ret == 0) 48162306a36Sopenharmony_ci return -EREMOTEIO; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci return 0; 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic int pluto2_request_firmware(struct dvb_frontend *fe, 48762306a36Sopenharmony_ci const struct firmware **fw, char *name) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct pluto *pluto = frontend_to_pluto(fe); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci return request_firmware(fw, name, &pluto->pdev->dev); 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic struct tda1004x_config pluto2_fe_config = { 49562306a36Sopenharmony_ci .demod_address = I2C_ADDR_TDA10046 >> 1, 49662306a36Sopenharmony_ci .invert = 1, 49762306a36Sopenharmony_ci .invert_oclk = 0, 49862306a36Sopenharmony_ci .xtal_freq = TDA10046_XTAL_16M, 49962306a36Sopenharmony_ci .agc_config = TDA10046_AGC_DEFAULT, 50062306a36Sopenharmony_ci .if_freq = TDA10046_FREQ_3617, 50162306a36Sopenharmony_ci .request_firmware = pluto2_request_firmware, 50262306a36Sopenharmony_ci}; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic int frontend_init(struct pluto *pluto) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci int ret; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci pluto->fe = tda10046_attach(&pluto2_fe_config, &pluto->i2c_adap); 50962306a36Sopenharmony_ci if (!pluto->fe) { 51062306a36Sopenharmony_ci dev_err(&pluto->pdev->dev, "could not attach frontend\n"); 51162306a36Sopenharmony_ci return -ENODEV; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci pluto->fe->ops.tuner_ops.set_params = lg_tdtpe001p_tuner_set_params; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe); 51662306a36Sopenharmony_ci if (ret < 0) { 51762306a36Sopenharmony_ci if (pluto->fe->ops.release) 51862306a36Sopenharmony_ci pluto->fe->ops.release(pluto->fe); 51962306a36Sopenharmony_ci return ret; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci return 0; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic void pluto_read_rev(struct pluto *pluto) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci u32 val = pluto_readreg(pluto, REG_MISC) & MISC_DVR; 52862306a36Sopenharmony_ci dev_info(&pluto->pdev->dev, "board revision %d.%d\n", 52962306a36Sopenharmony_ci (val >> 12) & 0x0f, (val >> 4) & 0xff); 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic void pluto_read_mac(struct pluto *pluto, u8 *mac) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci u32 val = pluto_readreg(pluto, REG_MMAC); 53562306a36Sopenharmony_ci mac[0] = (val >> 8) & 0xff; 53662306a36Sopenharmony_ci mac[1] = (val >> 0) & 0xff; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci val = pluto_readreg(pluto, REG_IMAC); 53962306a36Sopenharmony_ci mac[2] = (val >> 8) & 0xff; 54062306a36Sopenharmony_ci mac[3] = (val >> 0) & 0xff; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci val = pluto_readreg(pluto, REG_LMAC); 54362306a36Sopenharmony_ci mac[4] = (val >> 8) & 0xff; 54462306a36Sopenharmony_ci mac[5] = (val >> 0) & 0xff; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci dev_info(&pluto->pdev->dev, "MAC %pM\n", mac); 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic int pluto_read_serial(struct pluto *pluto) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci struct pci_dev *pdev = pluto->pdev; 55262306a36Sopenharmony_ci unsigned int i, j; 55362306a36Sopenharmony_ci u8 __iomem *cis; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci cis = pci_iomap(pdev, 1, 0); 55662306a36Sopenharmony_ci if (!cis) 55762306a36Sopenharmony_ci return -EIO; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci dev_info(&pdev->dev, "S/N "); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci for (i = 0xe0; i < 0x100; i += 4) { 56262306a36Sopenharmony_ci u32 val = readl(&cis[i]); 56362306a36Sopenharmony_ci for (j = 0; j < 32; j += 8) { 56462306a36Sopenharmony_ci if ((val & 0xff) == 0xff) 56562306a36Sopenharmony_ci goto out; 56662306a36Sopenharmony_ci printk(KERN_CONT "%c", val & 0xff); 56762306a36Sopenharmony_ci val >>= 8; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ciout: 57162306a36Sopenharmony_ci printk(KERN_CONT "\n"); 57262306a36Sopenharmony_ci pci_iounmap(pdev, cis); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci return 0; 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic int pluto2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci struct pluto *pluto; 58062306a36Sopenharmony_ci struct dvb_adapter *dvb_adapter; 58162306a36Sopenharmony_ci struct dvb_demux *dvbdemux; 58262306a36Sopenharmony_ci struct dmx_demux *dmx; 58362306a36Sopenharmony_ci int ret = -ENOMEM; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci pluto = kzalloc(sizeof(struct pluto), GFP_KERNEL); 58662306a36Sopenharmony_ci if (!pluto) 58762306a36Sopenharmony_ci goto out; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci pluto->pdev = pdev; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci ret = pci_enable_device(pdev); 59262306a36Sopenharmony_ci if (ret < 0) 59362306a36Sopenharmony_ci goto err_kfree; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* enable interrupts */ 59662306a36Sopenharmony_ci pci_write_config_dword(pdev, 0x6c, 0x8000); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 59962306a36Sopenharmony_ci if (ret < 0) 60062306a36Sopenharmony_ci goto err_pci_disable_device; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci pci_set_master(pdev); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci ret = pci_request_regions(pdev, DRIVER_NAME); 60562306a36Sopenharmony_ci if (ret < 0) 60662306a36Sopenharmony_ci goto err_pci_disable_device; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci pluto->io_mem = pci_iomap(pdev, 0, 0x40); 60962306a36Sopenharmony_ci if (!pluto->io_mem) { 61062306a36Sopenharmony_ci ret = -EIO; 61162306a36Sopenharmony_ci goto err_pci_release_regions; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci pci_set_drvdata(pdev, pluto); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci ret = request_irq(pdev->irq, pluto_irq, IRQF_SHARED, DRIVER_NAME, pluto); 61762306a36Sopenharmony_ci if (ret < 0) 61862306a36Sopenharmony_ci goto err_pci_iounmap; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci ret = pluto_hw_init(pluto); 62162306a36Sopenharmony_ci if (ret < 0) 62262306a36Sopenharmony_ci goto err_free_irq; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* i2c */ 62562306a36Sopenharmony_ci i2c_set_adapdata(&pluto->i2c_adap, pluto); 62662306a36Sopenharmony_ci strscpy(pluto->i2c_adap.name, DRIVER_NAME, sizeof(pluto->i2c_adap.name)); 62762306a36Sopenharmony_ci pluto->i2c_adap.owner = THIS_MODULE; 62862306a36Sopenharmony_ci pluto->i2c_adap.dev.parent = &pdev->dev; 62962306a36Sopenharmony_ci pluto->i2c_adap.algo_data = &pluto->i2c_bit; 63062306a36Sopenharmony_ci pluto->i2c_bit.data = pluto; 63162306a36Sopenharmony_ci pluto->i2c_bit.setsda = pluto_setsda; 63262306a36Sopenharmony_ci pluto->i2c_bit.setscl = pluto_setscl; 63362306a36Sopenharmony_ci pluto->i2c_bit.getsda = pluto_getsda; 63462306a36Sopenharmony_ci pluto->i2c_bit.getscl = pluto_getscl; 63562306a36Sopenharmony_ci pluto->i2c_bit.udelay = 10; 63662306a36Sopenharmony_ci pluto->i2c_bit.timeout = 10; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* Raise SCL and SDA */ 63962306a36Sopenharmony_ci pluto_setsda(pluto, 1); 64062306a36Sopenharmony_ci pluto_setscl(pluto, 1); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci ret = i2c_bit_add_bus(&pluto->i2c_adap); 64362306a36Sopenharmony_ci if (ret < 0) 64462306a36Sopenharmony_ci goto err_pluto_hw_exit; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* dvb */ 64762306a36Sopenharmony_ci ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, 64862306a36Sopenharmony_ci THIS_MODULE, &pdev->dev, adapter_nr); 64962306a36Sopenharmony_ci if (ret < 0) 65062306a36Sopenharmony_ci goto err_i2c_del_adapter; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci dvb_adapter = &pluto->dvb_adapter; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci pluto_read_rev(pluto); 65562306a36Sopenharmony_ci pluto_read_serial(pluto); 65662306a36Sopenharmony_ci pluto_read_mac(pluto, dvb_adapter->proposed_mac); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci dvbdemux = &pluto->demux; 65962306a36Sopenharmony_ci dvbdemux->filternum = 256; 66062306a36Sopenharmony_ci dvbdemux->feednum = 256; 66162306a36Sopenharmony_ci dvbdemux->start_feed = pluto_start_feed; 66262306a36Sopenharmony_ci dvbdemux->stop_feed = pluto_stop_feed; 66362306a36Sopenharmony_ci dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | 66462306a36Sopenharmony_ci DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); 66562306a36Sopenharmony_ci ret = dvb_dmx_init(dvbdemux); 66662306a36Sopenharmony_ci if (ret < 0) 66762306a36Sopenharmony_ci goto err_dvb_unregister_adapter; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci dmx = &dvbdemux->dmx; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci pluto->hw_frontend.source = DMX_FRONTEND_0; 67262306a36Sopenharmony_ci pluto->mem_frontend.source = DMX_MEMORY_FE; 67362306a36Sopenharmony_ci pluto->dmxdev.filternum = NHWFILTERS; 67462306a36Sopenharmony_ci pluto->dmxdev.demux = dmx; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci ret = dvb_dmxdev_init(&pluto->dmxdev, dvb_adapter); 67762306a36Sopenharmony_ci if (ret < 0) 67862306a36Sopenharmony_ci goto err_dvb_dmx_release; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci ret = dmx->add_frontend(dmx, &pluto->hw_frontend); 68162306a36Sopenharmony_ci if (ret < 0) 68262306a36Sopenharmony_ci goto err_dvb_dmxdev_release; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci ret = dmx->add_frontend(dmx, &pluto->mem_frontend); 68562306a36Sopenharmony_ci if (ret < 0) 68662306a36Sopenharmony_ci goto err_remove_hw_frontend; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci ret = dmx->connect_frontend(dmx, &pluto->hw_frontend); 68962306a36Sopenharmony_ci if (ret < 0) 69062306a36Sopenharmony_ci goto err_remove_mem_frontend; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci ret = frontend_init(pluto); 69362306a36Sopenharmony_ci if (ret < 0) 69462306a36Sopenharmony_ci goto err_disconnect_frontend; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci dvb_net_init(dvb_adapter, &pluto->dvbnet, dmx); 69762306a36Sopenharmony_ciout: 69862306a36Sopenharmony_ci return ret; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cierr_disconnect_frontend: 70162306a36Sopenharmony_ci dmx->disconnect_frontend(dmx); 70262306a36Sopenharmony_cierr_remove_mem_frontend: 70362306a36Sopenharmony_ci dmx->remove_frontend(dmx, &pluto->mem_frontend); 70462306a36Sopenharmony_cierr_remove_hw_frontend: 70562306a36Sopenharmony_ci dmx->remove_frontend(dmx, &pluto->hw_frontend); 70662306a36Sopenharmony_cierr_dvb_dmxdev_release: 70762306a36Sopenharmony_ci dvb_dmxdev_release(&pluto->dmxdev); 70862306a36Sopenharmony_cierr_dvb_dmx_release: 70962306a36Sopenharmony_ci dvb_dmx_release(dvbdemux); 71062306a36Sopenharmony_cierr_dvb_unregister_adapter: 71162306a36Sopenharmony_ci dvb_unregister_adapter(dvb_adapter); 71262306a36Sopenharmony_cierr_i2c_del_adapter: 71362306a36Sopenharmony_ci i2c_del_adapter(&pluto->i2c_adap); 71462306a36Sopenharmony_cierr_pluto_hw_exit: 71562306a36Sopenharmony_ci pluto_hw_exit(pluto); 71662306a36Sopenharmony_cierr_free_irq: 71762306a36Sopenharmony_ci free_irq(pdev->irq, pluto); 71862306a36Sopenharmony_cierr_pci_iounmap: 71962306a36Sopenharmony_ci pci_iounmap(pdev, pluto->io_mem); 72062306a36Sopenharmony_cierr_pci_release_regions: 72162306a36Sopenharmony_ci pci_release_regions(pdev); 72262306a36Sopenharmony_cierr_pci_disable_device: 72362306a36Sopenharmony_ci pci_disable_device(pdev); 72462306a36Sopenharmony_cierr_kfree: 72562306a36Sopenharmony_ci kfree(pluto); 72662306a36Sopenharmony_ci goto out; 72762306a36Sopenharmony_ci} 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_cistatic void pluto2_remove(struct pci_dev *pdev) 73062306a36Sopenharmony_ci{ 73162306a36Sopenharmony_ci struct pluto *pluto = pci_get_drvdata(pdev); 73262306a36Sopenharmony_ci struct dvb_adapter *dvb_adapter = &pluto->dvb_adapter; 73362306a36Sopenharmony_ci struct dvb_demux *dvbdemux = &pluto->demux; 73462306a36Sopenharmony_ci struct dmx_demux *dmx = &dvbdemux->dmx; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci dmx->close(dmx); 73762306a36Sopenharmony_ci dvb_net_release(&pluto->dvbnet); 73862306a36Sopenharmony_ci if (pluto->fe) 73962306a36Sopenharmony_ci dvb_unregister_frontend(pluto->fe); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci dmx->disconnect_frontend(dmx); 74262306a36Sopenharmony_ci dmx->remove_frontend(dmx, &pluto->mem_frontend); 74362306a36Sopenharmony_ci dmx->remove_frontend(dmx, &pluto->hw_frontend); 74462306a36Sopenharmony_ci dvb_dmxdev_release(&pluto->dmxdev); 74562306a36Sopenharmony_ci dvb_dmx_release(dvbdemux); 74662306a36Sopenharmony_ci dvb_unregister_adapter(dvb_adapter); 74762306a36Sopenharmony_ci i2c_del_adapter(&pluto->i2c_adap); 74862306a36Sopenharmony_ci pluto_hw_exit(pluto); 74962306a36Sopenharmony_ci free_irq(pdev->irq, pluto); 75062306a36Sopenharmony_ci pci_iounmap(pdev, pluto->io_mem); 75162306a36Sopenharmony_ci pci_release_regions(pdev); 75262306a36Sopenharmony_ci pci_disable_device(pdev); 75362306a36Sopenharmony_ci kfree(pluto); 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci#ifndef PCI_VENDOR_ID_SCM 75762306a36Sopenharmony_ci#define PCI_VENDOR_ID_SCM 0x0432 75862306a36Sopenharmony_ci#endif 75962306a36Sopenharmony_ci#ifndef PCI_DEVICE_ID_PLUTO2 76062306a36Sopenharmony_ci#define PCI_DEVICE_ID_PLUTO2 0x0001 76162306a36Sopenharmony_ci#endif 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cistatic const struct pci_device_id pluto2_id_table[] = { 76462306a36Sopenharmony_ci { 76562306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_SCM, 76662306a36Sopenharmony_ci .device = PCI_DEVICE_ID_PLUTO2, 76762306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 76862306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 76962306a36Sopenharmony_ci }, { 77062306a36Sopenharmony_ci /* empty */ 77162306a36Sopenharmony_ci }, 77262306a36Sopenharmony_ci}; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pluto2_id_table); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic struct pci_driver pluto2_driver = { 77762306a36Sopenharmony_ci .name = DRIVER_NAME, 77862306a36Sopenharmony_ci .id_table = pluto2_id_table, 77962306a36Sopenharmony_ci .probe = pluto2_probe, 78062306a36Sopenharmony_ci .remove = pluto2_remove, 78162306a36Sopenharmony_ci}; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cimodule_pci_driver(pluto2_driver); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ciMODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>"); 78662306a36Sopenharmony_ciMODULE_DESCRIPTION("Pluto2 driver"); 78762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 788