18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * dm1105.c - driver for DVB cards based on SDMC DM1105 PCI chip
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/i2c.h>
98c2ecf20Sopenharmony_ci#include <linux/i2c-algo-bit.h>
108c2ecf20Sopenharmony_ci#include <linux/init.h>
118c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/pci.h>
158c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci#include <media/rc-core.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <media/demux.h>
208c2ecf20Sopenharmony_ci#include <media/dmxdev.h>
218c2ecf20Sopenharmony_ci#include <media/dvb_demux.h>
228c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h>
238c2ecf20Sopenharmony_ci#include <media/dvb_net.h>
248c2ecf20Sopenharmony_ci#include <media/dvbdev.h>
258c2ecf20Sopenharmony_ci#include "dvb-pll.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include "stv0299.h"
288c2ecf20Sopenharmony_ci#include "stv0288.h"
298c2ecf20Sopenharmony_ci#include "stb6000.h"
308c2ecf20Sopenharmony_ci#include "si21xx.h"
318c2ecf20Sopenharmony_ci#include "cx24116.h"
328c2ecf20Sopenharmony_ci#include "z0194a.h"
338c2ecf20Sopenharmony_ci#include "ts2020.h"
348c2ecf20Sopenharmony_ci#include "ds3000.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define MODULE_NAME "dm1105"
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define UNSET (-1U)
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define DM1105_BOARD_NOAUTO			UNSET
418c2ecf20Sopenharmony_ci#define DM1105_BOARD_UNKNOWN			0
428c2ecf20Sopenharmony_ci#define DM1105_BOARD_DVBWORLD_2002		1
438c2ecf20Sopenharmony_ci#define DM1105_BOARD_DVBWORLD_2004		2
448c2ecf20Sopenharmony_ci#define DM1105_BOARD_AXESS_DM05			3
458c2ecf20Sopenharmony_ci#define DM1105_BOARD_UNBRANDED_I2C_ON_GPIO	4
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/* ----------------------------------------------- */
488c2ecf20Sopenharmony_ci/*
498c2ecf20Sopenharmony_ci * PCI ID's
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_ci#ifndef PCI_VENDOR_ID_TRIGEM
528c2ecf20Sopenharmony_ci#define PCI_VENDOR_ID_TRIGEM	0x109f
538c2ecf20Sopenharmony_ci#endif
548c2ecf20Sopenharmony_ci#ifndef PCI_VENDOR_ID_AXESS
558c2ecf20Sopenharmony_ci#define PCI_VENDOR_ID_AXESS	0x195d
568c2ecf20Sopenharmony_ci#endif
578c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_DM1105
588c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_DM1105	0x036f
598c2ecf20Sopenharmony_ci#endif
608c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_DW2002
618c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_DW2002	0x2002
628c2ecf20Sopenharmony_ci#endif
638c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_DW2004
648c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_DW2004	0x2004
658c2ecf20Sopenharmony_ci#endif
668c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_DM05
678c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_DM05	0x1105
688c2ecf20Sopenharmony_ci#endif
698c2ecf20Sopenharmony_ci/* ----------------------------------------------- */
708c2ecf20Sopenharmony_ci/* sdmc dm1105 registers */
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/* TS Control */
738c2ecf20Sopenharmony_ci#define DM1105_TSCTR				0x00
748c2ecf20Sopenharmony_ci#define DM1105_DTALENTH				0x04
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci/* GPIO Interface */
778c2ecf20Sopenharmony_ci#define DM1105_GPIOVAL				0x08
788c2ecf20Sopenharmony_ci#define DM1105_GPIOCTR				0x0c
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci/* PID serial number */
818c2ecf20Sopenharmony_ci#define DM1105_PIDN				0x10
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci/* Odd-even secret key select */
848c2ecf20Sopenharmony_ci#define DM1105_CWSEL				0x14
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci/* Host Command Interface */
878c2ecf20Sopenharmony_ci#define DM1105_HOST_CTR				0x18
888c2ecf20Sopenharmony_ci#define DM1105_HOST_AD				0x1c
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci/* PCI Interface */
918c2ecf20Sopenharmony_ci#define DM1105_CR				0x30
928c2ecf20Sopenharmony_ci#define DM1105_RST				0x34
938c2ecf20Sopenharmony_ci#define DM1105_STADR				0x38
948c2ecf20Sopenharmony_ci#define DM1105_RLEN				0x3c
958c2ecf20Sopenharmony_ci#define DM1105_WRP				0x40
968c2ecf20Sopenharmony_ci#define DM1105_INTCNT				0x44
978c2ecf20Sopenharmony_ci#define DM1105_INTMAK				0x48
988c2ecf20Sopenharmony_ci#define DM1105_INTSTS				0x4c
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci/* CW Value */
1018c2ecf20Sopenharmony_ci#define DM1105_ODD				0x50
1028c2ecf20Sopenharmony_ci#define DM1105_EVEN				0x58
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci/* PID Value */
1058c2ecf20Sopenharmony_ci#define DM1105_PID				0x60
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci/* IR Control */
1088c2ecf20Sopenharmony_ci#define DM1105_IRCTR				0x64
1098c2ecf20Sopenharmony_ci#define DM1105_IRMODE				0x68
1108c2ecf20Sopenharmony_ci#define DM1105_SYSTEMCODE			0x6c
1118c2ecf20Sopenharmony_ci#define DM1105_IRCODE				0x70
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci/* Unknown Values */
1148c2ecf20Sopenharmony_ci#define DM1105_ENCRYPT				0x74
1158c2ecf20Sopenharmony_ci#define DM1105_VER				0x7c
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci/* I2C Interface */
1188c2ecf20Sopenharmony_ci#define DM1105_I2CCTR				0x80
1198c2ecf20Sopenharmony_ci#define DM1105_I2CSTS				0x81
1208c2ecf20Sopenharmony_ci#define DM1105_I2CDAT				0x82
1218c2ecf20Sopenharmony_ci#define DM1105_I2C_RA				0x83
1228c2ecf20Sopenharmony_ci/* ----------------------------------------------- */
1238c2ecf20Sopenharmony_ci/* Interrupt Mask Bits */
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci#define INTMAK_TSIRQM				0x01
1268c2ecf20Sopenharmony_ci#define INTMAK_HIRQM				0x04
1278c2ecf20Sopenharmony_ci#define INTMAK_IRM				0x08
1288c2ecf20Sopenharmony_ci#define INTMAK_ALLMASK				(INTMAK_TSIRQM | \
1298c2ecf20Sopenharmony_ci						INTMAK_HIRQM | \
1308c2ecf20Sopenharmony_ci						INTMAK_IRM)
1318c2ecf20Sopenharmony_ci#define INTMAK_NONEMASK				0x00
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci/* Interrupt Status Bits */
1348c2ecf20Sopenharmony_ci#define INTSTS_TSIRQ				0x01
1358c2ecf20Sopenharmony_ci#define INTSTS_HIRQ				0x04
1368c2ecf20Sopenharmony_ci#define INTSTS_IR				0x08
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci/* IR Control Bits */
1398c2ecf20Sopenharmony_ci#define DM1105_IR_EN				0x01
1408c2ecf20Sopenharmony_ci#define DM1105_SYS_CHK				0x02
1418c2ecf20Sopenharmony_ci#define DM1105_REP_FLG				0x08
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci/* EEPROM addr */
1448c2ecf20Sopenharmony_ci#define IIC_24C01_addr				0xa0
1458c2ecf20Sopenharmony_ci/* Max board count */
1468c2ecf20Sopenharmony_ci#define DM1105_MAX				0x04
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci#define DRIVER_NAME				"dm1105"
1498c2ecf20Sopenharmony_ci#define DM1105_I2C_GPIO_NAME			"dm1105-gpio"
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci#define DM1105_DMA_PACKETS			47
1528c2ecf20Sopenharmony_ci#define DM1105_DMA_PACKET_LENGTH		(128*4)
1538c2ecf20Sopenharmony_ci#define DM1105_DMA_BYTES			(128 * 4 * DM1105_DMA_PACKETS)
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci/*  */
1568c2ecf20Sopenharmony_ci#define GPIO08					(1 << 8)
1578c2ecf20Sopenharmony_ci#define GPIO13					(1 << 13)
1588c2ecf20Sopenharmony_ci#define GPIO14					(1 << 14)
1598c2ecf20Sopenharmony_ci#define GPIO15					(1 << 15)
1608c2ecf20Sopenharmony_ci#define GPIO16					(1 << 16)
1618c2ecf20Sopenharmony_ci#define GPIO17					(1 << 17)
1628c2ecf20Sopenharmony_ci#define GPIO_ALL				0x03ffff
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci/* GPIO's for LNB power control */
1658c2ecf20Sopenharmony_ci#define DM1105_LNB_MASK				(GPIO_ALL & ~(GPIO14 | GPIO13))
1668c2ecf20Sopenharmony_ci#define DM1105_LNB_OFF				GPIO17
1678c2ecf20Sopenharmony_ci#define DM1105_LNB_13V				(GPIO16 | GPIO08)
1688c2ecf20Sopenharmony_ci#define DM1105_LNB_18V				GPIO08
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci/* GPIO's for LNB power control for Axess DM05 */
1718c2ecf20Sopenharmony_ci#define DM05_LNB_MASK				(GPIO_ALL & ~(GPIO14 | GPIO13))
1728c2ecf20Sopenharmony_ci#define DM05_LNB_OFF				GPIO17/* actually 13v */
1738c2ecf20Sopenharmony_ci#define DM05_LNB_13V				GPIO17
1748c2ecf20Sopenharmony_ci#define DM05_LNB_18V				(GPIO17 | GPIO16)
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci/* GPIO's for LNB power control for unbranded with I2C on GPIO */
1778c2ecf20Sopenharmony_ci#define UNBR_LNB_MASK				(GPIO17 | GPIO16)
1788c2ecf20Sopenharmony_ci#define UNBR_LNB_OFF				0
1798c2ecf20Sopenharmony_ci#define UNBR_LNB_13V				GPIO17
1808c2ecf20Sopenharmony_ci#define UNBR_LNB_18V				(GPIO17 | GPIO16)
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic unsigned int card[]  = {[0 ... 3] = UNSET };
1838c2ecf20Sopenharmony_cimodule_param_array(card,  int, NULL, 0444);
1848c2ecf20Sopenharmony_ciMODULE_PARM_DESC(card, "card type");
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic int ir_debug;
1878c2ecf20Sopenharmony_cimodule_param(ir_debug, int, 0644);
1888c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic unsigned int dm1105_devcount;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistruct dm1105_board {
1958c2ecf20Sopenharmony_ci	char	*name;
1968c2ecf20Sopenharmony_ci	struct	{
1978c2ecf20Sopenharmony_ci		u32	mask, off, v13, v18;
1988c2ecf20Sopenharmony_ci	} lnb;
1998c2ecf20Sopenharmony_ci	u32	gpio_scl, gpio_sda;
2008c2ecf20Sopenharmony_ci};
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistruct dm1105_subid {
2038c2ecf20Sopenharmony_ci	u16     subvendor;
2048c2ecf20Sopenharmony_ci	u16     subdevice;
2058c2ecf20Sopenharmony_ci	u32     card;
2068c2ecf20Sopenharmony_ci};
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic const struct dm1105_board dm1105_boards[] = {
2098c2ecf20Sopenharmony_ci	[DM1105_BOARD_UNKNOWN] = {
2108c2ecf20Sopenharmony_ci		.name		= "UNKNOWN/GENERIC",
2118c2ecf20Sopenharmony_ci		.lnb = {
2128c2ecf20Sopenharmony_ci			.mask = DM1105_LNB_MASK,
2138c2ecf20Sopenharmony_ci			.off = DM1105_LNB_OFF,
2148c2ecf20Sopenharmony_ci			.v13 = DM1105_LNB_13V,
2158c2ecf20Sopenharmony_ci			.v18 = DM1105_LNB_18V,
2168c2ecf20Sopenharmony_ci		},
2178c2ecf20Sopenharmony_ci	},
2188c2ecf20Sopenharmony_ci	[DM1105_BOARD_DVBWORLD_2002] = {
2198c2ecf20Sopenharmony_ci		.name		= "DVBWorld PCI 2002",
2208c2ecf20Sopenharmony_ci		.lnb = {
2218c2ecf20Sopenharmony_ci			.mask = DM1105_LNB_MASK,
2228c2ecf20Sopenharmony_ci			.off = DM1105_LNB_OFF,
2238c2ecf20Sopenharmony_ci			.v13 = DM1105_LNB_13V,
2248c2ecf20Sopenharmony_ci			.v18 = DM1105_LNB_18V,
2258c2ecf20Sopenharmony_ci		},
2268c2ecf20Sopenharmony_ci	},
2278c2ecf20Sopenharmony_ci	[DM1105_BOARD_DVBWORLD_2004] = {
2288c2ecf20Sopenharmony_ci		.name		= "DVBWorld PCI 2004",
2298c2ecf20Sopenharmony_ci		.lnb = {
2308c2ecf20Sopenharmony_ci			.mask = DM1105_LNB_MASK,
2318c2ecf20Sopenharmony_ci			.off = DM1105_LNB_OFF,
2328c2ecf20Sopenharmony_ci			.v13 = DM1105_LNB_13V,
2338c2ecf20Sopenharmony_ci			.v18 = DM1105_LNB_18V,
2348c2ecf20Sopenharmony_ci		},
2358c2ecf20Sopenharmony_ci	},
2368c2ecf20Sopenharmony_ci	[DM1105_BOARD_AXESS_DM05] = {
2378c2ecf20Sopenharmony_ci		.name		= "Axess/EasyTv DM05",
2388c2ecf20Sopenharmony_ci		.lnb = {
2398c2ecf20Sopenharmony_ci			.mask = DM05_LNB_MASK,
2408c2ecf20Sopenharmony_ci			.off = DM05_LNB_OFF,
2418c2ecf20Sopenharmony_ci			.v13 = DM05_LNB_13V,
2428c2ecf20Sopenharmony_ci			.v18 = DM05_LNB_18V,
2438c2ecf20Sopenharmony_ci		},
2448c2ecf20Sopenharmony_ci	},
2458c2ecf20Sopenharmony_ci	[DM1105_BOARD_UNBRANDED_I2C_ON_GPIO] = {
2468c2ecf20Sopenharmony_ci		.name		= "Unbranded DM1105 with i2c on GPIOs",
2478c2ecf20Sopenharmony_ci		.lnb = {
2488c2ecf20Sopenharmony_ci			.mask = UNBR_LNB_MASK,
2498c2ecf20Sopenharmony_ci			.off = UNBR_LNB_OFF,
2508c2ecf20Sopenharmony_ci			.v13 = UNBR_LNB_13V,
2518c2ecf20Sopenharmony_ci			.v18 = UNBR_LNB_18V,
2528c2ecf20Sopenharmony_ci		},
2538c2ecf20Sopenharmony_ci		.gpio_scl	= GPIO14,
2548c2ecf20Sopenharmony_ci		.gpio_sda	= GPIO13,
2558c2ecf20Sopenharmony_ci	},
2568c2ecf20Sopenharmony_ci};
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic const struct dm1105_subid dm1105_subids[] = {
2598c2ecf20Sopenharmony_ci	{
2608c2ecf20Sopenharmony_ci		.subvendor = 0x0000,
2618c2ecf20Sopenharmony_ci		.subdevice = 0x2002,
2628c2ecf20Sopenharmony_ci		.card      = DM1105_BOARD_DVBWORLD_2002,
2638c2ecf20Sopenharmony_ci	}, {
2648c2ecf20Sopenharmony_ci		.subvendor = 0x0001,
2658c2ecf20Sopenharmony_ci		.subdevice = 0x2002,
2668c2ecf20Sopenharmony_ci		.card      = DM1105_BOARD_DVBWORLD_2002,
2678c2ecf20Sopenharmony_ci	}, {
2688c2ecf20Sopenharmony_ci		.subvendor = 0x0000,
2698c2ecf20Sopenharmony_ci		.subdevice = 0x2004,
2708c2ecf20Sopenharmony_ci		.card      = DM1105_BOARD_DVBWORLD_2004,
2718c2ecf20Sopenharmony_ci	}, {
2728c2ecf20Sopenharmony_ci		.subvendor = 0x0001,
2738c2ecf20Sopenharmony_ci		.subdevice = 0x2004,
2748c2ecf20Sopenharmony_ci		.card      = DM1105_BOARD_DVBWORLD_2004,
2758c2ecf20Sopenharmony_ci	}, {
2768c2ecf20Sopenharmony_ci		.subvendor = 0x195d,
2778c2ecf20Sopenharmony_ci		.subdevice = 0x1105,
2788c2ecf20Sopenharmony_ci		.card      = DM1105_BOARD_AXESS_DM05,
2798c2ecf20Sopenharmony_ci	},
2808c2ecf20Sopenharmony_ci};
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic void dm1105_card_list(struct pci_dev *pci)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	int i;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	if (0 == pci->subsystem_vendor &&
2878c2ecf20Sopenharmony_ci			0 == pci->subsystem_device) {
2888c2ecf20Sopenharmony_ci		printk(KERN_ERR
2898c2ecf20Sopenharmony_ci			"dm1105: Your board has no valid PCI Subsystem ID\n"
2908c2ecf20Sopenharmony_ci			"dm1105: and thus can't be autodetected\n"
2918c2ecf20Sopenharmony_ci			"dm1105: Please pass card=<n> insmod option to\n"
2928c2ecf20Sopenharmony_ci			"dm1105: workaround that.  Redirect complaints to\n"
2938c2ecf20Sopenharmony_ci			"dm1105: the vendor of the TV card.  Best regards,\n"
2948c2ecf20Sopenharmony_ci			"dm1105: -- tux\n");
2958c2ecf20Sopenharmony_ci	} else {
2968c2ecf20Sopenharmony_ci		printk(KERN_ERR
2978c2ecf20Sopenharmony_ci			"dm1105: Your board isn't known (yet) to the driver.\n"
2988c2ecf20Sopenharmony_ci			"dm1105: You can try to pick one of the existing\n"
2998c2ecf20Sopenharmony_ci			"dm1105: card configs via card=<n> insmod option.\n"
3008c2ecf20Sopenharmony_ci			"dm1105: Updating to the latest version might help\n"
3018c2ecf20Sopenharmony_ci			"dm1105: as well.\n");
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci	printk(KERN_ERR "Here is a list of valid choices for the card=<n> insmod option:\n");
3048c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dm1105_boards); i++)
3058c2ecf20Sopenharmony_ci		printk(KERN_ERR "dm1105:    card=%d -> %s\n",
3068c2ecf20Sopenharmony_ci				i, dm1105_boards[i].name);
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci/* infrared remote control */
3108c2ecf20Sopenharmony_cistruct infrared {
3118c2ecf20Sopenharmony_ci	struct rc_dev		*dev;
3128c2ecf20Sopenharmony_ci	char			input_phys[32];
3138c2ecf20Sopenharmony_ci	struct work_struct	work;
3148c2ecf20Sopenharmony_ci	u32			ir_command;
3158c2ecf20Sopenharmony_ci};
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistruct dm1105_dev {
3188c2ecf20Sopenharmony_ci	/* pci */
3198c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
3208c2ecf20Sopenharmony_ci	u8 __iomem *io_mem;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	/* ir */
3238c2ecf20Sopenharmony_ci	struct infrared ir;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	/* dvb */
3268c2ecf20Sopenharmony_ci	struct dmx_frontend hw_frontend;
3278c2ecf20Sopenharmony_ci	struct dmx_frontend mem_frontend;
3288c2ecf20Sopenharmony_ci	struct dmxdev dmxdev;
3298c2ecf20Sopenharmony_ci	struct dvb_adapter dvb_adapter;
3308c2ecf20Sopenharmony_ci	struct dvb_demux demux;
3318c2ecf20Sopenharmony_ci	struct dvb_frontend *fe;
3328c2ecf20Sopenharmony_ci	struct dvb_net dvbnet;
3338c2ecf20Sopenharmony_ci	unsigned int full_ts_users;
3348c2ecf20Sopenharmony_ci	unsigned int boardnr;
3358c2ecf20Sopenharmony_ci	int nr;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	/* i2c */
3388c2ecf20Sopenharmony_ci	struct i2c_adapter i2c_adap;
3398c2ecf20Sopenharmony_ci	struct i2c_adapter i2c_bb_adap;
3408c2ecf20Sopenharmony_ci	struct i2c_algo_bit_data i2c_bit;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	/* irq */
3438c2ecf20Sopenharmony_ci	struct work_struct work;
3448c2ecf20Sopenharmony_ci	struct workqueue_struct *wq;
3458c2ecf20Sopenharmony_ci	char wqn[16];
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	/* dma */
3488c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
3498c2ecf20Sopenharmony_ci	unsigned char *ts_buf;
3508c2ecf20Sopenharmony_ci	u32 wrp;
3518c2ecf20Sopenharmony_ci	u32 nextwrp;
3528c2ecf20Sopenharmony_ci	u32 buffer_size;
3538c2ecf20Sopenharmony_ci	unsigned int	PacketErrorCount;
3548c2ecf20Sopenharmony_ci	unsigned int dmarst;
3558c2ecf20Sopenharmony_ci	spinlock_t lock;
3568c2ecf20Sopenharmony_ci};
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci#define dm_io_mem(reg)	((unsigned long)(&dev->io_mem[reg]))
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci#define dm_readb(reg)		inb(dm_io_mem(reg))
3618c2ecf20Sopenharmony_ci#define dm_writeb(reg, value)	outb((value), (dm_io_mem(reg)))
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci#define dm_readw(reg)		inw(dm_io_mem(reg))
3648c2ecf20Sopenharmony_ci#define dm_writew(reg, value)	outw((value), (dm_io_mem(reg)))
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci#define dm_readl(reg)		inl(dm_io_mem(reg))
3678c2ecf20Sopenharmony_ci#define dm_writel(reg, value)	outl((value), (dm_io_mem(reg)))
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci#define dm_andorl(reg, mask, value) \
3708c2ecf20Sopenharmony_ci	outl((inl(dm_io_mem(reg)) & ~(mask)) |\
3718c2ecf20Sopenharmony_ci		((value) & (mask)), (dm_io_mem(reg)))
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci#define dm_setl(reg, bit)	dm_andorl((reg), (bit), (bit))
3748c2ecf20Sopenharmony_ci#define dm_clearl(reg, bit)	dm_andorl((reg), (bit), 0)
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci/* The chip has 18 GPIOs. In HOST mode GPIO's used as 15 bit address lines,
3778c2ecf20Sopenharmony_ci so we can use only 3 GPIO's from GPIO15 to GPIO17.
3788c2ecf20Sopenharmony_ci Here I don't check whether HOST is enebled as it is not implemented yet.
3798c2ecf20Sopenharmony_ci */
3808c2ecf20Sopenharmony_cistatic void dm1105_gpio_set(struct dm1105_dev *dev, u32 mask)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	if (mask & 0xfffc0000)
3838c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	if (mask & 0x0003ffff)
3868c2ecf20Sopenharmony_ci		dm_setl(DM1105_GPIOVAL, mask & 0x0003ffff);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cistatic void dm1105_gpio_clear(struct dm1105_dev *dev, u32 mask)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	if (mask & 0xfffc0000)
3938c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (mask & 0x0003ffff)
3968c2ecf20Sopenharmony_ci		dm_clearl(DM1105_GPIOVAL, mask & 0x0003ffff);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic void dm1105_gpio_andor(struct dm1105_dev *dev, u32 mask, u32 val)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	if (mask & 0xfffc0000)
4038c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	if (mask & 0x0003ffff)
4068c2ecf20Sopenharmony_ci		dm_andorl(DM1105_GPIOVAL, mask & 0x0003ffff, val);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_cistatic u32 dm1105_gpio_get(struct dm1105_dev *dev, u32 mask)
4118c2ecf20Sopenharmony_ci{
4128c2ecf20Sopenharmony_ci	if (mask & 0xfffc0000)
4138c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	if (mask & 0x0003ffff)
4168c2ecf20Sopenharmony_ci		return dm_readl(DM1105_GPIOVAL) & mask & 0x0003ffff;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	return 0;
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic void dm1105_gpio_enable(struct dm1105_dev *dev, u32 mask, int asoutput)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	if (mask & 0xfffc0000)
4248c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	if ((mask & 0x0003ffff) && asoutput)
4278c2ecf20Sopenharmony_ci		dm_clearl(DM1105_GPIOCTR, mask & 0x0003ffff);
4288c2ecf20Sopenharmony_ci	else if ((mask & 0x0003ffff) && !asoutput)
4298c2ecf20Sopenharmony_ci		dm_setl(DM1105_GPIOCTR, mask & 0x0003ffff);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cistatic void dm1105_setline(struct dm1105_dev *dev, u32 line, int state)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	if (state)
4368c2ecf20Sopenharmony_ci		dm1105_gpio_enable(dev, line, 0);
4378c2ecf20Sopenharmony_ci	else {
4388c2ecf20Sopenharmony_ci		dm1105_gpio_enable(dev, line, 1);
4398c2ecf20Sopenharmony_ci		dm1105_gpio_clear(dev, line);
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic void dm1105_setsda(void *data, int state)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	struct dm1105_dev *dev = data;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_sda, state);
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic void dm1105_setscl(void *data, int state)
4518c2ecf20Sopenharmony_ci{
4528c2ecf20Sopenharmony_ci	struct dm1105_dev *dev = data;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_scl, state);
4558c2ecf20Sopenharmony_ci}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_cistatic int dm1105_getsda(void *data)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	struct dm1105_dev *dev = data;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_sda)
4628c2ecf20Sopenharmony_ci									? 1 : 0;
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_cistatic int dm1105_getscl(void *data)
4668c2ecf20Sopenharmony_ci{
4678c2ecf20Sopenharmony_ci	struct dm1105_dev *dev = data;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_scl)
4708c2ecf20Sopenharmony_ci									? 1 : 0;
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_cistatic int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
4748c2ecf20Sopenharmony_ci			    struct i2c_msg *msgs, int num)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	struct dm1105_dev *dev ;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	int addr, rc, i, j, k, len, byte, data;
4798c2ecf20Sopenharmony_ci	u8 status;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	dev = i2c_adap->algo_data;
4828c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
4838c2ecf20Sopenharmony_ci		dm_writeb(DM1105_I2CCTR, 0x00);
4848c2ecf20Sopenharmony_ci		if (msgs[i].flags & I2C_M_RD) {
4858c2ecf20Sopenharmony_ci			/* read bytes */
4868c2ecf20Sopenharmony_ci			addr  = msgs[i].addr << 1;
4878c2ecf20Sopenharmony_ci			addr |= 1;
4888c2ecf20Sopenharmony_ci			dm_writeb(DM1105_I2CDAT, addr);
4898c2ecf20Sopenharmony_ci			for (byte = 0; byte < msgs[i].len; byte++)
4908c2ecf20Sopenharmony_ci				dm_writeb(DM1105_I2CDAT + byte + 1, 0);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci			dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len);
4938c2ecf20Sopenharmony_ci			for (j = 0; j < 55; j++) {
4948c2ecf20Sopenharmony_ci				mdelay(10);
4958c2ecf20Sopenharmony_ci				status = dm_readb(DM1105_I2CSTS);
4968c2ecf20Sopenharmony_ci				if ((status & 0xc0) == 0x40)
4978c2ecf20Sopenharmony_ci					break;
4988c2ecf20Sopenharmony_ci			}
4998c2ecf20Sopenharmony_ci			if (j >= 55)
5008c2ecf20Sopenharmony_ci				return -1;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci			for (byte = 0; byte < msgs[i].len; byte++) {
5038c2ecf20Sopenharmony_ci				rc = dm_readb(DM1105_I2CDAT + byte + 1);
5048c2ecf20Sopenharmony_ci				if (rc < 0)
5058c2ecf20Sopenharmony_ci					goto err;
5068c2ecf20Sopenharmony_ci				msgs[i].buf[byte] = rc;
5078c2ecf20Sopenharmony_ci			}
5088c2ecf20Sopenharmony_ci		} else if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) {
5098c2ecf20Sopenharmony_ci			/* prepared for cx24116 firmware */
5108c2ecf20Sopenharmony_ci			/* Write in small blocks */
5118c2ecf20Sopenharmony_ci			len = msgs[i].len - 1;
5128c2ecf20Sopenharmony_ci			k = 1;
5138c2ecf20Sopenharmony_ci			do {
5148c2ecf20Sopenharmony_ci				dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1);
5158c2ecf20Sopenharmony_ci				dm_writeb(DM1105_I2CDAT + 1, 0xf7);
5168c2ecf20Sopenharmony_ci				for (byte = 0; byte < (len > 48 ? 48 : len); byte++) {
5178c2ecf20Sopenharmony_ci					data = msgs[i].buf[k + byte];
5188c2ecf20Sopenharmony_ci					dm_writeb(DM1105_I2CDAT + byte + 2, data);
5198c2ecf20Sopenharmony_ci				}
5208c2ecf20Sopenharmony_ci				dm_writeb(DM1105_I2CCTR, 0x82 + (len > 48 ? 48 : len));
5218c2ecf20Sopenharmony_ci				for (j = 0; j < 25; j++) {
5228c2ecf20Sopenharmony_ci					mdelay(10);
5238c2ecf20Sopenharmony_ci					status = dm_readb(DM1105_I2CSTS);
5248c2ecf20Sopenharmony_ci					if ((status & 0xc0) == 0x40)
5258c2ecf20Sopenharmony_ci						break;
5268c2ecf20Sopenharmony_ci				}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci				if (j >= 25)
5298c2ecf20Sopenharmony_ci					return -1;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci				k += 48;
5328c2ecf20Sopenharmony_ci				len -= 48;
5338c2ecf20Sopenharmony_ci			} while (len > 0);
5348c2ecf20Sopenharmony_ci		} else {
5358c2ecf20Sopenharmony_ci			/* write bytes */
5368c2ecf20Sopenharmony_ci			dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1);
5378c2ecf20Sopenharmony_ci			for (byte = 0; byte < msgs[i].len; byte++) {
5388c2ecf20Sopenharmony_ci				data = msgs[i].buf[byte];
5398c2ecf20Sopenharmony_ci				dm_writeb(DM1105_I2CDAT + byte + 1, data);
5408c2ecf20Sopenharmony_ci			}
5418c2ecf20Sopenharmony_ci			dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len);
5428c2ecf20Sopenharmony_ci			for (j = 0; j < 25; j++) {
5438c2ecf20Sopenharmony_ci				mdelay(10);
5448c2ecf20Sopenharmony_ci				status = dm_readb(DM1105_I2CSTS);
5458c2ecf20Sopenharmony_ci				if ((status & 0xc0) == 0x40)
5468c2ecf20Sopenharmony_ci					break;
5478c2ecf20Sopenharmony_ci			}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci			if (j >= 25)
5508c2ecf20Sopenharmony_ci				return -1;
5518c2ecf20Sopenharmony_ci		}
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci	return num;
5548c2ecf20Sopenharmony_ci err:
5558c2ecf20Sopenharmony_ci	return rc;
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_cistatic u32 functionality(struct i2c_adapter *adap)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	return I2C_FUNC_I2C;
5618c2ecf20Sopenharmony_ci}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_cistatic const struct i2c_algorithm dm1105_algo = {
5648c2ecf20Sopenharmony_ci	.master_xfer   = dm1105_i2c_xfer,
5658c2ecf20Sopenharmony_ci	.functionality = functionality,
5668c2ecf20Sopenharmony_ci};
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cistatic inline struct dm1105_dev *feed_to_dm1105_dev(struct dvb_demux_feed *feed)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	return container_of(feed->demux, struct dm1105_dev, demux);
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_cistatic inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe)
5748c2ecf20Sopenharmony_ci{
5758c2ecf20Sopenharmony_ci	return container_of(fe->dvb, struct dm1105_dev, dvb_adapter);
5768c2ecf20Sopenharmony_ci}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_cistatic int dm1105_set_voltage(struct dvb_frontend *fe,
5798c2ecf20Sopenharmony_ci			      enum fe_sec_voltage voltage)
5808c2ecf20Sopenharmony_ci{
5818c2ecf20Sopenharmony_ci	struct dm1105_dev *dev = frontend_to_dm1105_dev(fe);
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	dm1105_gpio_enable(dev, dm1105_boards[dev->boardnr].lnb.mask, 1);
5848c2ecf20Sopenharmony_ci	if (voltage == SEC_VOLTAGE_18)
5858c2ecf20Sopenharmony_ci		dm1105_gpio_andor(dev,
5868c2ecf20Sopenharmony_ci				dm1105_boards[dev->boardnr].lnb.mask,
5878c2ecf20Sopenharmony_ci				dm1105_boards[dev->boardnr].lnb.v18);
5888c2ecf20Sopenharmony_ci	else if (voltage == SEC_VOLTAGE_13)
5898c2ecf20Sopenharmony_ci		dm1105_gpio_andor(dev,
5908c2ecf20Sopenharmony_ci				dm1105_boards[dev->boardnr].lnb.mask,
5918c2ecf20Sopenharmony_ci				dm1105_boards[dev->boardnr].lnb.v13);
5928c2ecf20Sopenharmony_ci	else
5938c2ecf20Sopenharmony_ci		dm1105_gpio_andor(dev,
5948c2ecf20Sopenharmony_ci				dm1105_boards[dev->boardnr].lnb.mask,
5958c2ecf20Sopenharmony_ci				dm1105_boards[dev->boardnr].lnb.off);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	return 0;
5988c2ecf20Sopenharmony_ci}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_cistatic void dm1105_set_dma_addr(struct dm1105_dev *dev)
6018c2ecf20Sopenharmony_ci{
6028c2ecf20Sopenharmony_ci	dm_writel(DM1105_STADR, (__force u32)cpu_to_le32(dev->dma_addr));
6038c2ecf20Sopenharmony_ci}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_cistatic int dm1105_dma_map(struct dm1105_dev *dev)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	dev->ts_buf = pci_alloc_consistent(dev->pdev,
6088c2ecf20Sopenharmony_ci					6 * DM1105_DMA_BYTES,
6098c2ecf20Sopenharmony_ci					&dev->dma_addr);
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	return !dev->ts_buf;
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_cistatic void dm1105_dma_unmap(struct dm1105_dev *dev)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	pci_free_consistent(dev->pdev,
6178c2ecf20Sopenharmony_ci			6 * DM1105_DMA_BYTES,
6188c2ecf20Sopenharmony_ci			dev->ts_buf,
6198c2ecf20Sopenharmony_ci			dev->dma_addr);
6208c2ecf20Sopenharmony_ci}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_cistatic void dm1105_enable_irqs(struct dm1105_dev *dev)
6238c2ecf20Sopenharmony_ci{
6248c2ecf20Sopenharmony_ci	dm_writeb(DM1105_INTMAK, INTMAK_ALLMASK);
6258c2ecf20Sopenharmony_ci	dm_writeb(DM1105_CR, 1);
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_cistatic void dm1105_disable_irqs(struct dm1105_dev *dev)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	dm_writeb(DM1105_INTMAK, INTMAK_IRM);
6318c2ecf20Sopenharmony_ci	dm_writeb(DM1105_CR, 0);
6328c2ecf20Sopenharmony_ci}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_cistatic int dm1105_start_feed(struct dvb_demux_feed *f)
6358c2ecf20Sopenharmony_ci{
6368c2ecf20Sopenharmony_ci	struct dm1105_dev *dev = feed_to_dm1105_dev(f);
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	if (dev->full_ts_users++ == 0)
6398c2ecf20Sopenharmony_ci		dm1105_enable_irqs(dev);
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	return 0;
6428c2ecf20Sopenharmony_ci}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_cistatic int dm1105_stop_feed(struct dvb_demux_feed *f)
6458c2ecf20Sopenharmony_ci{
6468c2ecf20Sopenharmony_ci	struct dm1105_dev *dev = feed_to_dm1105_dev(f);
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	if (--dev->full_ts_users == 0)
6498c2ecf20Sopenharmony_ci		dm1105_disable_irqs(dev);
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	return 0;
6528c2ecf20Sopenharmony_ci}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci/* ir work handler */
6558c2ecf20Sopenharmony_cistatic void dm1105_emit_key(struct work_struct *work)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	struct infrared *ir = container_of(work, struct infrared, work);
6588c2ecf20Sopenharmony_ci	u32 ircom = ir->ir_command;
6598c2ecf20Sopenharmony_ci	u8 data;
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	if (ir_debug)
6628c2ecf20Sopenharmony_ci		printk(KERN_INFO "%s: received byte 0x%04x\n", __func__, ircom);
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	data = (ircom >> 8) & 0x7f;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	/* FIXME: UNKNOWN because we don't generate a full NEC scancode (yet?) */
6678c2ecf20Sopenharmony_ci	rc_keydown(ir->dev, RC_PROTO_UNKNOWN, data, 0);
6688c2ecf20Sopenharmony_ci}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci/* work handler */
6718c2ecf20Sopenharmony_cistatic void dm1105_dmx_buffer(struct work_struct *work)
6728c2ecf20Sopenharmony_ci{
6738c2ecf20Sopenharmony_ci	struct dm1105_dev *dev = container_of(work, struct dm1105_dev, work);
6748c2ecf20Sopenharmony_ci	unsigned int nbpackets;
6758c2ecf20Sopenharmony_ci	u32 oldwrp = dev->wrp;
6768c2ecf20Sopenharmony_ci	u32 nextwrp = dev->nextwrp;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	if (!((dev->ts_buf[oldwrp] == 0x47) &&
6798c2ecf20Sopenharmony_ci			(dev->ts_buf[oldwrp + 188] == 0x47) &&
6808c2ecf20Sopenharmony_ci			(dev->ts_buf[oldwrp + 188 * 2] == 0x47))) {
6818c2ecf20Sopenharmony_ci		dev->PacketErrorCount++;
6828c2ecf20Sopenharmony_ci		/* bad packet found */
6838c2ecf20Sopenharmony_ci		if ((dev->PacketErrorCount >= 2) &&
6848c2ecf20Sopenharmony_ci				(dev->dmarst == 0)) {
6858c2ecf20Sopenharmony_ci			dm_writeb(DM1105_RST, 1);
6868c2ecf20Sopenharmony_ci			dev->wrp = 0;
6878c2ecf20Sopenharmony_ci			dev->PacketErrorCount = 0;
6888c2ecf20Sopenharmony_ci			dev->dmarst = 0;
6898c2ecf20Sopenharmony_ci			return;
6908c2ecf20Sopenharmony_ci		}
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	if (nextwrp < oldwrp) {
6948c2ecf20Sopenharmony_ci		memcpy(dev->ts_buf + dev->buffer_size, dev->ts_buf, nextwrp);
6958c2ecf20Sopenharmony_ci		nbpackets = ((dev->buffer_size - oldwrp) + nextwrp) / 188;
6968c2ecf20Sopenharmony_ci	} else
6978c2ecf20Sopenharmony_ci		nbpackets = (nextwrp - oldwrp) / 188;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	dev->wrp = nextwrp;
7008c2ecf20Sopenharmony_ci	dvb_dmx_swfilter_packets(&dev->demux, &dev->ts_buf[oldwrp], nbpackets);
7018c2ecf20Sopenharmony_ci}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_cistatic irqreturn_t dm1105_irq(int irq, void *dev_id)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	struct dm1105_dev *dev = dev_id;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	/* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */
7088c2ecf20Sopenharmony_ci	unsigned int intsts = dm_readb(DM1105_INTSTS);
7098c2ecf20Sopenharmony_ci	dm_writeb(DM1105_INTSTS, intsts);
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	switch (intsts) {
7128c2ecf20Sopenharmony_ci	case INTSTS_TSIRQ:
7138c2ecf20Sopenharmony_ci	case (INTSTS_TSIRQ | INTSTS_IR):
7148c2ecf20Sopenharmony_ci		dev->nextwrp = dm_readl(DM1105_WRP) - dm_readl(DM1105_STADR);
7158c2ecf20Sopenharmony_ci		queue_work(dev->wq, &dev->work);
7168c2ecf20Sopenharmony_ci		break;
7178c2ecf20Sopenharmony_ci	case INTSTS_IR:
7188c2ecf20Sopenharmony_ci		dev->ir.ir_command = dm_readl(DM1105_IRCODE);
7198c2ecf20Sopenharmony_ci		schedule_work(&dev->ir.work);
7208c2ecf20Sopenharmony_ci		break;
7218c2ecf20Sopenharmony_ci	}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
7248c2ecf20Sopenharmony_ci}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_cistatic int dm1105_ir_init(struct dm1105_dev *dm1105)
7278c2ecf20Sopenharmony_ci{
7288c2ecf20Sopenharmony_ci	struct rc_dev *dev;
7298c2ecf20Sopenharmony_ci	int err = -ENOMEM;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	dev = rc_allocate_device(RC_DRIVER_SCANCODE);
7328c2ecf20Sopenharmony_ci	if (!dev)
7338c2ecf20Sopenharmony_ci		return -ENOMEM;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys),
7368c2ecf20Sopenharmony_ci		"pci-%s/ir0", pci_name(dm1105->pdev));
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	dev->driver_name = MODULE_NAME;
7398c2ecf20Sopenharmony_ci	dev->map_name = RC_MAP_DM1105_NEC;
7408c2ecf20Sopenharmony_ci	dev->device_name = "DVB on-card IR receiver";
7418c2ecf20Sopenharmony_ci	dev->input_phys = dm1105->ir.input_phys;
7428c2ecf20Sopenharmony_ci	dev->input_id.bustype = BUS_PCI;
7438c2ecf20Sopenharmony_ci	dev->input_id.version = 1;
7448c2ecf20Sopenharmony_ci	if (dm1105->pdev->subsystem_vendor) {
7458c2ecf20Sopenharmony_ci		dev->input_id.vendor = dm1105->pdev->subsystem_vendor;
7468c2ecf20Sopenharmony_ci		dev->input_id.product = dm1105->pdev->subsystem_device;
7478c2ecf20Sopenharmony_ci	} else {
7488c2ecf20Sopenharmony_ci		dev->input_id.vendor = dm1105->pdev->vendor;
7498c2ecf20Sopenharmony_ci		dev->input_id.product = dm1105->pdev->device;
7508c2ecf20Sopenharmony_ci	}
7518c2ecf20Sopenharmony_ci	dev->dev.parent = &dm1105->pdev->dev;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	INIT_WORK(&dm1105->ir.work, dm1105_emit_key);
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	err = rc_register_device(dev);
7568c2ecf20Sopenharmony_ci	if (err < 0) {
7578c2ecf20Sopenharmony_ci		rc_free_device(dev);
7588c2ecf20Sopenharmony_ci		return err;
7598c2ecf20Sopenharmony_ci	}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	dm1105->ir.dev = dev;
7628c2ecf20Sopenharmony_ci	return 0;
7638c2ecf20Sopenharmony_ci}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_cistatic void dm1105_ir_exit(struct dm1105_dev *dm1105)
7668c2ecf20Sopenharmony_ci{
7678c2ecf20Sopenharmony_ci	rc_unregister_device(dm1105->ir.dev);
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cistatic int dm1105_hw_init(struct dm1105_dev *dev)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	dm1105_disable_irqs(dev);
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	dm_writeb(DM1105_HOST_CTR, 0);
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	/*DATALEN 188,*/
7778c2ecf20Sopenharmony_ci	dm_writeb(DM1105_DTALENTH, 188);
7788c2ecf20Sopenharmony_ci	/*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/
7798c2ecf20Sopenharmony_ci	dm_writew(DM1105_TSCTR, 0xc10a);
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	/* map DMA and set address */
7828c2ecf20Sopenharmony_ci	dm1105_dma_map(dev);
7838c2ecf20Sopenharmony_ci	dm1105_set_dma_addr(dev);
7848c2ecf20Sopenharmony_ci	/* big buffer */
7858c2ecf20Sopenharmony_ci	dm_writel(DM1105_RLEN, 5 * DM1105_DMA_BYTES);
7868c2ecf20Sopenharmony_ci	dm_writeb(DM1105_INTCNT, 47);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	/* IR NEC mode enable */
7898c2ecf20Sopenharmony_ci	dm_writeb(DM1105_IRCTR, (DM1105_IR_EN | DM1105_SYS_CHK));
7908c2ecf20Sopenharmony_ci	dm_writeb(DM1105_IRMODE, 0);
7918c2ecf20Sopenharmony_ci	dm_writew(DM1105_SYSTEMCODE, 0);
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	return 0;
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic void dm1105_hw_exit(struct dm1105_dev *dev)
7978c2ecf20Sopenharmony_ci{
7988c2ecf20Sopenharmony_ci	dm1105_disable_irqs(dev);
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	/* IR disable */
8018c2ecf20Sopenharmony_ci	dm_writeb(DM1105_IRCTR, 0);
8028c2ecf20Sopenharmony_ci	dm_writeb(DM1105_INTMAK, INTMAK_NONEMASK);
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	dm1105_dma_unmap(dev);
8058c2ecf20Sopenharmony_ci}
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_cistatic const struct stv0299_config sharp_z0194a_config = {
8088c2ecf20Sopenharmony_ci	.demod_address = 0x68,
8098c2ecf20Sopenharmony_ci	.inittab = sharp_z0194a_inittab,
8108c2ecf20Sopenharmony_ci	.mclk = 88000000UL,
8118c2ecf20Sopenharmony_ci	.invert = 1,
8128c2ecf20Sopenharmony_ci	.skip_reinit = 0,
8138c2ecf20Sopenharmony_ci	.lock_output = STV0299_LOCKOUTPUT_1,
8148c2ecf20Sopenharmony_ci	.volt13_op0_op1 = STV0299_VOLT13_OP1,
8158c2ecf20Sopenharmony_ci	.min_delay_ms = 100,
8168c2ecf20Sopenharmony_ci	.set_symbol_rate = sharp_z0194a_set_symbol_rate,
8178c2ecf20Sopenharmony_ci};
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_cistatic struct stv0288_config earda_config = {
8208c2ecf20Sopenharmony_ci	.demod_address = 0x68,
8218c2ecf20Sopenharmony_ci	.min_delay_ms = 100,
8228c2ecf20Sopenharmony_ci};
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_cistatic struct si21xx_config serit_config = {
8258c2ecf20Sopenharmony_ci	.demod_address = 0x68,
8268c2ecf20Sopenharmony_ci	.min_delay_ms = 100,
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci};
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_cistatic struct cx24116_config serit_sp2633_config = {
8318c2ecf20Sopenharmony_ci	.demod_address = 0x55,
8328c2ecf20Sopenharmony_ci};
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_cistatic struct ds3000_config dvbworld_ds3000_config = {
8358c2ecf20Sopenharmony_ci	.demod_address = 0x68,
8368c2ecf20Sopenharmony_ci};
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_cistatic struct ts2020_config dvbworld_ts2020_config  = {
8398c2ecf20Sopenharmony_ci	.tuner_address = 0x60,
8408c2ecf20Sopenharmony_ci	.clk_out_div = 1,
8418c2ecf20Sopenharmony_ci};
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_cistatic int frontend_init(struct dm1105_dev *dev)
8448c2ecf20Sopenharmony_ci{
8458c2ecf20Sopenharmony_ci	int ret;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	switch (dev->boardnr) {
8488c2ecf20Sopenharmony_ci	case DM1105_BOARD_UNBRANDED_I2C_ON_GPIO:
8498c2ecf20Sopenharmony_ci		dm1105_gpio_enable(dev, GPIO15, 1);
8508c2ecf20Sopenharmony_ci		dm1105_gpio_clear(dev, GPIO15);
8518c2ecf20Sopenharmony_ci		msleep(100);
8528c2ecf20Sopenharmony_ci		dm1105_gpio_set(dev, GPIO15);
8538c2ecf20Sopenharmony_ci		msleep(200);
8548c2ecf20Sopenharmony_ci		dev->fe = dvb_attach(
8558c2ecf20Sopenharmony_ci			stv0299_attach, &sharp_z0194a_config,
8568c2ecf20Sopenharmony_ci			&dev->i2c_bb_adap);
8578c2ecf20Sopenharmony_ci		if (dev->fe) {
8588c2ecf20Sopenharmony_ci			dev->fe->ops.set_voltage = dm1105_set_voltage;
8598c2ecf20Sopenharmony_ci			dvb_attach(dvb_pll_attach, dev->fe, 0x60,
8608c2ecf20Sopenharmony_ci					&dev->i2c_bb_adap, DVB_PLL_OPERA1);
8618c2ecf20Sopenharmony_ci			break;
8628c2ecf20Sopenharmony_ci		}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci		dev->fe = dvb_attach(
8658c2ecf20Sopenharmony_ci			stv0288_attach, &earda_config,
8668c2ecf20Sopenharmony_ci			&dev->i2c_bb_adap);
8678c2ecf20Sopenharmony_ci		if (dev->fe) {
8688c2ecf20Sopenharmony_ci			dev->fe->ops.set_voltage = dm1105_set_voltage;
8698c2ecf20Sopenharmony_ci			dvb_attach(stb6000_attach, dev->fe, 0x61,
8708c2ecf20Sopenharmony_ci					&dev->i2c_bb_adap);
8718c2ecf20Sopenharmony_ci			break;
8728c2ecf20Sopenharmony_ci		}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci		dev->fe = dvb_attach(
8758c2ecf20Sopenharmony_ci			si21xx_attach, &serit_config,
8768c2ecf20Sopenharmony_ci			&dev->i2c_bb_adap);
8778c2ecf20Sopenharmony_ci		if (dev->fe)
8788c2ecf20Sopenharmony_ci			dev->fe->ops.set_voltage = dm1105_set_voltage;
8798c2ecf20Sopenharmony_ci		break;
8808c2ecf20Sopenharmony_ci	case DM1105_BOARD_DVBWORLD_2004:
8818c2ecf20Sopenharmony_ci		dev->fe = dvb_attach(
8828c2ecf20Sopenharmony_ci			cx24116_attach, &serit_sp2633_config,
8838c2ecf20Sopenharmony_ci			&dev->i2c_adap);
8848c2ecf20Sopenharmony_ci		if (dev->fe) {
8858c2ecf20Sopenharmony_ci			dev->fe->ops.set_voltage = dm1105_set_voltage;
8868c2ecf20Sopenharmony_ci			break;
8878c2ecf20Sopenharmony_ci		}
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci		dev->fe = dvb_attach(
8908c2ecf20Sopenharmony_ci			ds3000_attach, &dvbworld_ds3000_config,
8918c2ecf20Sopenharmony_ci			&dev->i2c_adap);
8928c2ecf20Sopenharmony_ci		if (dev->fe) {
8938c2ecf20Sopenharmony_ci			dvb_attach(ts2020_attach, dev->fe,
8948c2ecf20Sopenharmony_ci				&dvbworld_ts2020_config, &dev->i2c_adap);
8958c2ecf20Sopenharmony_ci			dev->fe->ops.set_voltage = dm1105_set_voltage;
8968c2ecf20Sopenharmony_ci		}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci		break;
8998c2ecf20Sopenharmony_ci	case DM1105_BOARD_DVBWORLD_2002:
9008c2ecf20Sopenharmony_ci	case DM1105_BOARD_AXESS_DM05:
9018c2ecf20Sopenharmony_ci	default:
9028c2ecf20Sopenharmony_ci		dev->fe = dvb_attach(
9038c2ecf20Sopenharmony_ci			stv0299_attach, &sharp_z0194a_config,
9048c2ecf20Sopenharmony_ci			&dev->i2c_adap);
9058c2ecf20Sopenharmony_ci		if (dev->fe) {
9068c2ecf20Sopenharmony_ci			dev->fe->ops.set_voltage = dm1105_set_voltage;
9078c2ecf20Sopenharmony_ci			dvb_attach(dvb_pll_attach, dev->fe, 0x60,
9088c2ecf20Sopenharmony_ci					&dev->i2c_adap, DVB_PLL_OPERA1);
9098c2ecf20Sopenharmony_ci			break;
9108c2ecf20Sopenharmony_ci		}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci		dev->fe = dvb_attach(
9138c2ecf20Sopenharmony_ci			stv0288_attach, &earda_config,
9148c2ecf20Sopenharmony_ci			&dev->i2c_adap);
9158c2ecf20Sopenharmony_ci		if (dev->fe) {
9168c2ecf20Sopenharmony_ci			dev->fe->ops.set_voltage = dm1105_set_voltage;
9178c2ecf20Sopenharmony_ci			dvb_attach(stb6000_attach, dev->fe, 0x61,
9188c2ecf20Sopenharmony_ci					&dev->i2c_adap);
9198c2ecf20Sopenharmony_ci			break;
9208c2ecf20Sopenharmony_ci		}
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci		dev->fe = dvb_attach(
9238c2ecf20Sopenharmony_ci			si21xx_attach, &serit_config,
9248c2ecf20Sopenharmony_ci			&dev->i2c_adap);
9258c2ecf20Sopenharmony_ci		if (dev->fe)
9268c2ecf20Sopenharmony_ci			dev->fe->ops.set_voltage = dm1105_set_voltage;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	if (!dev->fe) {
9318c2ecf20Sopenharmony_ci		dev_err(&dev->pdev->dev, "could not attach frontend\n");
9328c2ecf20Sopenharmony_ci		return -ENODEV;
9338c2ecf20Sopenharmony_ci	}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	ret = dvb_register_frontend(&dev->dvb_adapter, dev->fe);
9368c2ecf20Sopenharmony_ci	if (ret < 0) {
9378c2ecf20Sopenharmony_ci		if (dev->fe->ops.release)
9388c2ecf20Sopenharmony_ci			dev->fe->ops.release(dev->fe);
9398c2ecf20Sopenharmony_ci		dev->fe = NULL;
9408c2ecf20Sopenharmony_ci		return ret;
9418c2ecf20Sopenharmony_ci	}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	return 0;
9448c2ecf20Sopenharmony_ci}
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_cistatic void dm1105_read_mac(struct dm1105_dev *dev, u8 *mac)
9478c2ecf20Sopenharmony_ci{
9488c2ecf20Sopenharmony_ci	static u8 command[1] = { 0x28 };
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	struct i2c_msg msg[] = {
9518c2ecf20Sopenharmony_ci		{
9528c2ecf20Sopenharmony_ci			.addr = IIC_24C01_addr >> 1,
9538c2ecf20Sopenharmony_ci			.flags = 0,
9548c2ecf20Sopenharmony_ci			.buf = command,
9558c2ecf20Sopenharmony_ci			.len = 1
9568c2ecf20Sopenharmony_ci		}, {
9578c2ecf20Sopenharmony_ci			.addr = IIC_24C01_addr >> 1,
9588c2ecf20Sopenharmony_ci			.flags = I2C_M_RD,
9598c2ecf20Sopenharmony_ci			.buf = mac,
9608c2ecf20Sopenharmony_ci			.len = 6
9618c2ecf20Sopenharmony_ci		},
9628c2ecf20Sopenharmony_ci	};
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	dm1105_i2c_xfer(&dev->i2c_adap, msg , 2);
9658c2ecf20Sopenharmony_ci	dev_info(&dev->pdev->dev, "MAC %pM\n", mac);
9668c2ecf20Sopenharmony_ci}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_cistatic int dm1105_probe(struct pci_dev *pdev,
9698c2ecf20Sopenharmony_ci				  const struct pci_device_id *ent)
9708c2ecf20Sopenharmony_ci{
9718c2ecf20Sopenharmony_ci	struct dm1105_dev *dev;
9728c2ecf20Sopenharmony_ci	struct dvb_adapter *dvb_adapter;
9738c2ecf20Sopenharmony_ci	struct dvb_demux *dvbdemux;
9748c2ecf20Sopenharmony_ci	struct dmx_demux *dmx;
9758c2ecf20Sopenharmony_ci	int ret = -ENOMEM;
9768c2ecf20Sopenharmony_ci	int i;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	if (dm1105_devcount >= ARRAY_SIZE(card))
9798c2ecf20Sopenharmony_ci		return -ENODEV;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	dev = kzalloc(sizeof(struct dm1105_dev), GFP_KERNEL);
9828c2ecf20Sopenharmony_ci	if (!dev)
9838c2ecf20Sopenharmony_ci		return -ENOMEM;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	/* board config */
9868c2ecf20Sopenharmony_ci	dev->nr = dm1105_devcount;
9878c2ecf20Sopenharmony_ci	dev->boardnr = UNSET;
9888c2ecf20Sopenharmony_ci	if (card[dev->nr] < ARRAY_SIZE(dm1105_boards))
9898c2ecf20Sopenharmony_ci		dev->boardnr = card[dev->nr];
9908c2ecf20Sopenharmony_ci	for (i = 0; UNSET == dev->boardnr &&
9918c2ecf20Sopenharmony_ci				i < ARRAY_SIZE(dm1105_subids); i++)
9928c2ecf20Sopenharmony_ci		if (pdev->subsystem_vendor ==
9938c2ecf20Sopenharmony_ci			dm1105_subids[i].subvendor &&
9948c2ecf20Sopenharmony_ci				pdev->subsystem_device ==
9958c2ecf20Sopenharmony_ci					dm1105_subids[i].subdevice)
9968c2ecf20Sopenharmony_ci			dev->boardnr = dm1105_subids[i].card;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	if (UNSET == dev->boardnr) {
9998c2ecf20Sopenharmony_ci		dev->boardnr = DM1105_BOARD_UNKNOWN;
10008c2ecf20Sopenharmony_ci		dm1105_card_list(pdev);
10018c2ecf20Sopenharmony_ci	}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	dm1105_devcount++;
10048c2ecf20Sopenharmony_ci	dev->pdev = pdev;
10058c2ecf20Sopenharmony_ci	dev->buffer_size = 5 * DM1105_DMA_BYTES;
10068c2ecf20Sopenharmony_ci	dev->PacketErrorCount = 0;
10078c2ecf20Sopenharmony_ci	dev->dmarst = 0;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	ret = pci_enable_device(pdev);
10108c2ecf20Sopenharmony_ci	if (ret < 0)
10118c2ecf20Sopenharmony_ci		goto err_kfree;
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
10148c2ecf20Sopenharmony_ci	if (ret < 0)
10158c2ecf20Sopenharmony_ci		goto err_pci_disable_device;
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	pci_set_master(pdev);
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	ret = pci_request_regions(pdev, DRIVER_NAME);
10208c2ecf20Sopenharmony_ci	if (ret < 0)
10218c2ecf20Sopenharmony_ci		goto err_pci_disable_device;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	dev->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
10248c2ecf20Sopenharmony_ci	if (!dev->io_mem) {
10258c2ecf20Sopenharmony_ci		ret = -EIO;
10268c2ecf20Sopenharmony_ci		goto err_pci_release_regions;
10278c2ecf20Sopenharmony_ci	}
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	spin_lock_init(&dev->lock);
10308c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, dev);
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	ret = dm1105_hw_init(dev);
10338c2ecf20Sopenharmony_ci	if (ret < 0)
10348c2ecf20Sopenharmony_ci		goto err_pci_iounmap;
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	/* i2c */
10378c2ecf20Sopenharmony_ci	i2c_set_adapdata(&dev->i2c_adap, dev);
10388c2ecf20Sopenharmony_ci	strscpy(dev->i2c_adap.name, DRIVER_NAME, sizeof(dev->i2c_adap.name));
10398c2ecf20Sopenharmony_ci	dev->i2c_adap.owner = THIS_MODULE;
10408c2ecf20Sopenharmony_ci	dev->i2c_adap.dev.parent = &pdev->dev;
10418c2ecf20Sopenharmony_ci	dev->i2c_adap.algo = &dm1105_algo;
10428c2ecf20Sopenharmony_ci	dev->i2c_adap.algo_data = dev;
10438c2ecf20Sopenharmony_ci	ret = i2c_add_adapter(&dev->i2c_adap);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	if (ret < 0)
10468c2ecf20Sopenharmony_ci		goto err_dm1105_hw_exit;
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	i2c_set_adapdata(&dev->i2c_bb_adap, dev);
10498c2ecf20Sopenharmony_ci	strscpy(dev->i2c_bb_adap.name, DM1105_I2C_GPIO_NAME,
10508c2ecf20Sopenharmony_ci		sizeof(dev->i2c_bb_adap.name));
10518c2ecf20Sopenharmony_ci	dev->i2c_bb_adap.owner = THIS_MODULE;
10528c2ecf20Sopenharmony_ci	dev->i2c_bb_adap.dev.parent = &pdev->dev;
10538c2ecf20Sopenharmony_ci	dev->i2c_bb_adap.algo_data = &dev->i2c_bit;
10548c2ecf20Sopenharmony_ci	dev->i2c_bit.data = dev;
10558c2ecf20Sopenharmony_ci	dev->i2c_bit.setsda = dm1105_setsda;
10568c2ecf20Sopenharmony_ci	dev->i2c_bit.setscl = dm1105_setscl;
10578c2ecf20Sopenharmony_ci	dev->i2c_bit.getsda = dm1105_getsda;
10588c2ecf20Sopenharmony_ci	dev->i2c_bit.getscl = dm1105_getscl;
10598c2ecf20Sopenharmony_ci	dev->i2c_bit.udelay = 10;
10608c2ecf20Sopenharmony_ci	dev->i2c_bit.timeout = 10;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	/* Raise SCL and SDA */
10638c2ecf20Sopenharmony_ci	dm1105_setsda(dev, 1);
10648c2ecf20Sopenharmony_ci	dm1105_setscl(dev, 1);
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	ret = i2c_bit_add_bus(&dev->i2c_bb_adap);
10678c2ecf20Sopenharmony_ci	if (ret < 0)
10688c2ecf20Sopenharmony_ci		goto err_i2c_del_adapter;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	/* dvb */
10718c2ecf20Sopenharmony_ci	ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME,
10728c2ecf20Sopenharmony_ci					THIS_MODULE, &pdev->dev, adapter_nr);
10738c2ecf20Sopenharmony_ci	if (ret < 0)
10748c2ecf20Sopenharmony_ci		goto err_i2c_del_adapters;
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	dvb_adapter = &dev->dvb_adapter;
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	dm1105_read_mac(dev, dvb_adapter->proposed_mac);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	dvbdemux = &dev->demux;
10818c2ecf20Sopenharmony_ci	dvbdemux->filternum = 256;
10828c2ecf20Sopenharmony_ci	dvbdemux->feednum = 256;
10838c2ecf20Sopenharmony_ci	dvbdemux->start_feed = dm1105_start_feed;
10848c2ecf20Sopenharmony_ci	dvbdemux->stop_feed = dm1105_stop_feed;
10858c2ecf20Sopenharmony_ci	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
10868c2ecf20Sopenharmony_ci			DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
10878c2ecf20Sopenharmony_ci	ret = dvb_dmx_init(dvbdemux);
10888c2ecf20Sopenharmony_ci	if (ret < 0)
10898c2ecf20Sopenharmony_ci		goto err_dvb_unregister_adapter;
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	dmx = &dvbdemux->dmx;
10928c2ecf20Sopenharmony_ci	dev->dmxdev.filternum = 256;
10938c2ecf20Sopenharmony_ci	dev->dmxdev.demux = dmx;
10948c2ecf20Sopenharmony_ci	dev->dmxdev.capabilities = 0;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	ret = dvb_dmxdev_init(&dev->dmxdev, dvb_adapter);
10978c2ecf20Sopenharmony_ci	if (ret < 0)
10988c2ecf20Sopenharmony_ci		goto err_dvb_dmx_release;
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	dev->hw_frontend.source = DMX_FRONTEND_0;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	ret = dmx->add_frontend(dmx, &dev->hw_frontend);
11038c2ecf20Sopenharmony_ci	if (ret < 0)
11048c2ecf20Sopenharmony_ci		goto err_dvb_dmxdev_release;
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	dev->mem_frontend.source = DMX_MEMORY_FE;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	ret = dmx->add_frontend(dmx, &dev->mem_frontend);
11098c2ecf20Sopenharmony_ci	if (ret < 0)
11108c2ecf20Sopenharmony_ci		goto err_remove_hw_frontend;
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	ret = dmx->connect_frontend(dmx, &dev->hw_frontend);
11138c2ecf20Sopenharmony_ci	if (ret < 0)
11148c2ecf20Sopenharmony_ci		goto err_remove_mem_frontend;
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	ret = dvb_net_init(dvb_adapter, &dev->dvbnet, dmx);
11178c2ecf20Sopenharmony_ci	if (ret < 0)
11188c2ecf20Sopenharmony_ci		goto err_disconnect_frontend;
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	ret = frontend_init(dev);
11218c2ecf20Sopenharmony_ci	if (ret < 0)
11228c2ecf20Sopenharmony_ci		goto err_dvb_net;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	dm1105_ir_init(dev);
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	INIT_WORK(&dev->work, dm1105_dmx_buffer);
11278c2ecf20Sopenharmony_ci	sprintf(dev->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num);
11288c2ecf20Sopenharmony_ci	dev->wq = create_singlethread_workqueue(dev->wqn);
11298c2ecf20Sopenharmony_ci	if (!dev->wq) {
11308c2ecf20Sopenharmony_ci		ret = -ENOMEM;
11318c2ecf20Sopenharmony_ci		goto err_dvb_net;
11328c2ecf20Sopenharmony_ci	}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	ret = request_irq(pdev->irq, dm1105_irq, IRQF_SHARED,
11358c2ecf20Sopenharmony_ci						DRIVER_NAME, dev);
11368c2ecf20Sopenharmony_ci	if (ret < 0)
11378c2ecf20Sopenharmony_ci		goto err_workqueue;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	return 0;
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_cierr_workqueue:
11428c2ecf20Sopenharmony_ci	destroy_workqueue(dev->wq);
11438c2ecf20Sopenharmony_cierr_dvb_net:
11448c2ecf20Sopenharmony_ci	dvb_net_release(&dev->dvbnet);
11458c2ecf20Sopenharmony_cierr_disconnect_frontend:
11468c2ecf20Sopenharmony_ci	dmx->disconnect_frontend(dmx);
11478c2ecf20Sopenharmony_cierr_remove_mem_frontend:
11488c2ecf20Sopenharmony_ci	dmx->remove_frontend(dmx, &dev->mem_frontend);
11498c2ecf20Sopenharmony_cierr_remove_hw_frontend:
11508c2ecf20Sopenharmony_ci	dmx->remove_frontend(dmx, &dev->hw_frontend);
11518c2ecf20Sopenharmony_cierr_dvb_dmxdev_release:
11528c2ecf20Sopenharmony_ci	dvb_dmxdev_release(&dev->dmxdev);
11538c2ecf20Sopenharmony_cierr_dvb_dmx_release:
11548c2ecf20Sopenharmony_ci	dvb_dmx_release(dvbdemux);
11558c2ecf20Sopenharmony_cierr_dvb_unregister_adapter:
11568c2ecf20Sopenharmony_ci	dvb_unregister_adapter(dvb_adapter);
11578c2ecf20Sopenharmony_cierr_i2c_del_adapters:
11588c2ecf20Sopenharmony_ci	i2c_del_adapter(&dev->i2c_bb_adap);
11598c2ecf20Sopenharmony_cierr_i2c_del_adapter:
11608c2ecf20Sopenharmony_ci	i2c_del_adapter(&dev->i2c_adap);
11618c2ecf20Sopenharmony_cierr_dm1105_hw_exit:
11628c2ecf20Sopenharmony_ci	dm1105_hw_exit(dev);
11638c2ecf20Sopenharmony_cierr_pci_iounmap:
11648c2ecf20Sopenharmony_ci	pci_iounmap(pdev, dev->io_mem);
11658c2ecf20Sopenharmony_cierr_pci_release_regions:
11668c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
11678c2ecf20Sopenharmony_cierr_pci_disable_device:
11688c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
11698c2ecf20Sopenharmony_cierr_kfree:
11708c2ecf20Sopenharmony_ci	kfree(dev);
11718c2ecf20Sopenharmony_ci	return ret;
11728c2ecf20Sopenharmony_ci}
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_cistatic void dm1105_remove(struct pci_dev *pdev)
11758c2ecf20Sopenharmony_ci{
11768c2ecf20Sopenharmony_ci	struct dm1105_dev *dev = pci_get_drvdata(pdev);
11778c2ecf20Sopenharmony_ci	struct dvb_adapter *dvb_adapter = &dev->dvb_adapter;
11788c2ecf20Sopenharmony_ci	struct dvb_demux *dvbdemux = &dev->demux;
11798c2ecf20Sopenharmony_ci	struct dmx_demux *dmx = &dvbdemux->dmx;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	cancel_work_sync(&dev->ir.work);
11828c2ecf20Sopenharmony_ci	dm1105_ir_exit(dev);
11838c2ecf20Sopenharmony_ci	dmx->close(dmx);
11848c2ecf20Sopenharmony_ci	dvb_net_release(&dev->dvbnet);
11858c2ecf20Sopenharmony_ci	if (dev->fe)
11868c2ecf20Sopenharmony_ci		dvb_unregister_frontend(dev->fe);
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	dmx->disconnect_frontend(dmx);
11898c2ecf20Sopenharmony_ci	dmx->remove_frontend(dmx, &dev->mem_frontend);
11908c2ecf20Sopenharmony_ci	dmx->remove_frontend(dmx, &dev->hw_frontend);
11918c2ecf20Sopenharmony_ci	dvb_dmxdev_release(&dev->dmxdev);
11928c2ecf20Sopenharmony_ci	dvb_dmx_release(dvbdemux);
11938c2ecf20Sopenharmony_ci	dvb_unregister_adapter(dvb_adapter);
11948c2ecf20Sopenharmony_ci	i2c_del_adapter(&dev->i2c_adap);
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	dm1105_hw_exit(dev);
11978c2ecf20Sopenharmony_ci	free_irq(pdev->irq, dev);
11988c2ecf20Sopenharmony_ci	pci_iounmap(pdev, dev->io_mem);
11998c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
12008c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
12018c2ecf20Sopenharmony_ci	dm1105_devcount--;
12028c2ecf20Sopenharmony_ci	kfree(dev);
12038c2ecf20Sopenharmony_ci}
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_cistatic const struct pci_device_id dm1105_id_table[] = {
12068c2ecf20Sopenharmony_ci	{
12078c2ecf20Sopenharmony_ci		.vendor = PCI_VENDOR_ID_TRIGEM,
12088c2ecf20Sopenharmony_ci		.device = PCI_DEVICE_ID_DM1105,
12098c2ecf20Sopenharmony_ci		.subvendor = PCI_ANY_ID,
12108c2ecf20Sopenharmony_ci		.subdevice = PCI_ANY_ID,
12118c2ecf20Sopenharmony_ci	}, {
12128c2ecf20Sopenharmony_ci		.vendor = PCI_VENDOR_ID_AXESS,
12138c2ecf20Sopenharmony_ci		.device = PCI_DEVICE_ID_DM05,
12148c2ecf20Sopenharmony_ci		.subvendor = PCI_ANY_ID,
12158c2ecf20Sopenharmony_ci		.subdevice = PCI_ANY_ID,
12168c2ecf20Sopenharmony_ci	}, {
12178c2ecf20Sopenharmony_ci		/* empty */
12188c2ecf20Sopenharmony_ci	},
12198c2ecf20Sopenharmony_ci};
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, dm1105_id_table);
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_cistatic struct pci_driver dm1105_driver = {
12248c2ecf20Sopenharmony_ci	.name = DRIVER_NAME,
12258c2ecf20Sopenharmony_ci	.id_table = dm1105_id_table,
12268c2ecf20Sopenharmony_ci	.probe = dm1105_probe,
12278c2ecf20Sopenharmony_ci	.remove = dm1105_remove,
12288c2ecf20Sopenharmony_ci};
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_cimodule_pci_driver(dm1105_driver);
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ciMODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");
12338c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SDMC DM1105 DVB driver");
12348c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1235