aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/ddbridge
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb/ddbridge')
-rw-r--r--drivers/media/dvb/ddbridge/Kconfig18
-rw-r--r--drivers/media/dvb/ddbridge/Makefile14
-rw-r--r--drivers/media/dvb/ddbridge/ddbridge-core.c1719
-rw-r--r--drivers/media/dvb/ddbridge/ddbridge-regs.h151
-rw-r--r--drivers/media/dvb/ddbridge/ddbridge.h187
5 files changed, 2089 insertions, 0 deletions
diff --git a/drivers/media/dvb/ddbridge/Kconfig b/drivers/media/dvb/ddbridge/Kconfig
new file mode 100644
index 00000000000..d099e1a12c8
--- /dev/null
+++ b/drivers/media/dvb/ddbridge/Kconfig
@@ -0,0 +1,18 @@
1config DVB_DDBRIDGE
2 tristate "Digital Devices bridge support"
3 depends on DVB_CORE && PCI && I2C
4 select DVB_LNBP21 if !DVB_FE_CUSTOMISE
5 select DVB_STV6110x if !DVB_FE_CUSTOMISE
6 select DVB_STV090x if !DVB_FE_CUSTOMISE
7 select DVB_DRXK if !DVB_FE_CUSTOMISE
8 select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE
9 ---help---
10 Support for cards with the Digital Devices PCI express bridge:
11 - Octopus PCIe Bridge
12 - Octopus mini PCIe Bridge
13 - Octopus LE
14 - DuoFlex S2 Octopus
15 - DuoFlex CT Octopus
16 - cineS2(v6)
17
18 Say Y if you own such a card and want to use it.
diff --git a/drivers/media/dvb/ddbridge/Makefile b/drivers/media/dvb/ddbridge/Makefile
new file mode 100644
index 00000000000..de4fe193c3e
--- /dev/null
+++ b/drivers/media/dvb/ddbridge/Makefile
@@ -0,0 +1,14 @@
1#
2# Makefile for the ddbridge device driver
3#
4
5ddbridge-objs := ddbridge-core.o
6
7obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
8
9EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
10EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/
11EXTRA_CFLAGS += -Idrivers/media/common/tuners/
12
13# For the staging CI driver cxd2099
14EXTRA_CFLAGS += -Idrivers/staging/cxd2099/
diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c
new file mode 100644
index 00000000000..573d540f213
--- /dev/null
+++ b/drivers/media/dvb/ddbridge/ddbridge-core.c
@@ -0,0 +1,1719 @@
1/*
2 * ddbridge.c: Digital Devices PCIe bridge driver
3 *
4 * Copyright (C) 2010-2011 Digital Devices GmbH
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 only, as published by the Free Software Foundation.
9 *
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA
21 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
22 */
23
24#include <linux/module.h>
25#include <linux/init.h>
26#include <linux/interrupt.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/poll.h>
30#include <linux/io.h>
31#include <linux/pci.h>
32#include <linux/pci_ids.h>
33#include <linux/timer.h>
34#include <linux/version.h>
35#include <linux/i2c.h>
36#include <linux/swab.h>
37#include <linux/vmalloc.h>
38#include "ddbridge.h"
39
40#include "ddbridge-regs.h"
41
42#include "tda18271c2dd.h"
43#include "stv6110x.h"
44#include "stv090x.h"
45#include "lnbh24.h"
46#include "drxk.h"
47
48DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
49
50/* MSI had problems with lost interrupts, fixed but needs testing */
51#undef CONFIG_PCI_MSI
52
53/******************************************************************************/
54
55static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
56{
57 struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD,
58 .buf = val, .len = 1 } };
59 return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
60}
61
62static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val)
63{
64 struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
65 .buf = &reg, .len = 1 },
66 {.addr = adr, .flags = I2C_M_RD,
67 .buf = val, .len = 1 } };
68 return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
69}
70
71static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
72 u16 reg, u8 *val)
73{
74 u8 msg[2] = {reg>>8, reg&0xff};
75 struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
76 .buf = msg, .len = 2},
77 {.addr = adr, .flags = I2C_M_RD,
78 .buf = val, .len = 1} };
79 return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
80}
81
82static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
83{
84 struct ddb *dev = i2c->dev;
85 int stat;
86 u32 val;
87
88 i2c->done = 0;
89 ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND);
90 stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ);
91 if (stat <= 0) {
92 printk(KERN_ERR "I2C timeout\n");
93 { /* MSI debugging*/
94 u32 istat = ddbreadl(INTERRUPT_STATUS);
95 printk(KERN_ERR "IRS %08x\n", istat);
96 ddbwritel(istat, INTERRUPT_ACK);
97 }
98 return -EIO;
99 }
100 val = ddbreadl(i2c->regs+I2C_COMMAND);
101 if (val & 0x70000)
102 return -EIO;
103 return 0;
104}
105
106static int ddb_i2c_master_xfer(struct i2c_adapter *adapter,
107 struct i2c_msg msg[], int num)
108{
109 struct ddb_i2c *i2c = (struct ddb_i2c *)i2c_get_adapdata(adapter);
110 struct ddb *dev = i2c->dev;
111 u8 addr = 0;
112
113 if (num)
114 addr = msg[0].addr;
115
116 if (num == 2 && msg[1].flags & I2C_M_RD &&
117 !(msg[0].flags & I2C_M_RD)) {
118 memcpy_toio(dev->regs + I2C_TASKMEM_BASE + i2c->wbuf,
119 msg[0].buf, msg[0].len);
120 ddbwritel(msg[0].len|(msg[1].len << 16),
121 i2c->regs+I2C_TASKLENGTH);
122 if (!ddb_i2c_cmd(i2c, addr, 1)) {
123 memcpy_fromio(msg[1].buf,
124 dev->regs + I2C_TASKMEM_BASE + i2c->rbuf,
125 msg[1].len);
126 return num;
127 }
128 }
129
130 if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
131 ddbcpyto(I2C_TASKMEM_BASE + i2c->wbuf, msg[0].buf, msg[0].len);
132 ddbwritel(msg[0].len, i2c->regs + I2C_TASKLENGTH);
133 if (!ddb_i2c_cmd(i2c, addr, 2))
134 return num;
135 }
136 if (num == 1 && (msg[0].flags & I2C_M_RD)) {
137 ddbwritel(msg[0].len << 16, i2c->regs + I2C_TASKLENGTH);
138 if (!ddb_i2c_cmd(i2c, addr, 3)) {
139 ddbcpyfrom(msg[0].buf,
140 I2C_TASKMEM_BASE + i2c->rbuf, msg[0].len);
141 return num;
142 }
143 }
144 return -EIO;
145}
146
147
148static u32 ddb_i2c_functionality(struct i2c_adapter *adap)
149{
150 return I2C_FUNC_SMBUS_EMUL;
151}
152
153struct i2c_algorithm ddb_i2c_algo = {
154 .master_xfer = ddb_i2c_master_xfer,
155 .functionality = ddb_i2c_functionality,
156};
157
158static void ddb_i2c_release(struct ddb *dev)
159{
160 int i;
161 struct ddb_i2c *i2c;
162 struct i2c_adapter *adap;
163
164 for (i = 0; i < dev->info->port_num; i++) {
165 i2c = &dev->i2c[i];
166 adap = &i2c->adap;
167 i2c_del_ad