xref: /linux/drivers/media/pci/dm1105/dm1105.c (revision cdd38c5f1ce4398ec58fec95904b75824daab7b5)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2a611d0caSIgor M. Liplianin /*
3a611d0caSIgor M. Liplianin  * dm1105.c - driver for DVB cards based on SDMC DM1105 PCI chip
4a611d0caSIgor M. Liplianin  *
5a611d0caSIgor M. Liplianin  * Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
6a611d0caSIgor M. Liplianin  */
7a611d0caSIgor M. Liplianin 
8a611d0caSIgor M. Liplianin #include <linux/i2c.h>
90017505dSIgor M. Liplianin #include <linux/i2c-algo-bit.h>
10a611d0caSIgor M. Liplianin #include <linux/init.h>
11a6b7a407SAlexey Dobriyan #include <linux/interrupt.h>
12a611d0caSIgor M. Liplianin #include <linux/kernel.h>
13a611d0caSIgor M. Liplianin #include <linux/module.h>
14a611d0caSIgor M. Liplianin #include <linux/pci.h>
15a611d0caSIgor M. Liplianin #include <linux/dma-mapping.h>
165a0e3ad6STejun Heo #include <linux/slab.h>
176bda9644SMauro Carvalho Chehab #include <media/rc-core.h>
18a611d0caSIgor M. Liplianin 
19fada1935SMauro Carvalho Chehab #include <media/demux.h>
20fada1935SMauro Carvalho Chehab #include <media/dmxdev.h>
21fada1935SMauro Carvalho Chehab #include <media/dvb_demux.h>
22fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
23fada1935SMauro Carvalho Chehab #include <media/dvb_net.h>
24fada1935SMauro Carvalho Chehab #include <media/dvbdev.h>
25a611d0caSIgor M. Liplianin #include "dvb-pll.h"
26a611d0caSIgor M. Liplianin 
27a611d0caSIgor M. Liplianin #include "stv0299.h"
28e4aab64cSIgor M. Liplianin #include "stv0288.h"
29e4aab64cSIgor M. Liplianin #include "stb6000.h"
3004ad28c9SIgor M. Liplianin #include "si21xx.h"
3135d9c427SIgor M. Liplianin #include "cx24116.h"
32a611d0caSIgor M. Liplianin #include "z0194a.h"
3373f0af44SKonstantin Dimitrov #include "ts2020.h"
34b4a0e816SIgor M. Liplianin #include "ds3000.h"
35a611d0caSIgor M. Liplianin 
36727e625cSMauro Carvalho Chehab #define MODULE_NAME "dm1105"
37727e625cSMauro Carvalho Chehab 
38d8300df9SIgor M. Liplianin #define UNSET (-1U)
39d8300df9SIgor M. Liplianin 
40d8300df9SIgor M. Liplianin #define DM1105_BOARD_NOAUTO			UNSET
41d8300df9SIgor M. Liplianin #define DM1105_BOARD_UNKNOWN			0
42d8300df9SIgor M. Liplianin #define DM1105_BOARD_DVBWORLD_2002		1
43d8300df9SIgor M. Liplianin #define DM1105_BOARD_DVBWORLD_2004		2
44d8300df9SIgor M. Liplianin #define DM1105_BOARD_AXESS_DM05			3
450017505dSIgor M. Liplianin #define DM1105_BOARD_UNBRANDED_I2C_ON_GPIO	4
46d8300df9SIgor M. Liplianin 
47a611d0caSIgor M. Liplianin /* ----------------------------------------------- */
48a611d0caSIgor M. Liplianin /*
49a611d0caSIgor M. Liplianin  * PCI ID's
50a611d0caSIgor M. Liplianin  */
51a611d0caSIgor M. Liplianin #ifndef PCI_VENDOR_ID_TRIGEM
52a611d0caSIgor M. Liplianin #define PCI_VENDOR_ID_TRIGEM	0x109f
53a611d0caSIgor M. Liplianin #endif
54519a4bdcSIgor M. Liplianin #ifndef PCI_VENDOR_ID_AXESS
55519a4bdcSIgor M. Liplianin #define PCI_VENDOR_ID_AXESS	0x195d
56519a4bdcSIgor M. Liplianin #endif
57a611d0caSIgor M. Liplianin #ifndef PCI_DEVICE_ID_DM1105
58a611d0caSIgor M. Liplianin #define PCI_DEVICE_ID_DM1105	0x036f
59a611d0caSIgor M. Liplianin #endif
60a611d0caSIgor M. Liplianin #ifndef PCI_DEVICE_ID_DW2002
61a611d0caSIgor M. Liplianin #define PCI_DEVICE_ID_DW2002	0x2002
62a611d0caSIgor M. Liplianin #endif
63a611d0caSIgor M. Liplianin #ifndef PCI_DEVICE_ID_DW2004
64a611d0caSIgor M. Liplianin #define PCI_DEVICE_ID_DW2004	0x2004
65a611d0caSIgor M. Liplianin #endif
66519a4bdcSIgor M. Liplianin #ifndef PCI_DEVICE_ID_DM05
67519a4bdcSIgor M. Liplianin #define PCI_DEVICE_ID_DM05	0x1105
68519a4bdcSIgor M. Liplianin #endif
69a611d0caSIgor M. Liplianin /* ----------------------------------------------- */
70a611d0caSIgor M. Liplianin /* sdmc dm1105 registers */
71a611d0caSIgor M. Liplianin 
72a611d0caSIgor M. Liplianin /* TS Control */
73a611d0caSIgor M. Liplianin #define DM1105_TSCTR				0x00
74a611d0caSIgor M. Liplianin #define DM1105_DTALENTH				0x04
75a611d0caSIgor M. Liplianin 
76a611d0caSIgor M. Liplianin /* GPIO Interface */
77a611d0caSIgor M. Liplianin #define DM1105_GPIOVAL				0x08
78a611d0caSIgor M. Liplianin #define DM1105_GPIOCTR				0x0c
79a611d0caSIgor M. Liplianin 
80a611d0caSIgor M. Liplianin /* PID serial number */
81a611d0caSIgor M. Liplianin #define DM1105_PIDN				0x10
82a611d0caSIgor M. Liplianin 
83a611d0caSIgor M. Liplianin /* Odd-even secret key select */
84a611d0caSIgor M. Liplianin #define DM1105_CWSEL				0x14
85a611d0caSIgor M. Liplianin 
86a611d0caSIgor M. Liplianin /* Host Command Interface */
87a611d0caSIgor M. Liplianin #define DM1105_HOST_CTR				0x18
88a611d0caSIgor M. Liplianin #define DM1105_HOST_AD				0x1c
89a611d0caSIgor M. Liplianin 
90a611d0caSIgor M. Liplianin /* PCI Interface */
91a611d0caSIgor M. Liplianin #define DM1105_CR				0x30
92a611d0caSIgor M. Liplianin #define DM1105_RST				0x34
93a611d0caSIgor M. Liplianin #define DM1105_STADR				0x38
94a611d0caSIgor M. Liplianin #define DM1105_RLEN				0x3c
95a611d0caSIgor M. Liplianin #define DM1105_WRP				0x40
96a611d0caSIgor M. Liplianin #define DM1105_INTCNT				0x44
97a611d0caSIgor M. Liplianin #define DM1105_INTMAK				0x48
98a611d0caSIgor M. Liplianin #define DM1105_INTSTS				0x4c
99a611d0caSIgor M. Liplianin 
100a611d0caSIgor M. Liplianin /* CW Value */
101a611d0caSIgor M. Liplianin #define DM1105_ODD				0x50
102a611d0caSIgor M. Liplianin #define DM1105_EVEN				0x58
103a611d0caSIgor M. Liplianin 
104a611d0caSIgor M. Liplianin /* PID Value */
105a611d0caSIgor M. Liplianin #define DM1105_PID				0x60
106a611d0caSIgor M. Liplianin 
107a611d0caSIgor M. Liplianin /* IR Control */
108a611d0caSIgor M. Liplianin #define DM1105_IRCTR				0x64
109a611d0caSIgor M. Liplianin #define DM1105_IRMODE				0x68
110a611d0caSIgor M. Liplianin #define DM1105_SYSTEMCODE			0x6c
111a611d0caSIgor M. Liplianin #define DM1105_IRCODE				0x70
112a611d0caSIgor M. Liplianin 
113a611d0caSIgor M. Liplianin /* Unknown Values */
114a611d0caSIgor M. Liplianin #define DM1105_ENCRYPT				0x74
115a611d0caSIgor M. Liplianin #define DM1105_VER				0x7c
116a611d0caSIgor M. Liplianin 
117a611d0caSIgor M. Liplianin /* I2C Interface */
118a611d0caSIgor M. Liplianin #define DM1105_I2CCTR				0x80
119a611d0caSIgor M. Liplianin #define DM1105_I2CSTS				0x81
120a611d0caSIgor M. Liplianin #define DM1105_I2CDAT				0x82
121a611d0caSIgor M. Liplianin #define DM1105_I2C_RA				0x83
122a611d0caSIgor M. Liplianin /* ----------------------------------------------- */
123a611d0caSIgor M. Liplianin /* Interrupt Mask Bits */
124a611d0caSIgor M. Liplianin 
125a611d0caSIgor M. Liplianin #define INTMAK_TSIRQM				0x01
126a611d0caSIgor M. Liplianin #define INTMAK_HIRQM				0x04
127a611d0caSIgor M. Liplianin #define INTMAK_IRM				0x08
128a611d0caSIgor M. Liplianin #define INTMAK_ALLMASK				(INTMAK_TSIRQM | \
129a611d0caSIgor M. Liplianin 						INTMAK_HIRQM | \
130a611d0caSIgor M. Liplianin 						INTMAK_IRM)
131a611d0caSIgor M. Liplianin #define INTMAK_NONEMASK				0x00
132a611d0caSIgor M. Liplianin 
133a611d0caSIgor M. Liplianin /* Interrupt Status Bits */
134a611d0caSIgor M. Liplianin #define INTSTS_TSIRQ				0x01
135a611d0caSIgor M. Liplianin #define INTSTS_HIRQ				0x04
136a611d0caSIgor M. Liplianin #define INTSTS_IR				0x08
137a611d0caSIgor M. Liplianin 
138a611d0caSIgor M. Liplianin /* IR Control Bits */
139a611d0caSIgor M. Liplianin #define DM1105_IR_EN				0x01
140a611d0caSIgor M. Liplianin #define DM1105_SYS_CHK				0x02
141a611d0caSIgor M. Liplianin #define DM1105_REP_FLG				0x08
142a611d0caSIgor M. Liplianin 
143a611d0caSIgor M. Liplianin /* EEPROM addr */
144a611d0caSIgor M. Liplianin #define IIC_24C01_addr				0xa0
145a611d0caSIgor M. Liplianin /* Max board count */
146a611d0caSIgor M. Liplianin #define DM1105_MAX				0x04
147a611d0caSIgor M. Liplianin 
148a611d0caSIgor M. Liplianin #define DRIVER_NAME				"dm1105"
1490017505dSIgor M. Liplianin #define DM1105_I2C_GPIO_NAME			"dm1105-gpio"
150a611d0caSIgor M. Liplianin 
151a611d0caSIgor M. Liplianin #define DM1105_DMA_PACKETS			47
152a611d0caSIgor M. Liplianin #define DM1105_DMA_PACKET_LENGTH		(128*4)
153a611d0caSIgor M. Liplianin #define DM1105_DMA_BYTES			(128 * 4 * DM1105_DMA_PACKETS)
154a611d0caSIgor M. Liplianin 
1550017505dSIgor M. Liplianin /*  */
1560017505dSIgor M. Liplianin #define GPIO08					(1 << 8)
1570017505dSIgor M. Liplianin #define GPIO13					(1 << 13)
1580017505dSIgor M. Liplianin #define GPIO14					(1 << 14)
1590017505dSIgor M. Liplianin #define GPIO15					(1 << 15)
1600017505dSIgor M. Liplianin #define GPIO16					(1 << 16)
1610017505dSIgor M. Liplianin #define GPIO17					(1 << 17)
1620017505dSIgor M. Liplianin #define GPIO_ALL				0x03ffff
1630017505dSIgor M. Liplianin 
164a611d0caSIgor M. Liplianin /* GPIO's for LNB power control */
1650017505dSIgor M. Liplianin #define DM1105_LNB_MASK				(GPIO_ALL & ~(GPIO14 | GPIO13))
1660017505dSIgor M. Liplianin #define DM1105_LNB_OFF				GPIO17
1670017505dSIgor M. Liplianin #define DM1105_LNB_13V				(GPIO16 | GPIO08)
1680017505dSIgor M. Liplianin #define DM1105_LNB_18V				GPIO08
169a611d0caSIgor M. Liplianin 
170519a4bdcSIgor M. Liplianin /* GPIO's for LNB power control for Axess DM05 */
1710017505dSIgor M. Liplianin #define DM05_LNB_MASK				(GPIO_ALL & ~(GPIO14 | GPIO13))
1720017505dSIgor M. Liplianin #define DM05_LNB_OFF				GPIO17/* actually 13v */
1730017505dSIgor M. Liplianin #define DM05_LNB_13V				GPIO17
1740017505dSIgor M. Liplianin #define DM05_LNB_18V				(GPIO17 | GPIO16)
1750017505dSIgor M. Liplianin 
1760017505dSIgor M. Liplianin /* GPIO's for LNB power control for unbranded with I2C on GPIO */
1770017505dSIgor M. Liplianin #define UNBR_LNB_MASK				(GPIO17 | GPIO16)
1780017505dSIgor M. Liplianin #define UNBR_LNB_OFF				0
1790017505dSIgor M. Liplianin #define UNBR_LNB_13V				GPIO17
1800017505dSIgor M. Liplianin #define UNBR_LNB_18V				(GPIO17 | GPIO16)
181519a4bdcSIgor M. Liplianin 
182d8300df9SIgor M. Liplianin static unsigned int card[]  = {[0 ... 3] = UNSET };
183d8300df9SIgor M. Liplianin module_param_array(card,  int, NULL, 0444);
184d8300df9SIgor M. Liplianin MODULE_PARM_DESC(card, "card type");
185d8300df9SIgor M. Liplianin 
186a611d0caSIgor M. Liplianin static int ir_debug;
187a611d0caSIgor M. Liplianin module_param(ir_debug, int, 0644);
188a611d0caSIgor M. Liplianin MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
189a611d0caSIgor M. Liplianin 
190d8300df9SIgor M. Liplianin static unsigned int dm1105_devcount;
191d8300df9SIgor M. Liplianin 
192a611d0caSIgor M. Liplianin DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
193a611d0caSIgor M. Liplianin 
194d8300df9SIgor M. Liplianin struct dm1105_board {
195d8300df9SIgor M. Liplianin 	char	*name;
1960017505dSIgor M. Liplianin 	struct	{
1970017505dSIgor M. Liplianin 		u32	mask, off, v13, v18;
1980017505dSIgor M. Liplianin 	} lnb;
1990017505dSIgor M. Liplianin 	u32	gpio_scl, gpio_sda;
200d8300df9SIgor M. Liplianin };
201d8300df9SIgor M. Liplianin 
202d8300df9SIgor M. Liplianin struct dm1105_subid {
203d8300df9SIgor M. Liplianin 	u16     subvendor;
204d8300df9SIgor M. Liplianin 	u16     subdevice;
205d8300df9SIgor M. Liplianin 	u32     card;
206d8300df9SIgor M. Liplianin };
207d8300df9SIgor M. Liplianin 
208d8300df9SIgor M. Liplianin static const struct dm1105_board dm1105_boards[] = {
209d8300df9SIgor M. Liplianin 	[DM1105_BOARD_UNKNOWN] = {
210d8300df9SIgor M. Liplianin 		.name		= "UNKNOWN/GENERIC",
2110017505dSIgor M. Liplianin 		.lnb = {
2120017505dSIgor M. Liplianin 			.mask = DM1105_LNB_MASK,
2130017505dSIgor M. Liplianin 			.off = DM1105_LNB_OFF,
2140017505dSIgor M. Liplianin 			.v13 = DM1105_LNB_13V,
2150017505dSIgor M. Liplianin 			.v18 = DM1105_LNB_18V,
2160017505dSIgor M. Liplianin 		},
217d8300df9SIgor M. Liplianin 	},
218d8300df9SIgor M. Liplianin 	[DM1105_BOARD_DVBWORLD_2002] = {
219d8300df9SIgor M. Liplianin 		.name		= "DVBWorld PCI 2002",
2200017505dSIgor M. Liplianin 		.lnb = {
2210017505dSIgor M. Liplianin 			.mask = DM1105_LNB_MASK,
2220017505dSIgor M. Liplianin 			.off = DM1105_LNB_OFF,
2230017505dSIgor M. Liplianin 			.v13 = DM1105_LNB_13V,
2240017505dSIgor M. Liplianin 			.v18 = DM1105_LNB_18V,
2250017505dSIgor M. Liplianin 		},
226d8300df9SIgor M. Liplianin 	},
227d8300df9SIgor M. Liplianin 	[DM1105_BOARD_DVBWORLD_2004] = {
228d8300df9SIgor M. Liplianin 		.name		= "DVBWorld PCI 2004",
2290017505dSIgor M. Liplianin 		.lnb = {
2300017505dSIgor M. Liplianin 			.mask = DM1105_LNB_MASK,
2310017505dSIgor M. Liplianin 			.off = DM1105_LNB_OFF,
2320017505dSIgor M. Liplianin 			.v13 = DM1105_LNB_13V,
2330017505dSIgor M. Liplianin 			.v18 = DM1105_LNB_18V,
2340017505dSIgor M. Liplianin 		},
235d8300df9SIgor M. Liplianin 	},
236d8300df9SIgor M. Liplianin 	[DM1105_BOARD_AXESS_DM05] = {
237d8300df9SIgor M. Liplianin 		.name		= "Axess/EasyTv DM05",
2380017505dSIgor M. Liplianin 		.lnb = {
2390017505dSIgor M. Liplianin 			.mask = DM05_LNB_MASK,
2400017505dSIgor M. Liplianin 			.off = DM05_LNB_OFF,
2410017505dSIgor M. Liplianin 			.v13 = DM05_LNB_13V,
2420017505dSIgor M. Liplianin 			.v18 = DM05_LNB_18V,
2430017505dSIgor M. Liplianin 		},
2440017505dSIgor M. Liplianin 	},
2450017505dSIgor M. Liplianin 	[DM1105_BOARD_UNBRANDED_I2C_ON_GPIO] = {
2460017505dSIgor M. Liplianin 		.name		= "Unbranded DM1105 with i2c on GPIOs",
2470017505dSIgor M. Liplianin 		.lnb = {
2480017505dSIgor M. Liplianin 			.mask = UNBR_LNB_MASK,
2490017505dSIgor M. Liplianin 			.off = UNBR_LNB_OFF,
2500017505dSIgor M. Liplianin 			.v13 = UNBR_LNB_13V,
2510017505dSIgor M. Liplianin 			.v18 = UNBR_LNB_18V,
2520017505dSIgor M. Liplianin 		},
2530017505dSIgor M. Liplianin 		.gpio_scl	= GPIO14,
2540017505dSIgor M. Liplianin 		.gpio_sda	= GPIO13,
255d8300df9SIgor M. Liplianin 	},
256d8300df9SIgor M. Liplianin };
257d8300df9SIgor M. Liplianin 
258d8300df9SIgor M. Liplianin static const struct dm1105_subid dm1105_subids[] = {
259d8300df9SIgor M. Liplianin 	{
260d8300df9SIgor M. Liplianin 		.subvendor = 0x0000,
261d8300df9SIgor M. Liplianin 		.subdevice = 0x2002,
262d8300df9SIgor M. Liplianin 		.card      = DM1105_BOARD_DVBWORLD_2002,
263d8300df9SIgor M. Liplianin 	}, {
264d8300df9SIgor M. Liplianin 		.subvendor = 0x0001,
265d8300df9SIgor M. Liplianin 		.subdevice = 0x2002,
266d8300df9SIgor M. Liplianin 		.card      = DM1105_BOARD_DVBWORLD_2002,
267d8300df9SIgor M. Liplianin 	}, {
268d8300df9SIgor M. Liplianin 		.subvendor = 0x0000,
269d8300df9SIgor M. Liplianin 		.subdevice = 0x2004,
270d8300df9SIgor M. Liplianin 		.card      = DM1105_BOARD_DVBWORLD_2004,
271d8300df9SIgor M. Liplianin 	}, {
272d8300df9SIgor M. Liplianin 		.subvendor = 0x0001,
273d8300df9SIgor M. Liplianin 		.subdevice = 0x2004,
274d8300df9SIgor M. Liplianin 		.card      = DM1105_BOARD_DVBWORLD_2004,
275d8300df9SIgor M. Liplianin 	}, {
276d8300df9SIgor M. Liplianin 		.subvendor = 0x195d,
277d8300df9SIgor M. Liplianin 		.subdevice = 0x1105,
278d8300df9SIgor M. Liplianin 		.card      = DM1105_BOARD_AXESS_DM05,
279d8300df9SIgor M. Liplianin 	},
280d8300df9SIgor M. Liplianin };
281d8300df9SIgor M. Liplianin 
282d8300df9SIgor M. Liplianin static void dm1105_card_list(struct pci_dev *pci)
283d8300df9SIgor M. Liplianin {
284d8300df9SIgor M. Liplianin 	int i;
285d8300df9SIgor M. Liplianin 
286d8300df9SIgor M. Liplianin 	if (0 == pci->subsystem_vendor &&
287d8300df9SIgor M. Liplianin 			0 == pci->subsystem_device) {
288d8300df9SIgor M. Liplianin 		printk(KERN_ERR
289d8300df9SIgor M. Liplianin 			"dm1105: Your board has no valid PCI Subsystem ID\n"
290d8300df9SIgor M. Liplianin 			"dm1105: and thus can't be autodetected\n"
291d8300df9SIgor M. Liplianin 			"dm1105: Please pass card=<n> insmod option to\n"
292d8300df9SIgor M. Liplianin 			"dm1105: workaround that.  Redirect complaints to\n"
293d8300df9SIgor M. Liplianin 			"dm1105: the vendor of the TV card.  Best regards,\n"
294d8300df9SIgor M. Liplianin 			"dm1105: -- tux\n");
295d8300df9SIgor M. Liplianin 	} else {
296d8300df9SIgor M. Liplianin 		printk(KERN_ERR
297d8300df9SIgor M. Liplianin 			"dm1105: Your board isn't known (yet) to the driver.\n"
298d8300df9SIgor M. Liplianin 			"dm1105: You can try to pick one of the existing\n"
299d8300df9SIgor M. Liplianin 			"dm1105: card configs via card=<n> insmod option.\n"
300d8300df9SIgor M. Liplianin 			"dm1105: Updating to the latest version might help\n"
301d8300df9SIgor M. Liplianin 			"dm1105: as well.\n");
302d8300df9SIgor M. Liplianin 	}
3030e8aebb5SMauro Carvalho Chehab 	printk(KERN_ERR "Here is a list of valid choices for the card=<n> insmod option:\n");
304d8300df9SIgor M. Liplianin 	for (i = 0; i < ARRAY_SIZE(dm1105_boards); i++)
305d8300df9SIgor M. Liplianin 		printk(KERN_ERR "dm1105:    card=%d -> %s\n",
306d8300df9SIgor M. Liplianin 				i, dm1105_boards[i].name);
307d8300df9SIgor M. Liplianin }
308d8300df9SIgor M. Liplianin 
309a611d0caSIgor M. Liplianin /* infrared remote control */
310a611d0caSIgor M. Liplianin struct infrared {
311d8b4b582SDavid Härdeman 	struct rc_dev		*dev;
312a611d0caSIgor M. Liplianin 	char			input_phys[32];
313b72857ddSIgor M. Liplianin 	struct work_struct	work;
314a611d0caSIgor M. Liplianin 	u32			ir_command;
315a611d0caSIgor M. Liplianin };
316a611d0caSIgor M. Liplianin 
31734d2f9bfSIgor M. Liplianin struct dm1105_dev {
318a611d0caSIgor M. Liplianin 	/* pci */
319a611d0caSIgor M. Liplianin 	struct pci_dev *pdev;
320a611d0caSIgor M. Liplianin 	u8 __iomem *io_mem;
321a611d0caSIgor M. Liplianin 
322a611d0caSIgor M. Liplianin 	/* ir */
323a611d0caSIgor M. Liplianin 	struct infrared ir;
324a611d0caSIgor M. Liplianin 
325a611d0caSIgor M. Liplianin 	/* dvb */
326a611d0caSIgor M. Liplianin 	struct dmx_frontend hw_frontend;
327a611d0caSIgor M. Liplianin 	struct dmx_frontend mem_frontend;
328a611d0caSIgor M. Liplianin 	struct dmxdev dmxdev;
329a611d0caSIgor M. Liplianin 	struct dvb_adapter dvb_adapter;
330a611d0caSIgor M. Liplianin 	struct dvb_demux demux;
331a611d0caSIgor M. Liplianin 	struct dvb_frontend *fe;
332a611d0caSIgor M. Liplianin 	struct dvb_net dvbnet;
333a611d0caSIgor M. Liplianin 	unsigned int full_ts_users;
334d8300df9SIgor M. Liplianin 	unsigned int boardnr;
335d8300df9SIgor M. Liplianin 	int nr;
336a611d0caSIgor M. Liplianin 
337a611d0caSIgor M. Liplianin 	/* i2c */
338a611d0caSIgor M. Liplianin 	struct i2c_adapter i2c_adap;
3390017505dSIgor M. Liplianin 	struct i2c_adapter i2c_bb_adap;
3400017505dSIgor M. Liplianin 	struct i2c_algo_bit_data i2c_bit;
341a611d0caSIgor M. Liplianin 
342d1498ffcSIgor M. Liplianin 	/* irq */
343d1498ffcSIgor M. Liplianin 	struct work_struct work;
344519a4bdcSIgor M. Liplianin 	struct workqueue_struct *wq;
345519a4bdcSIgor M. Liplianin 	char wqn[16];
346d1498ffcSIgor M. Liplianin 
347a611d0caSIgor M. Liplianin 	/* dma */
348a611d0caSIgor M. Liplianin 	dma_addr_t dma_addr;
349a611d0caSIgor M. Liplianin 	unsigned char *ts_buf;
350a611d0caSIgor M. Liplianin 	u32 wrp;
351d1498ffcSIgor M. Liplianin 	u32 nextwrp;
352a611d0caSIgor M. Liplianin 	u32 buffer_size;
353a611d0caSIgor M. Liplianin 	unsigned int	PacketErrorCount;
354a611d0caSIgor M. Liplianin 	unsigned int dmarst;
355a611d0caSIgor M. Liplianin 	spinlock_t lock;
356a611d0caSIgor M. Liplianin };
357a611d0caSIgor M. Liplianin 
35834d2f9bfSIgor M. Liplianin #define dm_io_mem(reg)	((unsigned long)(&dev->io_mem[reg]))
359a611d0caSIgor M. Liplianin 
3605eb3291fSIgor M. Liplianin #define dm_readb(reg)		inb(dm_io_mem(reg))
3615eb3291fSIgor M. Liplianin #define dm_writeb(reg, value)	outb((value), (dm_io_mem(reg)))
3625eb3291fSIgor M. Liplianin 
3635eb3291fSIgor M. Liplianin #define dm_readw(reg)		inw(dm_io_mem(reg))
3645eb3291fSIgor M. Liplianin #define dm_writew(reg, value)	outw((value), (dm_io_mem(reg)))
3655eb3291fSIgor M. Liplianin 
3665eb3291fSIgor M. Liplianin #define dm_readl(reg)		inl(dm_io_mem(reg))
3675eb3291fSIgor M. Liplianin #define dm_writel(reg, value)	outl((value), (dm_io_mem(reg)))
3685eb3291fSIgor M. Liplianin 
3695eb3291fSIgor M. Liplianin #define dm_andorl(reg, mask, value) \
3705eb3291fSIgor M. Liplianin 	outl((inl(dm_io_mem(reg)) & ~(mask)) |\
3715eb3291fSIgor M. Liplianin 		((value) & (mask)), (dm_io_mem(reg)))
3725eb3291fSIgor M. Liplianin 
3735eb3291fSIgor M. Liplianin #define dm_setl(reg, bit)	dm_andorl((reg), (bit), (bit))
3745eb3291fSIgor M. Liplianin #define dm_clearl(reg, bit)	dm_andorl((reg), (bit), 0)
3755eb3291fSIgor M. Liplianin 
3760017505dSIgor M. Liplianin /* The chip has 18 GPIOs. In HOST mode GPIO's used as 15 bit address lines,
3770017505dSIgor M. Liplianin  so we can use only 3 GPIO's from GPIO15 to GPIO17.
3780017505dSIgor M. Liplianin  Here I don't check whether HOST is enebled as it is not implemented yet.
3790017505dSIgor M. Liplianin  */
3800017505dSIgor M. Liplianin static void dm1105_gpio_set(struct dm1105_dev *dev, u32 mask)
3810017505dSIgor M. Liplianin {
3820017505dSIgor M. Liplianin 	if (mask & 0xfffc0000)
3830017505dSIgor M. Liplianin 		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
3840017505dSIgor M. Liplianin 
3850017505dSIgor M. Liplianin 	if (mask & 0x0003ffff)
3860017505dSIgor M. Liplianin 		dm_setl(DM1105_GPIOVAL, mask & 0x0003ffff);
3870017505dSIgor M. Liplianin 
3880017505dSIgor M. Liplianin }
3890017505dSIgor M. Liplianin 
3900017505dSIgor M. Liplianin static void dm1105_gpio_clear(struct dm1105_dev *dev, u32 mask)
3910017505dSIgor M. Liplianin {
3920017505dSIgor M. Liplianin 	if (mask & 0xfffc0000)
3930017505dSIgor M. Liplianin 		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
3940017505dSIgor M. Liplianin 
3950017505dSIgor M. Liplianin 	if (mask & 0x0003ffff)
3960017505dSIgor M. Liplianin 		dm_clearl(DM1105_GPIOVAL, mask & 0x0003ffff);
3970017505dSIgor M. Liplianin 
3980017505dSIgor M. Liplianin }
3990017505dSIgor M. Liplianin 
4000017505dSIgor M. Liplianin static void dm1105_gpio_andor(struct dm1105_dev *dev, u32 mask, u32 val)
4010017505dSIgor M. Liplianin {
4020017505dSIgor M. Liplianin 	if (mask & 0xfffc0000)
4030017505dSIgor M. Liplianin 		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
4040017505dSIgor M. Liplianin 
4050017505dSIgor M. Liplianin 	if (mask & 0x0003ffff)
4060017505dSIgor M. Liplianin 		dm_andorl(DM1105_GPIOVAL, mask & 0x0003ffff, val);
4070017505dSIgor M. Liplianin 
4080017505dSIgor M. Liplianin }
4090017505dSIgor M. Liplianin 
4100017505dSIgor M. Liplianin static u32 dm1105_gpio_get(struct dm1105_dev *dev, u32 mask)
4110017505dSIgor M. Liplianin {
4120017505dSIgor M. Liplianin 	if (mask & 0xfffc0000)
4130017505dSIgor M. Liplianin 		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
4140017505dSIgor M. Liplianin 
4150017505dSIgor M. Liplianin 	if (mask & 0x0003ffff)
4160017505dSIgor M. Liplianin 		return dm_readl(DM1105_GPIOVAL) & mask & 0x0003ffff;
4170017505dSIgor M. Liplianin 
4180017505dSIgor M. Liplianin 	return 0;
4190017505dSIgor M. Liplianin }
4200017505dSIgor M. Liplianin 
4210017505dSIgor M. Liplianin static void dm1105_gpio_enable(struct dm1105_dev *dev, u32 mask, int asoutput)
4220017505dSIgor M. Liplianin {
4230017505dSIgor M. Liplianin 	if (mask & 0xfffc0000)
4240017505dSIgor M. Liplianin 		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
4250017505dSIgor M. Liplianin 
4260017505dSIgor M. Liplianin 	if ((mask & 0x0003ffff) && asoutput)
4270017505dSIgor M. Liplianin 		dm_clearl(DM1105_GPIOCTR, mask & 0x0003ffff);
4280017505dSIgor M. Liplianin 	else if ((mask & 0x0003ffff) && !asoutput)
4290017505dSIgor M. Liplianin 		dm_setl(DM1105_GPIOCTR, mask & 0x0003ffff);
4300017505dSIgor M. Liplianin 
4310017505dSIgor M. Liplianin }
4320017505dSIgor M. Liplianin 
4330017505dSIgor M. Liplianin static void dm1105_setline(struct dm1105_dev *dev, u32 line, int state)
4340017505dSIgor M. Liplianin {
4350017505dSIgor M. Liplianin 	if (state)
4360017505dSIgor M. Liplianin 		dm1105_gpio_enable(dev, line, 0);
4370017505dSIgor M. Liplianin 	else {
4380017505dSIgor M. Liplianin 		dm1105_gpio_enable(dev, line, 1);
4390017505dSIgor M. Liplianin 		dm1105_gpio_clear(dev, line);
4400017505dSIgor M. Liplianin 	}
4410017505dSIgor M. Liplianin }
4420017505dSIgor M. Liplianin 
4430017505dSIgor M. Liplianin static void dm1105_setsda(void *data, int state)
4440017505dSIgor M. Liplianin {
4450017505dSIgor M. Liplianin 	struct dm1105_dev *dev = data;
4460017505dSIgor M. Liplianin 
4470017505dSIgor M. Liplianin 	dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_sda, state);
4480017505dSIgor M. Liplianin }
4490017505dSIgor M. Liplianin 
4500017505dSIgor M. Liplianin static void dm1105_setscl(void *data, int state)
4510017505dSIgor M. Liplianin {
4520017505dSIgor M. Liplianin 	struct dm1105_dev *dev = data;
4530017505dSIgor M. Liplianin 
4540017505dSIgor M. Liplianin 	dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_scl, state);
4550017505dSIgor M. Liplianin }
4560017505dSIgor M. Liplianin 
4570017505dSIgor M. Liplianin static int dm1105_getsda(void *data)
4580017505dSIgor M. Liplianin {
4590017505dSIgor M. Liplianin 	struct dm1105_dev *dev = data;
4600017505dSIgor M. Liplianin 
4610017505dSIgor M. Liplianin 	return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_sda)
4620017505dSIgor M. Liplianin 									? 1 : 0;
4630017505dSIgor M. Liplianin }
4640017505dSIgor M. Liplianin 
4650017505dSIgor M. Liplianin static int dm1105_getscl(void *data)
4660017505dSIgor M. Liplianin {
4670017505dSIgor M. Liplianin 	struct dm1105_dev *dev = data;
4680017505dSIgor M. Liplianin 
4690017505dSIgor M. Liplianin 	return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_scl)
4700017505dSIgor M. Liplianin 									? 1 : 0;
4710017505dSIgor M. Liplianin }
4720017505dSIgor M. Liplianin 
473a611d0caSIgor M. Liplianin static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
474a611d0caSIgor M. Liplianin 			    struct i2c_msg *msgs, int num)
475a611d0caSIgor M. Liplianin {
47634d2f9bfSIgor M. Liplianin 	struct dm1105_dev *dev ;
477a611d0caSIgor M. Liplianin 
478a611d0caSIgor M. Liplianin 	int addr, rc, i, j, k, len, byte, data;
479a611d0caSIgor M. Liplianin 	u8 status;
480a611d0caSIgor M. Liplianin 
48134d2f9bfSIgor M. Liplianin 	dev = i2c_adap->algo_data;
482a611d0caSIgor M. Liplianin 	for (i = 0; i < num; i++) {
4835eb3291fSIgor M. Liplianin 		dm_writeb(DM1105_I2CCTR, 0x00);
484a611d0caSIgor M. Liplianin 		if (msgs[i].flags & I2C_M_RD) {
485a611d0caSIgor M. Liplianin 			/* read bytes */
486a611d0caSIgor M. Liplianin 			addr  = msgs[i].addr << 1;
487a611d0caSIgor M. Liplianin 			addr |= 1;
4885eb3291fSIgor M. Liplianin 			dm_writeb(DM1105_I2CDAT, addr);
489a611d0caSIgor M. Liplianin 			for (byte = 0; byte < msgs[i].len; byte++)
4905eb3291fSIgor M. Liplianin 				dm_writeb(DM1105_I2CDAT + byte + 1, 0);
491a611d0caSIgor M. Liplianin 
4925eb3291fSIgor M. Liplianin 			dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len);
493a611d0caSIgor M. Liplianin 			for (j = 0; j < 55; j++) {
494a611d0caSIgor M. Liplianin 				mdelay(10);
4955eb3291fSIgor M. Liplianin 				status = dm_readb(DM1105_I2CSTS);
496a611d0caSIgor M. Liplianin 				if ((status & 0xc0) == 0x40)
497a611d0caSIgor M. Liplianin 					break;
498a611d0caSIgor M. Liplianin 			}
499a611d0caSIgor M. Liplianin 			if (j >= 55)
500a611d0caSIgor M. Liplianin 				return -1;
501a611d0caSIgor M. Liplianin 
502a611d0caSIgor M. Liplianin 			for (byte = 0; byte < msgs[i].len; byte++) {
5035eb3291fSIgor M. Liplianin 				rc = dm_readb(DM1105_I2CDAT + byte + 1);
504a611d0caSIgor M. Liplianin 				if (rc < 0)
505a611d0caSIgor M. Liplianin 					goto err;
506a611d0caSIgor M. Liplianin 				msgs[i].buf[byte] = rc;
507a611d0caSIgor M. Liplianin 			}
508ed7c847aSIgor M. Liplianin 		} else if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) {
50916790554SMauro Carvalho Chehab 			/* prepared for cx24116 firmware */
510a611d0caSIgor M. Liplianin 			/* Write in small blocks */
511a611d0caSIgor M. Liplianin 			len = msgs[i].len - 1;
512a611d0caSIgor M. Liplianin 			k = 1;
513a611d0caSIgor M. Liplianin 			do {
5145eb3291fSIgor M. Liplianin 				dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1);
5155eb3291fSIgor M. Liplianin 				dm_writeb(DM1105_I2CDAT + 1, 0xf7);
516a611d0caSIgor M. Liplianin 				for (byte = 0; byte < (len > 48 ? 48 : len); byte++) {
517a611d0caSIgor M. Liplianin 					data = msgs[i].buf[k + byte];
5185eb3291fSIgor M. Liplianin 					dm_writeb(DM1105_I2CDAT + byte + 2, data);
519a611d0caSIgor M. Liplianin 				}
5205eb3291fSIgor M. Liplianin 				dm_writeb(DM1105_I2CCTR, 0x82 + (len > 48 ? 48 : len));
521a611d0caSIgor M. Liplianin 				for (j = 0; j < 25; j++) {
522a611d0caSIgor M. Liplianin 					mdelay(10);
5235eb3291fSIgor M. Liplianin 					status = dm_readb(DM1105_I2CSTS);
524a611d0caSIgor M. Liplianin 					if ((status & 0xc0) == 0x40)
525a611d0caSIgor M. Liplianin 						break;
526a611d0caSIgor M. Liplianin 				}
527a611d0caSIgor M. Liplianin 
528a611d0caSIgor M. Liplianin 				if (j >= 25)
529a611d0caSIgor M. Liplianin 					return -1;
530a611d0caSIgor M. Liplianin 
531a611d0caSIgor M. Liplianin 				k += 48;
532a611d0caSIgor M. Liplianin 				len -= 48;
533a611d0caSIgor M. Liplianin 			} while (len > 0);
534a611d0caSIgor M. Liplianin 		} else {
535a611d0caSIgor M. Liplianin 			/* write bytes */
5365eb3291fSIgor M. Liplianin 			dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1);
537a611d0caSIgor M. Liplianin 			for (byte = 0; byte < msgs[i].len; byte++) {
538a611d0caSIgor M. Liplianin 				data = msgs[i].buf[byte];
5395eb3291fSIgor M. Liplianin 				dm_writeb(DM1105_I2CDAT + byte + 1, data);
540a611d0caSIgor M. Liplianin 			}
5415eb3291fSIgor M. Liplianin 			dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len);
542a611d0caSIgor M. Liplianin 			for (j = 0; j < 25; j++) {
543a611d0caSIgor M. Liplianin 				mdelay(10);
5445eb3291fSIgor M. Liplianin 				status = dm_readb(DM1105_I2CSTS);
545a611d0caSIgor M. Liplianin 				if ((status & 0xc0) == 0x40)
546a611d0caSIgor M. Liplianin 					break;
547a611d0caSIgor M. Liplianin 			}
548a611d0caSIgor M. Liplianin 
549a611d0caSIgor M. Liplianin 			if (j >= 25)
550a611d0caSIgor M. Liplianin 				return -1;
551a611d0caSIgor M. Liplianin 		}
552a611d0caSIgor M. Liplianin 	}
553a611d0caSIgor M. Liplianin 	return num;
554a611d0caSIgor M. Liplianin  err:
555a611d0caSIgor M. Liplianin 	return rc;
556a611d0caSIgor M. Liplianin }
557a611d0caSIgor M. Liplianin 
558a611d0caSIgor M. Liplianin static u32 functionality(struct i2c_adapter *adap)
559a611d0caSIgor M. Liplianin {
560a611d0caSIgor M. Liplianin 	return I2C_FUNC_I2C;
561a611d0caSIgor M. Liplianin }
562a611d0caSIgor M. Liplianin 
5633c13978eSGustavo A. R. Silva static const struct i2c_algorithm dm1105_algo = {
564a611d0caSIgor M. Liplianin 	.master_xfer   = dm1105_i2c_xfer,
565a611d0caSIgor M. Liplianin 	.functionality = functionality,
566a611d0caSIgor M. Liplianin };
567a611d0caSIgor M. Liplianin 
56834d2f9bfSIgor M. Liplianin static inline struct dm1105_dev *feed_to_dm1105_dev(struct dvb_demux_feed *feed)
569a611d0caSIgor M. Liplianin {
57034d2f9bfSIgor M. Liplianin 	return container_of(feed->demux, struct dm1105_dev, demux);
571a611d0caSIgor M. Liplianin }
572a611d0caSIgor M. Liplianin 
57334d2f9bfSIgor M. Liplianin static inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe)
574a611d0caSIgor M. Liplianin {
57534d2f9bfSIgor M. Liplianin 	return container_of(fe->dvb, struct dm1105_dev, dvb_adapter);
576a611d0caSIgor M. Liplianin }
577a611d0caSIgor M. Liplianin 
5780df289a2SMauro Carvalho Chehab static int dm1105_set_voltage(struct dvb_frontend *fe,
5790df289a2SMauro Carvalho Chehab 			      enum fe_sec_voltage voltage)
580a611d0caSIgor M. Liplianin {
58134d2f9bfSIgor M. Liplianin 	struct dm1105_dev *dev = frontend_to_dm1105_dev(fe);
582a611d0caSIgor M. Liplianin 
5830017505dSIgor M. Liplianin 	dm1105_gpio_enable(dev, dm1105_boards[dev->boardnr].lnb.mask, 1);
584519a4bdcSIgor M. Liplianin 	if (voltage == SEC_VOLTAGE_18)
5850017505dSIgor M. Liplianin 		dm1105_gpio_andor(dev,
5860017505dSIgor M. Liplianin 				dm1105_boards[dev->boardnr].lnb.mask,
5870017505dSIgor M. Liplianin 				dm1105_boards[dev->boardnr].lnb.v18);
588d8300df9SIgor M. Liplianin 	else if (voltage == SEC_VOLTAGE_13)
5890017505dSIgor M. Liplianin 		dm1105_gpio_andor(dev,
5900017505dSIgor M. Liplianin 				dm1105_boards[dev->boardnr].lnb.mask,
5910017505dSIgor M. Liplianin 				dm1105_boards[dev->boardnr].lnb.v13);
592d8300df9SIgor M. Liplianin 	else
5930017505dSIgor M. Liplianin 		dm1105_gpio_andor(dev,
5940017505dSIgor M. Liplianin 				dm1105_boards[dev->boardnr].lnb.mask,
5950017505dSIgor M. Liplianin 				dm1105_boards[dev->boardnr].lnb.off);
596519a4bdcSIgor M. Liplianin 
597a611d0caSIgor M. Liplianin 	return 0;
598a611d0caSIgor M. Liplianin }
599a611d0caSIgor M. Liplianin 
60034d2f9bfSIgor M. Liplianin static void dm1105_set_dma_addr(struct dm1105_dev *dev)
601a611d0caSIgor M. Liplianin {
602888bd5dcSHans Verkuil 	dm_writel(DM1105_STADR, (__force u32)cpu_to_le32(dev->dma_addr));
603a611d0caSIgor M. Liplianin }
604a611d0caSIgor M. Liplianin 
6054c62e976SGreg Kroah-Hartman static int dm1105_dma_map(struct dm1105_dev *dev)
606a611d0caSIgor M. Liplianin {
607*acc4c91eSChristophe JAILLET 	dev->ts_buf = dma_alloc_coherent(&dev->pdev->dev,
608*acc4c91eSChristophe JAILLET 					 6 * DM1105_DMA_BYTES, &dev->dma_addr,
609*acc4c91eSChristophe JAILLET 					 GFP_KERNEL);
610a611d0caSIgor M. Liplianin 
61134d2f9bfSIgor M. Liplianin 	return !dev->ts_buf;
612a611d0caSIgor M. Liplianin }
613a611d0caSIgor M. Liplianin 
61434d2f9bfSIgor M. Liplianin static void dm1105_dma_unmap(struct dm1105_dev *dev)
615a611d0caSIgor M. Liplianin {
616*acc4c91eSChristophe JAILLET 	dma_free_coherent(&dev->pdev->dev, 6 * DM1105_DMA_BYTES, dev->ts_buf,
61734d2f9bfSIgor M. Liplianin 			  dev->dma_addr);
618a611d0caSIgor M. Liplianin }
619a611d0caSIgor M. Liplianin 
62034d2f9bfSIgor M. Liplianin static void dm1105_enable_irqs(struct dm1105_dev *dev)
621a611d0caSIgor M. Liplianin {
6225eb3291fSIgor M. Liplianin 	dm_writeb(DM1105_INTMAK, INTMAK_ALLMASK);
6235eb3291fSIgor M. Liplianin 	dm_writeb(DM1105_CR, 1);
624a611d0caSIgor M. Liplianin }
625a611d0caSIgor M. Liplianin 
62634d2f9bfSIgor M. Liplianin static void dm1105_disable_irqs(struct dm1105_dev *dev)
627a611d0caSIgor M. Liplianin {
6285eb3291fSIgor M. Liplianin 	dm_writeb(DM1105_INTMAK, INTMAK_IRM);
6295eb3291fSIgor M. Liplianin 	dm_writeb(DM1105_CR, 0);
630a611d0caSIgor M. Liplianin }
631a611d0caSIgor M. Liplianin 
63234d2f9bfSIgor M. Liplianin static int dm1105_start_feed(struct dvb_demux_feed *f)
633a611d0caSIgor M. Liplianin {
63434d2f9bfSIgor M. Liplianin 	struct dm1105_dev *dev = feed_to_dm1105_dev(f);
635a611d0caSIgor M. Liplianin 
63634d2f9bfSIgor M. Liplianin 	if (dev->full_ts_users++ == 0)
63734d2f9bfSIgor M. Liplianin 		dm1105_enable_irqs(dev);
638a611d0caSIgor M. Liplianin 
639a611d0caSIgor M. Liplianin 	return 0;
640a611d0caSIgor M. Liplianin }
641a611d0caSIgor M. Liplianin 
64234d2f9bfSIgor M. Liplianin static int dm1105_stop_feed(struct dvb_demux_feed *f)
643a611d0caSIgor M. Liplianin {
64434d2f9bfSIgor M. Liplianin 	struct dm1105_dev *dev = feed_to_dm1105_dev(f);
645a611d0caSIgor M. Liplianin 
64634d2f9bfSIgor M. Liplianin 	if (--dev->full_ts_users == 0)
64734d2f9bfSIgor M. Liplianin 		dm1105_disable_irqs(dev);
648a611d0caSIgor M. Liplianin 
649a611d0caSIgor M. Liplianin 	return 0;
650a611d0caSIgor M. Liplianin }
651a611d0caSIgor M. Liplianin 
652b72857ddSIgor M. Liplianin /* ir work handler */
653b72857ddSIgor M. Liplianin static void dm1105_emit_key(struct work_struct *work)
654a611d0caSIgor M. Liplianin {
655b72857ddSIgor M. Liplianin 	struct infrared *ir = container_of(work, struct infrared, work);
656a611d0caSIgor M. Liplianin 	u32 ircom = ir->ir_command;
657a611d0caSIgor M. Liplianin 	u8 data;
658a611d0caSIgor M. Liplianin 
659d1498ffcSIgor M. Liplianin 	if (ir_debug)
660d1498ffcSIgor M. Liplianin 		printk(KERN_INFO "%s: received byte 0x%04x\n", __func__, ircom);
661d1498ffcSIgor M. Liplianin 
662a611d0caSIgor M. Liplianin 	data = (ircom >> 8) & 0x7f;
663a611d0caSIgor M. Liplianin 
664120703f9SDavid Härdeman 	/* FIXME: UNKNOWN because we don't generate a full NEC scancode (yet?) */
6656d741bfeSSean Young 	rc_keydown(ir->dev, RC_PROTO_UNKNOWN, data, 0);
666a611d0caSIgor M. Liplianin }
667a611d0caSIgor M. Liplianin 
668d1498ffcSIgor M. Liplianin /* work handler */
669d1498ffcSIgor M. Liplianin static void dm1105_dmx_buffer(struct work_struct *work)
670a611d0caSIgor M. Liplianin {
67134d2f9bfSIgor M. Liplianin 	struct dm1105_dev *dev = container_of(work, struct dm1105_dev, work);
672a611d0caSIgor M. Liplianin 	unsigned int nbpackets;
67334d2f9bfSIgor M. Liplianin 	u32 oldwrp = dev->wrp;
67434d2f9bfSIgor M. Liplianin 	u32 nextwrp = dev->nextwrp;
675a611d0caSIgor M. Liplianin 
67634d2f9bfSIgor M. Liplianin 	if (!((dev->ts_buf[oldwrp] == 0x47) &&
67734d2f9bfSIgor M. Liplianin 			(dev->ts_buf[oldwrp + 188] == 0x47) &&
67834d2f9bfSIgor M. Liplianin 			(dev->ts_buf[oldwrp + 188 * 2] == 0x47))) {
67934d2f9bfSIgor M. Liplianin 		dev->PacketErrorCount++;
680a611d0caSIgor M. Liplianin 		/* bad packet found */
68134d2f9bfSIgor M. Liplianin 		if ((dev->PacketErrorCount >= 2) &&
68234d2f9bfSIgor M. Liplianin 				(dev->dmarst == 0)) {
6835eb3291fSIgor M. Liplianin 			dm_writeb(DM1105_RST, 1);
68434d2f9bfSIgor M. Liplianin 			dev->wrp = 0;
68534d2f9bfSIgor M. Liplianin 			dev->PacketErrorCount = 0;
68634d2f9bfSIgor M. Liplianin 			dev->dmarst = 0;
687d1498ffcSIgor M. Liplianin 			return;
688a611d0caSIgor M. Liplianin 		}
689a611d0caSIgor M. Liplianin 	}
690d1498ffcSIgor M. Liplianin 
691a611d0caSIgor M. Liplianin 	if (nextwrp < oldwrp) {
69234d2f9bfSIgor M. Liplianin 		memcpy(dev->ts_buf + dev->buffer_size, dev->ts_buf, nextwrp);
69334d2f9bfSIgor M. Liplianin 		nbpackets = ((dev->buffer_size - oldwrp) + nextwrp) / 188;
694d1498ffcSIgor M. Liplianin 	} else
695a611d0caSIgor M. Liplianin 		nbpackets = (nextwrp - oldwrp) / 188;
696d1498ffcSIgor M. Liplianin 
69734d2f9bfSIgor M. Liplianin 	dev->wrp = nextwrp;
69834d2f9bfSIgor M. Liplianin 	dvb_dmx_swfilter_packets(&dev->demux, &dev->ts_buf[oldwrp], nbpackets);
699d1498ffcSIgor M. Liplianin }
700d1498ffcSIgor M. Liplianin 
70134d2f9bfSIgor M. Liplianin static irqreturn_t dm1105_irq(int irq, void *dev_id)
702d1498ffcSIgor M. Liplianin {
70334d2f9bfSIgor M. Liplianin 	struct dm1105_dev *dev = dev_id;
704d1498ffcSIgor M. Liplianin 
705d1498ffcSIgor M. Liplianin 	/* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */
7065eb3291fSIgor M. Liplianin 	unsigned int intsts = dm_readb(DM1105_INTSTS);
7075eb3291fSIgor M. Liplianin 	dm_writeb(DM1105_INTSTS, intsts);
708d1498ffcSIgor M. Liplianin 
709d1498ffcSIgor M. Liplianin 	switch (intsts) {
710d1498ffcSIgor M. Liplianin 	case INTSTS_TSIRQ:
711d1498ffcSIgor M. Liplianin 	case (INTSTS_TSIRQ | INTSTS_IR):
7125eb3291fSIgor M. Liplianin 		dev->nextwrp = dm_readl(DM1105_WRP) - dm_readl(DM1105_STADR);
71334d2f9bfSIgor M. Liplianin 		queue_work(dev->wq, &dev->work);
714a611d0caSIgor M. Liplianin 		break;
715a611d0caSIgor M. Liplianin 	case INTSTS_IR:
7165eb3291fSIgor M. Liplianin 		dev->ir.ir_command = dm_readl(DM1105_IRCODE);
71734d2f9bfSIgor M. Liplianin 		schedule_work(&dev->ir.work);
718a611d0caSIgor M. Liplianin 		break;
719a611d0caSIgor M. Liplianin 	}
720d1498ffcSIgor M. Liplianin 
721a611d0caSIgor M. Liplianin 	return IRQ_HANDLED;
722a611d0caSIgor M. Liplianin }
723a611d0caSIgor M. Liplianin 
7244c62e976SGreg Kroah-Hartman static int dm1105_ir_init(struct dm1105_dev *dm1105)
725a611d0caSIgor M. Liplianin {
726d8b4b582SDavid Härdeman 	struct rc_dev *dev;
727b72857ddSIgor M. Liplianin 	int err = -ENOMEM;
728a611d0caSIgor M. Liplianin 
7290f7499fdSAndi Shyti 	dev = rc_allocate_device(RC_DRIVER_SCANCODE);
730d8b4b582SDavid Härdeman 	if (!dev)
731a611d0caSIgor M. Liplianin 		return -ENOMEM;
732a611d0caSIgor M. Liplianin 
733a611d0caSIgor M. Liplianin 	snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys),
734a611d0caSIgor M. Liplianin 		"pci-%s/ir0", pci_name(dm1105->pdev));
735a611d0caSIgor M. Liplianin 
736d8b4b582SDavid Härdeman 	dev->driver_name = MODULE_NAME;
737d8b4b582SDavid Härdeman 	dev->map_name = RC_MAP_DM1105_NEC;
738518f4b26SSean Young 	dev->device_name = "DVB on-card IR receiver";
739d8b4b582SDavid Härdeman 	dev->input_phys = dm1105->ir.input_phys;
740d8b4b582SDavid Härdeman 	dev->input_id.bustype = BUS_PCI;
741d8b4b582SDavid Härdeman 	dev->input_id.version = 1;
742a611d0caSIgor M. Liplianin 	if (dm1105->pdev->subsystem_vendor) {
743d8b4b582SDavid Härdeman 		dev->input_id.vendor = dm1105->pdev->subsystem_vendor;
744d8b4b582SDavid Härdeman 		dev->input_id.product = dm1105->pdev->subsystem_device;
745a611d0caSIgor M. Liplianin 	} else {
746d8b4b582SDavid Härdeman 		dev->input_id.vendor = dm1105->pdev->vendor;
747d8b4b582SDavid Härdeman 		dev->input_id.product = dm1105->pdev->device;
748a611d0caSIgor M. Liplianin 	}
749d8b4b582SDavid Härdeman 	dev->dev.parent = &dm1105->pdev->dev;
750b72857ddSIgor M. Liplianin 
751b72857ddSIgor M. Liplianin 	INIT_WORK(&dm1105->ir.work, dm1105_emit_key);
752b72857ddSIgor M. Liplianin 
753d8b4b582SDavid Härdeman 	err = rc_register_device(dev);
75415100d89SDavid Härdeman 	if (err < 0) {
755d8b4b582SDavid Härdeman 		rc_free_device(dev);
756579e7d60SMauro Carvalho Chehab 		return err;
757a611d0caSIgor M. Liplianin 	}
758a611d0caSIgor M. Liplianin 
759d8b4b582SDavid Härdeman 	dm1105->ir.dev = dev;
76015100d89SDavid Härdeman 	return 0;
76115100d89SDavid Härdeman }
76215100d89SDavid Härdeman 
7634c62e976SGreg Kroah-Hartman static void dm1105_ir_exit(struct dm1105_dev *dm1105)
764a611d0caSIgor M. Liplianin {
765d8b4b582SDavid Härdeman 	rc_unregister_device(dm1105->ir.dev);
766a611d0caSIgor M. Liplianin }
767a611d0caSIgor M. Liplianin 
7684c62e976SGreg Kroah-Hartman static int dm1105_hw_init(struct dm1105_dev *dev)
769a611d0caSIgor M. Liplianin {
77034d2f9bfSIgor M. Liplianin 	dm1105_disable_irqs(dev);
771a611d0caSIgor M. Liplianin 
7725eb3291fSIgor M. Liplianin 	dm_writeb(DM1105_HOST_CTR, 0);
773a611d0caSIgor M. Liplianin 
774a611d0caSIgor M. Liplianin 	/*DATALEN 188,*/
7755eb3291fSIgor M. Liplianin 	dm_writeb(DM1105_DTALENTH, 188);
776a611d0caSIgor M. Liplianin 	/*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/
7775eb3291fSIgor M. Liplianin 	dm_writew(DM1105_TSCTR, 0xc10a);
778a611d0caSIgor M. Liplianin 
779a611d0caSIgor M. Liplianin 	/* map DMA and set address */
78034d2f9bfSIgor M. Liplianin 	dm1105_dma_map(dev);
78134d2f9bfSIgor M. Liplianin 	dm1105_set_dma_addr(dev);
782a611d0caSIgor M. Liplianin 	/* big buffer */
7835eb3291fSIgor M. Liplianin 	dm_writel(DM1105_RLEN, 5 * DM1105_DMA_BYTES);
7845eb3291fSIgor M. Liplianin 	dm_writeb(DM1105_INTCNT, 47);
785a611d0caSIgor M. Liplianin 
786a611d0caSIgor M. Liplianin 	/* IR NEC mode enable */
7875eb3291fSIgor M. Liplianin 	dm_writeb(DM1105_IRCTR, (DM1105_IR_EN | DM1105_SYS_CHK));
7885eb3291fSIgor M. Liplianin 	dm_writeb(DM1105_IRMODE, 0);
7895eb3291fSIgor M. Liplianin 	dm_writew(DM1105_SYSTEMCODE, 0);
790a611d0caSIgor M. Liplianin 
791a611d0caSIgor M. Liplianin 	return 0;
792a611d0caSIgor M. Liplianin }
793a611d0caSIgor M. Liplianin 
79434d2f9bfSIgor M. Liplianin static void dm1105_hw_exit(struct dm1105_dev *dev)
795a611d0caSIgor M. Liplianin {
79634d2f9bfSIgor M. Liplianin 	dm1105_disable_irqs(dev);
797a611d0caSIgor M. Liplianin 
798a611d0caSIgor M. Liplianin 	/* IR disable */
7995eb3291fSIgor M. Liplianin 	dm_writeb(DM1105_IRCTR, 0);
8005eb3291fSIgor M. Liplianin 	dm_writeb(DM1105_INTMAK, INTMAK_NONEMASK);
801a611d0caSIgor M. Liplianin 
80234d2f9bfSIgor M. Liplianin 	dm1105_dma_unmap(dev);
803a611d0caSIgor M. Liplianin }
804e4aab64cSIgor M. Liplianin 
805650497f1SBhumika Goyal static const struct stv0299_config sharp_z0194a_config = {
806d4305c68SIgor M. Liplianin 	.demod_address = 0x68,
807d4305c68SIgor M. Liplianin 	.inittab = sharp_z0194a_inittab,
808d4305c68SIgor M. Liplianin 	.mclk = 88000000UL,
809d4305c68SIgor M. Liplianin 	.invert = 1,
810d4305c68SIgor M. Liplianin 	.skip_reinit = 0,
811d4305c68SIgor M. Liplianin 	.lock_output = STV0299_LOCKOUTPUT_1,
812d4305c68SIgor M. Liplianin 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
813d4305c68SIgor M. Liplianin 	.min_delay_ms = 100,
814d4305c68SIgor M. Liplianin 	.set_symbol_rate = sharp_z0194a_set_symbol_rate,
815d4305c68SIgor M. Liplianin };
816d4305c68SIgor M. Liplianin 
817a611d0caSIgor M. Liplianin static struct stv0288_config earda_config = {
818a611d0caSIgor M. Liplianin 	.demod_address = 0x68,
819a611d0caSIgor M. Liplianin 	.min_delay_ms = 100,
820a611d0caSIgor M. Liplianin };
821a611d0caSIgor M. Liplianin 
822a611d0caSIgor M. Liplianin static struct si21xx_config serit_config = {
823a611d0caSIgor M. Liplianin 	.demod_address = 0x68,
824a611d0caSIgor M. Liplianin 	.min_delay_ms = 100,
825a611d0caSIgor M. Liplianin 
826a611d0caSIgor M. Liplianin };
827a611d0caSIgor M. Liplianin 
828a611d0caSIgor M. Liplianin static struct cx24116_config serit_sp2633_config = {
829a611d0caSIgor M. Liplianin 	.demod_address = 0x55,
830a611d0caSIgor M. Liplianin };
831a611d0caSIgor M. Liplianin 
832b4a0e816SIgor M. Liplianin static struct ds3000_config dvbworld_ds3000_config = {
833b4a0e816SIgor M. Liplianin 	.demod_address = 0x68,
834b4a0e816SIgor M. Liplianin };
835b4a0e816SIgor M. Liplianin 
83673f0af44SKonstantin Dimitrov static struct ts2020_config dvbworld_ts2020_config  = {
83773f0af44SKonstantin Dimitrov 	.tuner_address = 0x60,
838b858c331SIgor M. Liplianin 	.clk_out_div = 1,
83973f0af44SKonstantin Dimitrov };
84073f0af44SKonstantin Dimitrov 
8414c62e976SGreg Kroah-Hartman static int frontend_init(struct dm1105_dev *dev)
842a611d0caSIgor M. Liplianin {
843a611d0caSIgor M. Liplianin 	int ret;
844a611d0caSIgor M. Liplianin 
84534d2f9bfSIgor M. Liplianin 	switch (dev->boardnr) {
8460017505dSIgor M. Liplianin 	case DM1105_BOARD_UNBRANDED_I2C_ON_GPIO:
8470017505dSIgor M. Liplianin 		dm1105_gpio_enable(dev, GPIO15, 1);
8480017505dSIgor M. Liplianin 		dm1105_gpio_clear(dev, GPIO15);
8490017505dSIgor M. Liplianin 		msleep(100);
8500017505dSIgor M. Liplianin 		dm1105_gpio_set(dev, GPIO15);
8510017505dSIgor M. Liplianin 		msleep(200);
8520017505dSIgor M. Liplianin 		dev->fe = dvb_attach(
8530017505dSIgor M. Liplianin 			stv0299_attach, &sharp_z0194a_config,
8540017505dSIgor M. Liplianin 			&dev->i2c_bb_adap);
8550017505dSIgor M. Liplianin 		if (dev->fe) {
8560017505dSIgor M. Liplianin 			dev->fe->ops.set_voltage = dm1105_set_voltage;
8570017505dSIgor M. Liplianin 			dvb_attach(dvb_pll_attach, dev->fe, 0x60,
8580017505dSIgor M. Liplianin 					&dev->i2c_bb_adap, DVB_PLL_OPERA1);
8590017505dSIgor M. Liplianin 			break;
8600017505dSIgor M. Liplianin 		}
8610017505dSIgor M. Liplianin 
8620017505dSIgor M. Liplianin 		dev->fe = dvb_attach(
8630017505dSIgor M. Liplianin 			stv0288_attach, &earda_config,
8640017505dSIgor M. Liplianin 			&dev->i2c_bb_adap);
8650017505dSIgor M. Liplianin 		if (dev->fe) {
8660017505dSIgor M. Liplianin 			dev->fe->ops.set_voltage = dm1105_set_voltage;
8670017505dSIgor M. Liplianin 			dvb_attach(stb6000_attach, dev->fe, 0x61,
8680017505dSIgor M. Liplianin 					&dev->i2c_bb_adap);
8690017505dSIgor M. Liplianin 			break;
8700017505dSIgor M. Liplianin 		}
8710017505dSIgor M. Liplianin 
8720017505dSIgor M. Liplianin 		dev->fe = dvb_attach(
8730017505dSIgor M. Liplianin 			si21xx_attach, &serit_config,
8740017505dSIgor M. Liplianin 			&dev->i2c_bb_adap);
8750017505dSIgor M. Liplianin 		if (dev->fe)
8760017505dSIgor M. Liplianin 			dev->fe->ops.set_voltage = dm1105_set_voltage;
8770017505dSIgor M. Liplianin 		break;
878d8300df9SIgor M. Liplianin 	case DM1105_BOARD_DVBWORLD_2004:
87934d2f9bfSIgor M. Liplianin 		dev->fe = dvb_attach(
880519a4bdcSIgor M. Liplianin 			cx24116_attach, &serit_sp2633_config,
88134d2f9bfSIgor M. Liplianin 			&dev->i2c_adap);
88234d2f9bfSIgor M. Liplianin 		if (dev->fe) {
88334d2f9bfSIgor M. Liplianin 			dev->fe->ops.set_voltage = dm1105_set_voltage;
884b4a0e816SIgor M. Liplianin 			break;
885b4a0e816SIgor M. Liplianin 		}
886b4a0e816SIgor M. Liplianin 
88734d2f9bfSIgor M. Liplianin 		dev->fe = dvb_attach(
888b4a0e816SIgor M. Liplianin 			ds3000_attach, &dvbworld_ds3000_config,
88934d2f9bfSIgor M. Liplianin 			&dev->i2c_adap);
89073f0af44SKonstantin Dimitrov 		if (dev->fe) {
89173f0af44SKonstantin Dimitrov 			dvb_attach(ts2020_attach, dev->fe,
89273f0af44SKonstantin Dimitrov 				&dvbworld_ts2020_config, &dev->i2c_adap);
89334d2f9bfSIgor M. Liplianin 			dev->fe->ops.set_voltage = dm1105_set_voltage;
89473f0af44SKonstantin Dimitrov 		}
895519a4bdcSIgor M. Liplianin 
896519a4bdcSIgor M. Liplianin 		break;
897d8300df9SIgor M. Liplianin 	case DM1105_BOARD_DVBWORLD_2002:
898d8300df9SIgor M. Liplianin 	case DM1105_BOARD_AXESS_DM05:
899519a4bdcSIgor M. Liplianin 	default:
90034d2f9bfSIgor M. Liplianin 		dev->fe = dvb_attach(
901a611d0caSIgor M. Liplianin 			stv0299_attach, &sharp_z0194a_config,
90234d2f9bfSIgor M. Liplianin 			&dev->i2c_adap);
90334d2f9bfSIgor M. Liplianin 		if (dev->fe) {
90434d2f9bfSIgor M. Liplianin 			dev->fe->ops.set_voltage = dm1105_set_voltage;
90534d2f9bfSIgor M. Liplianin 			dvb_attach(dvb_pll_attach, dev->fe, 0x60,
90634d2f9bfSIgor M. Liplianin 					&dev->i2c_adap, DVB_PLL_OPERA1);
907519a4bdcSIgor M. Liplianin 			break;
908a611d0caSIgor M. Liplianin 		}
909e4aab64cSIgor M. Liplianin 
91034d2f9bfSIgor M. Liplianin 		dev->fe = dvb_attach(
911a611d0caSIgor M. Liplianin 			stv0288_attach, &earda_config,
91234d2f9bfSIgor M. Liplianin 			&dev->i2c_adap);
91334d2f9bfSIgor M. Liplianin 		if (dev->fe) {
91434d2f9bfSIgor M. Liplianin 			dev->fe->ops.set_voltage = dm1105_set_voltage;
91534d2f9bfSIgor M. Liplianin 			dvb_attach(stb6000_attach, dev->fe, 0x61,
91634d2f9bfSIgor M. Liplianin 					&dev->i2c_adap);
917519a4bdcSIgor M. Liplianin 			break;
918a611d0caSIgor M. Liplianin 		}
919e4aab64cSIgor M. Liplianin 
92034d2f9bfSIgor M. Liplianin 		dev->fe = dvb_attach(
921a611d0caSIgor M. Liplianin 			si21xx_attach, &serit_config,
92234d2f9bfSIgor M. Liplianin 			&dev->i2c_adap);
92334d2f9bfSIgor M. Liplianin 		if (dev->fe)
92434d2f9bfSIgor M. Liplianin 			dev->fe->ops.set_voltage = dm1105_set_voltage;
925519a4bdcSIgor M. Liplianin 
926a611d0caSIgor M. Liplianin 	}
927a611d0caSIgor M. Liplianin 
92834d2f9bfSIgor M. Liplianin 	if (!dev->fe) {
92934d2f9bfSIgor M. Liplianin 		dev_err(&dev->pdev->dev, "could not attach frontend\n");
930a611d0caSIgor M. Liplianin 		return -ENODEV;
931a611d0caSIgor M. Liplianin 	}
932a611d0caSIgor M. Liplianin 
93334d2f9bfSIgor M. Liplianin 	ret = dvb_register_frontend(&dev->dvb_adapter, dev->fe);
934a611d0caSIgor M. Liplianin 	if (ret < 0) {
93534d2f9bfSIgor M. Liplianin 		if (dev->fe->ops.release)
93634d2f9bfSIgor M. Liplianin 			dev->fe->ops.release(dev->fe);
93734d2f9bfSIgor M. Liplianin 		dev->fe = NULL;
938a611d0caSIgor M. Liplianin 		return ret;
939a611d0caSIgor M. Liplianin 	}
940a611d0caSIgor M. Liplianin 
941a611d0caSIgor M. Liplianin 	return 0;
942a611d0caSIgor M. Liplianin }
943a611d0caSIgor M. Liplianin 
9444c62e976SGreg Kroah-Hartman static void dm1105_read_mac(struct dm1105_dev *dev, u8 *mac)
945a611d0caSIgor M. Liplianin {
946a611d0caSIgor M. Liplianin 	static u8 command[1] = { 0x28 };
947a611d0caSIgor M. Liplianin 
948a611d0caSIgor M. Liplianin 	struct i2c_msg msg[] = {
949519a4bdcSIgor M. Liplianin 		{
950519a4bdcSIgor M. Liplianin 			.addr = IIC_24C01_addr >> 1,
951519a4bdcSIgor M. Liplianin 			.flags = 0,
952519a4bdcSIgor M. Liplianin 			.buf = command,
953519a4bdcSIgor M. Liplianin 			.len = 1
954519a4bdcSIgor M. Liplianin 		}, {
955519a4bdcSIgor M. Liplianin 			.addr = IIC_24C01_addr >> 1,
956519a4bdcSIgor M. Liplianin 			.flags = I2C_M_RD,
957519a4bdcSIgor M. Liplianin 			.buf = mac,
958519a4bdcSIgor M. Liplianin 			.len = 6
959519a4bdcSIgor M. Liplianin 		},
960a611d0caSIgor M. Liplianin 	};
961a611d0caSIgor M. Liplianin 
96234d2f9bfSIgor M. Liplianin 	dm1105_i2c_xfer(&dev->i2c_adap, msg , 2);
96334d2f9bfSIgor M. Liplianin 	dev_info(&dev->pdev->dev, "MAC %pM\n", mac);
964a611d0caSIgor M. Liplianin }
965a611d0caSIgor M. Liplianin 
9664c62e976SGreg Kroah-Hartman static int dm1105_probe(struct pci_dev *pdev,
967a611d0caSIgor M. Liplianin 				  const struct pci_device_id *ent)
968a611d0caSIgor M. Liplianin {
96934d2f9bfSIgor M. Liplianin 	struct dm1105_dev *dev;
970a611d0caSIgor M. Liplianin 	struct dvb_adapter *dvb_adapter;
971a611d0caSIgor M. Liplianin 	struct dvb_demux *dvbdemux;
972a611d0caSIgor M. Liplianin 	struct dmx_demux *dmx;
973a611d0caSIgor M. Liplianin 	int ret = -ENOMEM;
974d8300df9SIgor M. Liplianin 	int i;
975a611d0caSIgor M. Liplianin 
97665b40a98SAnton Vasilyev 	if (dm1105_devcount >= ARRAY_SIZE(card))
97765b40a98SAnton Vasilyev 		return -ENODEV;
97865b40a98SAnton Vasilyev 
97934d2f9bfSIgor M. Liplianin 	dev = kzalloc(sizeof(struct dm1105_dev), GFP_KERNEL);
98034d2f9bfSIgor M. Liplianin 	if (!dev)
981d1498ffcSIgor M. Liplianin 		return -ENOMEM;
982a611d0caSIgor M. Liplianin 
983d8300df9SIgor M. Liplianin 	/* board config */
98434d2f9bfSIgor M. Liplianin 	dev->nr = dm1105_devcount;
98534d2f9bfSIgor M. Liplianin 	dev->boardnr = UNSET;
98634d2f9bfSIgor M. Liplianin 	if (card[dev->nr] < ARRAY_SIZE(dm1105_boards))
98734d2f9bfSIgor M. Liplianin 		dev->boardnr = card[dev->nr];
98834d2f9bfSIgor M. Liplianin 	for (i = 0; UNSET == dev->boardnr &&
989d8300df9SIgor M. Liplianin 				i < ARRAY_SIZE(dm1105_subids); i++)
990d8300df9SIgor M. Liplianin 		if (pdev->subsystem_vendor ==
991d8300df9SIgor M. Liplianin 			dm1105_subids[i].subvendor &&
992d8300df9SIgor M. Liplianin 				pdev->subsystem_device ==
993d8300df9SIgor M. Liplianin 					dm1105_subids[i].subdevice)
99434d2f9bfSIgor M. Liplianin 			dev->boardnr = dm1105_subids[i].card;
995d8300df9SIgor M. Liplianin 
99634d2f9bfSIgor M. Liplianin 	if (UNSET == dev->boardnr) {
99734d2f9bfSIgor M. Liplianin 		dev->boardnr = DM1105_BOARD_UNKNOWN;
998d8300df9SIgor M. Liplianin 		dm1105_card_list(pdev);
999d8300df9SIgor M. Liplianin 	}
1000d8300df9SIgor M. Liplianin 
1001d8300df9SIgor M. Liplianin 	dm1105_devcount++;
100234d2f9bfSIgor M. Liplianin 	dev->pdev = pdev;
100334d2f9bfSIgor M. Liplianin 	dev->buffer_size = 5 * DM1105_DMA_BYTES;
100434d2f9bfSIgor M. Liplianin 	dev->PacketErrorCount = 0;
100534d2f9bfSIgor M. Liplianin 	dev->dmarst = 0;
1006a611d0caSIgor M. Liplianin 
1007a611d0caSIgor M. Liplianin 	ret = pci_enable_device(pdev);
1008a611d0caSIgor M. Liplianin 	if (ret < 0)
1009a611d0caSIgor M. Liplianin 		goto err_kfree;
1010a611d0caSIgor M. Liplianin 
1011*acc4c91eSChristophe JAILLET 	ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
1012a611d0caSIgor M. Liplianin 	if (ret < 0)
1013a611d0caSIgor M. Liplianin 		goto err_pci_disable_device;
1014a611d0caSIgor M. Liplianin 
1015a611d0caSIgor M. Liplianin 	pci_set_master(pdev);
1016a611d0caSIgor M. Liplianin 
1017a611d0caSIgor M. Liplianin 	ret = pci_request_regions(pdev, DRIVER_NAME);
1018a611d0caSIgor M. Liplianin 	if (ret < 0)
1019a611d0caSIgor M. Liplianin 		goto err_pci_disable_device;
1020a611d0caSIgor M. Liplianin 
102134d2f9bfSIgor M. Liplianin 	dev->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
102234d2f9bfSIgor M. Liplianin 	if (!dev->io_mem) {
1023a611d0caSIgor M. Liplianin 		ret = -EIO;
1024a611d0caSIgor M. Liplianin 		goto err_pci_release_regions;
1025a611d0caSIgor M. Liplianin 	}
1026a611d0caSIgor M. Liplianin 
102734d2f9bfSIgor M. Liplianin 	spin_lock_init(&dev->lock);
102834d2f9bfSIgor M. Liplianin 	pci_set_drvdata(pdev, dev);
1029a611d0caSIgor M. Liplianin 
103034d2f9bfSIgor M. Liplianin 	ret = dm1105_hw_init(dev);
1031a611d0caSIgor M. Liplianin 	if (ret < 0)
1032d1498ffcSIgor M. Liplianin 		goto err_pci_iounmap;
1033a611d0caSIgor M. Liplianin 
1034a611d0caSIgor M. Liplianin 	/* i2c */
103534d2f9bfSIgor M. Liplianin 	i2c_set_adapdata(&dev->i2c_adap, dev);
1036cc1e6315SMauro Carvalho Chehab 	strscpy(dev->i2c_adap.name, DRIVER_NAME, sizeof(dev->i2c_adap.name));
103734d2f9bfSIgor M. Liplianin 	dev->i2c_adap.owner = THIS_MODULE;
103834d2f9bfSIgor M. Liplianin 	dev->i2c_adap.dev.parent = &pdev->dev;
103934d2f9bfSIgor M. Liplianin 	dev->i2c_adap.algo = &dm1105_algo;
104034d2f9bfSIgor M. Liplianin 	dev->i2c_adap.algo_data = dev;
104134d2f9bfSIgor M. Liplianin 	ret = i2c_add_adapter(&dev->i2c_adap);
1042a611d0caSIgor M. Liplianin 
1043a611d0caSIgor M. Liplianin 	if (ret < 0)
104434d2f9bfSIgor M. Liplianin 		goto err_dm1105_hw_exit;
1045a611d0caSIgor M. Liplianin 
10460017505dSIgor M. Liplianin 	i2c_set_adapdata(&dev->i2c_bb_adap, dev);
1047cc1e6315SMauro Carvalho Chehab 	strscpy(dev->i2c_bb_adap.name, DM1105_I2C_GPIO_NAME,
1048cc1e6315SMauro Carvalho Chehab 		sizeof(dev->i2c_bb_adap.name));
10490017505dSIgor M. Liplianin 	dev->i2c_bb_adap.owner = THIS_MODULE;
10500017505dSIgor M. Liplianin 	dev->i2c_bb_adap.dev.parent = &pdev->dev;
10510017505dSIgor M. Liplianin 	dev->i2c_bb_adap.algo_data = &dev->i2c_bit;
10520017505dSIgor M. Liplianin 	dev->i2c_bit.data = dev;
10530017505dSIgor M. Liplianin 	dev->i2c_bit.setsda = dm1105_setsda;
10540017505dSIgor M. Liplianin 	dev->i2c_bit.setscl = dm1105_setscl;
10550017505dSIgor M. Liplianin 	dev->i2c_bit.getsda = dm1105_getsda;
10560017505dSIgor M. Liplianin 	dev->i2c_bit.getscl = dm1105_getscl;
10570017505dSIgor M. Liplianin 	dev->i2c_bit.udelay = 10;
10580017505dSIgor M. Liplianin 	dev->i2c_bit.timeout = 10;
10590017505dSIgor M. Liplianin 
10600017505dSIgor M. Liplianin 	/* Raise SCL and SDA */
10610017505dSIgor M. Liplianin 	dm1105_setsda(dev, 1);
10620017505dSIgor M. Liplianin 	dm1105_setscl(dev, 1);
10630017505dSIgor M. Liplianin 
10640017505dSIgor M. Liplianin 	ret = i2c_bit_add_bus(&dev->i2c_bb_adap);
10650017505dSIgor M. Liplianin 	if (ret < 0)
10660017505dSIgor M. Liplianin 		goto err_i2c_del_adapter;
10670017505dSIgor M. Liplianin 
1068a611d0caSIgor M. Liplianin 	/* dvb */
106934d2f9bfSIgor M. Liplianin 	ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME,
1070a611d0caSIgor M. Liplianin 					THIS_MODULE, &pdev->dev, adapter_nr);
1071a611d0caSIgor M. Liplianin 	if (ret < 0)
10720017505dSIgor M. Liplianin 		goto err_i2c_del_adapters;
1073a611d0caSIgor M. Liplianin 
107434d2f9bfSIgor M. Liplianin 	dvb_adapter = &dev->dvb_adapter;
1075a611d0caSIgor M. Liplianin 
107634d2f9bfSIgor M. Liplianin 	dm1105_read_mac(dev, dvb_adapter->proposed_mac);
1077a611d0caSIgor M. Liplianin 
107834d2f9bfSIgor M. Liplianin 	dvbdemux = &dev->demux;
1079a611d0caSIgor M. Liplianin 	dvbdemux->filternum = 256;
1080a611d0caSIgor M. Liplianin 	dvbdemux->feednum = 256;
108134d2f9bfSIgor M. Liplianin 	dvbdemux->start_feed = dm1105_start_feed;
108234d2f9bfSIgor M. Liplianin 	dvbdemux->stop_feed = dm1105_stop_feed;
1083a611d0caSIgor M. Liplianin 	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
1084a611d0caSIgor M. Liplianin 			DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
1085a611d0caSIgor M. Liplianin 	ret = dvb_dmx_init(dvbdemux);
1086a611d0caSIgor M. Liplianin 	if (ret < 0)
1087a611d0caSIgor M. Liplianin 		goto err_dvb_unregister_adapter;
1088a611d0caSIgor M. Liplianin 
1089a611d0caSIgor M. Liplianin 	dmx = &dvbdemux->dmx;
109034d2f9bfSIgor M. Liplianin 	dev->dmxdev.filternum = 256;
109134d2f9bfSIgor M. Liplianin 	dev->dmxdev.demux = dmx;
109234d2f9bfSIgor M. Liplianin 	dev->dmxdev.capabilities = 0;
1093a611d0caSIgor M. Liplianin 
109434d2f9bfSIgor M. Liplianin 	ret = dvb_dmxdev_init(&dev->dmxdev, dvb_adapter);
1095a611d0caSIgor M. Liplianin 	if (ret < 0)
1096a611d0caSIgor M. Liplianin 		goto err_dvb_dmx_release;
1097a611d0caSIgor M. Liplianin 
109834d2f9bfSIgor M. Liplianin 	dev->hw_frontend.source = DMX_FRONTEND_0;
1099a611d0caSIgor M. Liplianin 
110034d2f9bfSIgor M. Liplianin 	ret = dmx->add_frontend(dmx, &dev->hw_frontend);
1101a611d0caSIgor M. Liplianin 	if (ret < 0)
1102a611d0caSIgor M. Liplianin 		goto err_dvb_dmxdev_release;
1103a611d0caSIgor M. Liplianin 
110434d2f9bfSIgor M. Liplianin 	dev->mem_frontend.source = DMX_MEMORY_FE;
1105a611d0caSIgor M. Liplianin 
110634d2f9bfSIgor M. Liplianin 	ret = dmx->add_frontend(dmx, &dev->mem_frontend);
1107a611d0caSIgor M. Liplianin 	if (ret < 0)
1108a611d0caSIgor M. Liplianin 		goto err_remove_hw_frontend;
1109a611d0caSIgor M. Liplianin 
111034d2f9bfSIgor M. Liplianin 	ret = dmx->connect_frontend(dmx, &dev->hw_frontend);
1111a611d0caSIgor M. Liplianin 	if (ret < 0)
1112a611d0caSIgor M. Liplianin 		goto err_remove_mem_frontend;
1113a611d0caSIgor M. Liplianin 
11145584c641SJonathan Nieder 	ret = dvb_net_init(dvb_adapter, &dev->dvbnet, dmx);
11155584c641SJonathan Nieder 	if (ret < 0)
11165584c641SJonathan Nieder 		goto err_disconnect_frontend;
11175584c641SJonathan Nieder 
111834d2f9bfSIgor M. Liplianin 	ret = frontend_init(dev);
1119a611d0caSIgor M. Liplianin 	if (ret < 0)
1120e9966341SJonathan Nieder 		goto err_dvb_net;
1121a611d0caSIgor M. Liplianin 
112234d2f9bfSIgor M. Liplianin 	dm1105_ir_init(dev);
1123d1498ffcSIgor M. Liplianin 
112434d2f9bfSIgor M. Liplianin 	INIT_WORK(&dev->work, dm1105_dmx_buffer);
112534d2f9bfSIgor M. Liplianin 	sprintf(dev->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num);
112634d2f9bfSIgor M. Liplianin 	dev->wq = create_singlethread_workqueue(dev->wqn);
112795d08126SPeter Senna Tschudin 	if (!dev->wq) {
112895d08126SPeter Senna Tschudin 		ret = -ENOMEM;
1129519a4bdcSIgor M. Liplianin 		goto err_dvb_net;
113095d08126SPeter Senna Tschudin 	}
1131d1498ffcSIgor M. Liplianin 
113234d2f9bfSIgor M. Liplianin 	ret = request_irq(pdev->irq, dm1105_irq, IRQF_SHARED,
113334d2f9bfSIgor M. Liplianin 						DRIVER_NAME, dev);
1134d1498ffcSIgor M. Liplianin 	if (ret < 0)
1135519a4bdcSIgor M. Liplianin 		goto err_workqueue;
1136d1498ffcSIgor M. Liplianin 
1137d1498ffcSIgor M. Liplianin 	return 0;
1138a611d0caSIgor M. Liplianin 
1139519a4bdcSIgor M. Liplianin err_workqueue:
114034d2f9bfSIgor M. Liplianin 	destroy_workqueue(dev->wq);
1141519a4bdcSIgor M. Liplianin err_dvb_net:
114234d2f9bfSIgor M. Liplianin 	dvb_net_release(&dev->dvbnet);
1143a611d0caSIgor M. Liplianin err_disconnect_frontend:
1144a611d0caSIgor M. Liplianin 	dmx->disconnect_frontend(dmx);
1145a611d0caSIgor M. Liplianin err_remove_mem_frontend:
114634d2f9bfSIgor M. Liplianin 	dmx->remove_frontend(dmx, &dev->mem_frontend);
1147a611d0caSIgor M. Liplianin err_remove_hw_frontend:
114834d2f9bfSIgor M. Liplianin 	dmx->remove_frontend(dmx, &dev->hw_frontend);
1149a611d0caSIgor M. Liplianin err_dvb_dmxdev_release:
115034d2f9bfSIgor M. Liplianin 	dvb_dmxdev_release(&dev->dmxdev);
1151a611d0caSIgor M. Liplianin err_dvb_dmx_release:
1152a611d0caSIgor M. Liplianin 	dvb_dmx_release(dvbdemux);
1153a611d0caSIgor M. Liplianin err_dvb_unregister_adapter:
1154a611d0caSIgor M. Liplianin 	dvb_unregister_adapter(dvb_adapter);
11550017505dSIgor M. Liplianin err_i2c_del_adapters:
11560017505dSIgor M. Liplianin 	i2c_del_adapter(&dev->i2c_bb_adap);
1157a611d0caSIgor M. Liplianin err_i2c_del_adapter:
115834d2f9bfSIgor M. Liplianin 	i2c_del_adapter(&dev->i2c_adap);
115934d2f9bfSIgor M. Liplianin err_dm1105_hw_exit:
116034d2f9bfSIgor M. Liplianin 	dm1105_hw_exit(dev);
1161a611d0caSIgor M. Liplianin err_pci_iounmap:
116234d2f9bfSIgor M. Liplianin 	pci_iounmap(pdev, dev->io_mem);
1163a611d0caSIgor M. Liplianin err_pci_release_regions:
1164a611d0caSIgor M. Liplianin 	pci_release_regions(pdev);
1165a611d0caSIgor M. Liplianin err_pci_disable_device:
1166a611d0caSIgor M. Liplianin 	pci_disable_device(pdev);
1167a611d0caSIgor M. Liplianin err_kfree:
116834d2f9bfSIgor M. Liplianin 	kfree(dev);
1169d1498ffcSIgor M. Liplianin 	return ret;
1170a611d0caSIgor M. Liplianin }
1171a611d0caSIgor M. Liplianin 
11724c62e976SGreg Kroah-Hartman static void dm1105_remove(struct pci_dev *pdev)
1173a611d0caSIgor M. Liplianin {
117434d2f9bfSIgor M. Liplianin 	struct dm1105_dev *dev = pci_get_drvdata(pdev);
117534d2f9bfSIgor M. Liplianin 	struct dvb_adapter *dvb_adapter = &dev->dvb_adapter;
117634d2f9bfSIgor M. Liplianin 	struct dvb_demux *dvbdemux = &dev->demux;
1177a611d0caSIgor M. Liplianin 	struct dmx_demux *dmx = &dvbdemux->dmx;
1178a611d0caSIgor M. Liplianin 
117934d2f9bfSIgor M. Liplianin 	dm1105_ir_exit(dev);
1180a611d0caSIgor M. Liplianin 	dmx->close(dmx);
118134d2f9bfSIgor M. Liplianin 	dvb_net_release(&dev->dvbnet);
118234d2f9bfSIgor M. Liplianin 	if (dev->fe)
118334d2f9bfSIgor M. Liplianin 		dvb_unregister_frontend(dev->fe);
1184a611d0caSIgor M. Liplianin 
1185a611d0caSIgor M. Liplianin 	dmx->disconnect_frontend(dmx);
118634d2f9bfSIgor M. Liplianin 	dmx->remove_frontend(dmx, &dev->mem_frontend);
118734d2f9bfSIgor M. Liplianin 	dmx->remove_frontend(dmx, &dev->hw_frontend);
118834d2f9bfSIgor M. Liplianin 	dvb_dmxdev_release(&dev->dmxdev);
1189a611d0caSIgor M. Liplianin 	dvb_dmx_release(dvbdemux);
1190a611d0caSIgor M. Liplianin 	dvb_unregister_adapter(dvb_adapter);
119134d2f9bfSIgor M. Liplianin 	i2c_del_adapter(&dev->i2c_adap);
1192a611d0caSIgor M. Liplianin 
119334d2f9bfSIgor M. Liplianin 	dm1105_hw_exit(dev);
119434d2f9bfSIgor M. Liplianin 	free_irq(pdev->irq, dev);
119534d2f9bfSIgor M. Liplianin 	pci_iounmap(pdev, dev->io_mem);
1196a611d0caSIgor M. Liplianin 	pci_release_regions(pdev);
1197a611d0caSIgor M. Liplianin 	pci_disable_device(pdev);
1198d8300df9SIgor M. Liplianin 	dm1105_devcount--;
119934d2f9bfSIgor M. Liplianin 	kfree(dev);
1200a611d0caSIgor M. Liplianin }
1201a611d0caSIgor M. Liplianin 
120282c055cdSArvind Yadav static const struct pci_device_id dm1105_id_table[] = {
1203a611d0caSIgor M. Liplianin 	{
1204a611d0caSIgor M. Liplianin 		.vendor = PCI_VENDOR_ID_TRIGEM,
1205a611d0caSIgor M. Liplianin 		.device = PCI_DEVICE_ID_DM1105,
1206a611d0caSIgor M. Liplianin 		.subvendor = PCI_ANY_ID,
1207d8300df9SIgor M. Liplianin 		.subdevice = PCI_ANY_ID,
1208a611d0caSIgor M. Liplianin 	}, {
1209519a4bdcSIgor M. Liplianin 		.vendor = PCI_VENDOR_ID_AXESS,
1210519a4bdcSIgor M. Liplianin 		.device = PCI_DEVICE_ID_DM05,
1211d8300df9SIgor M. Liplianin 		.subvendor = PCI_ANY_ID,
1212d8300df9SIgor M. Liplianin 		.subdevice = PCI_ANY_ID,
1213519a4bdcSIgor M. Liplianin 	}, {
1214a611d0caSIgor M. Liplianin 		/* empty */
1215a611d0caSIgor M. Liplianin 	},
1216a611d0caSIgor M. Liplianin };
1217a611d0caSIgor M. Liplianin 
1218a611d0caSIgor M. Liplianin MODULE_DEVICE_TABLE(pci, dm1105_id_table);
1219a611d0caSIgor M. Liplianin 
1220a611d0caSIgor M. Liplianin static struct pci_driver dm1105_driver = {
1221a611d0caSIgor M. Liplianin 	.name = DRIVER_NAME,
1222a611d0caSIgor M. Liplianin 	.id_table = dm1105_id_table,
1223a611d0caSIgor M. Liplianin 	.probe = dm1105_probe,
12244c62e976SGreg Kroah-Hartman 	.remove = dm1105_remove,
1225a611d0caSIgor M. Liplianin };
1226a611d0caSIgor M. Liplianin 
1227548006ceSLibo Chen module_pci_driver(dm1105_driver);
1228a611d0caSIgor M. Liplianin 
1229a611d0caSIgor M. Liplianin MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");
1230a611d0caSIgor M. Liplianin MODULE_DESCRIPTION("SDMC DM1105 DVB driver");
1231a611d0caSIgor M. Liplianin MODULE_LICENSE("GPL");
1232