1a10e763bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2786baecfSMauro Carvalho Chehab /* DVB USB framework compliant Linux driver for the Opera1 DVB-S Card
3786baecfSMauro Carvalho Chehab *
4786baecfSMauro Carvalho Chehab * Copyright (C) 2006 Mario Hlawitschka (dh1pa@amsat.org)
5786baecfSMauro Carvalho Chehab * Copyright (C) 2006 Marco Gittler (g.marco@freenet.de)
6786baecfSMauro Carvalho Chehab *
7577a7ad3SMauro Carvalho Chehab * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
8786baecfSMauro Carvalho Chehab */
9786baecfSMauro Carvalho Chehab
10786baecfSMauro Carvalho Chehab #define DVB_USB_LOG_PREFIX "opera"
11786baecfSMauro Carvalho Chehab
12786baecfSMauro Carvalho Chehab #include "dvb-usb.h"
13786baecfSMauro Carvalho Chehab #include "stv0299.h"
14786baecfSMauro Carvalho Chehab
15786baecfSMauro Carvalho Chehab #define OPERA_READ_MSG 0
16786baecfSMauro Carvalho Chehab #define OPERA_WRITE_MSG 1
17786baecfSMauro Carvalho Chehab #define OPERA_I2C_TUNER 0xd1
18786baecfSMauro Carvalho Chehab
19786baecfSMauro Carvalho Chehab #define READ_FX2_REG_REQ 0xba
20786baecfSMauro Carvalho Chehab #define READ_MAC_ADDR 0x08
21786baecfSMauro Carvalho Chehab #define OPERA_WRITE_FX2 0xbb
22786baecfSMauro Carvalho Chehab #define OPERA_TUNER_REQ 0xb1
23786baecfSMauro Carvalho Chehab #define REG_1F_SYMBOLRATE_BYTE0 0x1f
24786baecfSMauro Carvalho Chehab #define REG_20_SYMBOLRATE_BYTE1 0x20
25786baecfSMauro Carvalho Chehab #define REG_21_SYMBOLRATE_BYTE2 0x21
26786baecfSMauro Carvalho Chehab
27786baecfSMauro Carvalho Chehab #define ADDR_B600_VOLTAGE_13V (0x02)
28786baecfSMauro Carvalho Chehab #define ADDR_B601_VOLTAGE_18V (0x03)
29786baecfSMauro Carvalho Chehab #define ADDR_B1A6_STREAM_CTRL (0x04)
30786baecfSMauro Carvalho Chehab #define ADDR_B880_READ_REMOTE (0x05)
31786baecfSMauro Carvalho Chehab
32786baecfSMauro Carvalho Chehab struct opera1_state {
33786baecfSMauro Carvalho Chehab u32 last_key_pressed;
34786baecfSMauro Carvalho Chehab };
35786baecfSMauro Carvalho Chehab struct rc_map_opera_table {
36786baecfSMauro Carvalho Chehab u32 keycode;
37786baecfSMauro Carvalho Chehab u32 event;
38786baecfSMauro Carvalho Chehab };
39786baecfSMauro Carvalho Chehab
40786baecfSMauro Carvalho Chehab static int dvb_usb_opera1_debug;
41786baecfSMauro Carvalho Chehab module_param_named(debug, dvb_usb_opera1_debug, int, 0644);
42786baecfSMauro Carvalho Chehab MODULE_PARM_DESC(debug,
43786baecfSMauro Carvalho Chehab "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))."
44786baecfSMauro Carvalho Chehab DVB_USB_DEBUG_STATUS);
45786baecfSMauro Carvalho Chehab
46786baecfSMauro Carvalho Chehab DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
47786baecfSMauro Carvalho Chehab
48786baecfSMauro Carvalho Chehab
opera1_xilinx_rw(struct usb_device * dev,u8 request,u16 value,u8 * data,u16 len,int flags)49786baecfSMauro Carvalho Chehab static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value,
50786baecfSMauro Carvalho Chehab u8 * data, u16 len, int flags)
51786baecfSMauro Carvalho Chehab {
52786baecfSMauro Carvalho Chehab int ret;
53786baecfSMauro Carvalho Chehab u8 tmp;
54786baecfSMauro Carvalho Chehab u8 *buf;
55786baecfSMauro Carvalho Chehab unsigned int pipe = (flags == OPERA_READ_MSG) ?
56786baecfSMauro Carvalho Chehab usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0);
57786baecfSMauro Carvalho Chehab u8 request_type = (flags == OPERA_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
58786baecfSMauro Carvalho Chehab
59786baecfSMauro Carvalho Chehab buf = kmalloc(len, GFP_KERNEL);
60786baecfSMauro Carvalho Chehab if (!buf)
61786baecfSMauro Carvalho Chehab return -ENOMEM;
62786baecfSMauro Carvalho Chehab
63786baecfSMauro Carvalho Chehab if (flags == OPERA_WRITE_MSG)
64786baecfSMauro Carvalho Chehab memcpy(buf, data, len);
65786baecfSMauro Carvalho Chehab ret = usb_control_msg(dev, pipe, request,
66786baecfSMauro Carvalho Chehab request_type | USB_TYPE_VENDOR, value, 0x0,
67786baecfSMauro Carvalho Chehab buf, len, 2000);
68786baecfSMauro Carvalho Chehab
69786baecfSMauro Carvalho Chehab if (request == OPERA_TUNER_REQ) {
70786baecfSMauro Carvalho Chehab tmp = buf[0];
71786baecfSMauro Carvalho Chehab if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
72786baecfSMauro Carvalho Chehab OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR,
73786baecfSMauro Carvalho Chehab 0x01, 0x0, buf, 1, 2000) < 1 || buf[0] != 0x08) {
74786baecfSMauro Carvalho Chehab ret = 0;
75786baecfSMauro Carvalho Chehab goto out;
76786baecfSMauro Carvalho Chehab }
77786baecfSMauro Carvalho Chehab buf[0] = tmp;
78786baecfSMauro Carvalho Chehab }
79786baecfSMauro Carvalho Chehab if (flags == OPERA_READ_MSG)
80786baecfSMauro Carvalho Chehab memcpy(data, buf, len);
81786baecfSMauro Carvalho Chehab out:
82786baecfSMauro Carvalho Chehab kfree(buf);
83786baecfSMauro Carvalho Chehab return ret;
84786baecfSMauro Carvalho Chehab }
85786baecfSMauro Carvalho Chehab
86786baecfSMauro Carvalho Chehab /* I2C */
87786baecfSMauro Carvalho Chehab
opera1_usb_i2c_msgxfer(struct dvb_usb_device * dev,u16 addr,u8 * buf,u16 len)88786baecfSMauro Carvalho Chehab static int opera1_usb_i2c_msgxfer(struct dvb_usb_device *dev, u16 addr,
89786baecfSMauro Carvalho Chehab u8 * buf, u16 len)
90786baecfSMauro Carvalho Chehab {
91786baecfSMauro Carvalho Chehab int ret = 0;
92786baecfSMauro Carvalho Chehab u8 request;
93786baecfSMauro Carvalho Chehab u16 value;
94786baecfSMauro Carvalho Chehab
95786baecfSMauro Carvalho Chehab if (!dev) {
96786baecfSMauro Carvalho Chehab info("no usb_device");
97786baecfSMauro Carvalho Chehab return -EINVAL;
98786baecfSMauro Carvalho Chehab }
99786baecfSMauro Carvalho Chehab if (mutex_lock_interruptible(&dev->usb_mutex) < 0)
100786baecfSMauro Carvalho Chehab return -EAGAIN;
101786baecfSMauro Carvalho Chehab
102786baecfSMauro Carvalho Chehab switch (addr>>1){
103786baecfSMauro Carvalho Chehab case ADDR_B600_VOLTAGE_13V:
104786baecfSMauro Carvalho Chehab request=0xb6;
105786baecfSMauro Carvalho Chehab value=0x00;
106786baecfSMauro Carvalho Chehab break;
107786baecfSMauro Carvalho Chehab case ADDR_B601_VOLTAGE_18V:
108786baecfSMauro Carvalho Chehab request=0xb6;
109786baecfSMauro Carvalho Chehab value=0x01;
110786baecfSMauro Carvalho Chehab break;
111786baecfSMauro Carvalho Chehab case ADDR_B1A6_STREAM_CTRL:
112786baecfSMauro Carvalho Chehab request=0xb1;
113786baecfSMauro Carvalho Chehab value=0xa6;
114786baecfSMauro Carvalho Chehab break;
115786baecfSMauro Carvalho Chehab case ADDR_B880_READ_REMOTE:
116786baecfSMauro Carvalho Chehab request=0xb8;
117786baecfSMauro Carvalho Chehab value=0x80;
118786baecfSMauro Carvalho Chehab break;
119786baecfSMauro Carvalho Chehab default:
120786baecfSMauro Carvalho Chehab request=0xb1;
121786baecfSMauro Carvalho Chehab value=addr;
122786baecfSMauro Carvalho Chehab }
123786baecfSMauro Carvalho Chehab ret = opera1_xilinx_rw(dev->udev, request,
124786baecfSMauro Carvalho Chehab value, buf, len,
125786baecfSMauro Carvalho Chehab addr&0x01?OPERA_READ_MSG:OPERA_WRITE_MSG);
126786baecfSMauro Carvalho Chehab
127786baecfSMauro Carvalho Chehab mutex_unlock(&dev->usb_mutex);
128786baecfSMauro Carvalho Chehab return ret;
129786baecfSMauro Carvalho Chehab }
130786baecfSMauro Carvalho Chehab
opera1_i2c_xfer(struct i2c_adapter * adap,struct i2c_msg msg[],int num)131786baecfSMauro Carvalho Chehab static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
132786baecfSMauro Carvalho Chehab int num)
133786baecfSMauro Carvalho Chehab {
134786baecfSMauro Carvalho Chehab struct dvb_usb_device *d = i2c_get_adapdata(adap);
135786baecfSMauro Carvalho Chehab int i = 0, tmp = 0;
136786baecfSMauro Carvalho Chehab
137786baecfSMauro Carvalho Chehab if (!d)
138786baecfSMauro Carvalho Chehab return -ENODEV;
139786baecfSMauro Carvalho Chehab if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
140786baecfSMauro Carvalho Chehab return -EAGAIN;
141786baecfSMauro Carvalho Chehab
142786baecfSMauro Carvalho Chehab for (i = 0; i < num; i++) {
143786baecfSMauro Carvalho Chehab if ((tmp = opera1_usb_i2c_msgxfer(d,
144786baecfSMauro Carvalho Chehab (msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0),
145786baecfSMauro Carvalho Chehab msg[i].buf,
146786baecfSMauro Carvalho Chehab msg[i].len
147786baecfSMauro Carvalho Chehab )) != msg[i].len) {
148786baecfSMauro Carvalho Chehab break;
149786baecfSMauro Carvalho Chehab }
150786baecfSMauro Carvalho Chehab if (dvb_usb_opera1_debug & 0x10)
15107f42258SMasanari Iida info("sending i2c message %d %d", tmp, msg[i].len);
152786baecfSMauro Carvalho Chehab }
153786baecfSMauro Carvalho Chehab mutex_unlock(&d->i2c_mutex);
154786baecfSMauro Carvalho Chehab return num;
155786baecfSMauro Carvalho Chehab }
156786baecfSMauro Carvalho Chehab
opera1_i2c_func(struct i2c_adapter * adapter)157786baecfSMauro Carvalho Chehab static u32 opera1_i2c_func(struct i2c_adapter *adapter)
158786baecfSMauro Carvalho Chehab {
159786baecfSMauro Carvalho Chehab return I2C_FUNC_I2C;
160786baecfSMauro Carvalho Chehab }
161786baecfSMauro Carvalho Chehab
162786baecfSMauro Carvalho Chehab static struct i2c_algorithm opera1_i2c_algo = {
163786baecfSMauro Carvalho Chehab .master_xfer = opera1_i2c_xfer,
164786baecfSMauro Carvalho Chehab .functionality = opera1_i2c_func,
165786baecfSMauro Carvalho Chehab };
166786baecfSMauro Carvalho Chehab
opera1_set_voltage(struct dvb_frontend * fe,enum fe_sec_voltage voltage)1670df289a2SMauro Carvalho Chehab static int opera1_set_voltage(struct dvb_frontend *fe,
1680df289a2SMauro Carvalho Chehab enum fe_sec_voltage voltage)
169786baecfSMauro Carvalho Chehab {
170786baecfSMauro Carvalho Chehab static u8 command_13v[1]={0x00};
171786baecfSMauro Carvalho Chehab static u8 command_18v[1]={0x01};
172786baecfSMauro Carvalho Chehab struct i2c_msg msg[] = {
173786baecfSMauro Carvalho Chehab {.addr = ADDR_B600_VOLTAGE_13V,.flags = 0,.buf = command_13v,.len = 1},
174786baecfSMauro Carvalho Chehab };
175663e7460SYu Zhe struct dvb_usb_adapter *udev_adap = fe->dvb->priv;
176786baecfSMauro Carvalho Chehab if (voltage == SEC_VOLTAGE_18) {
177786baecfSMauro Carvalho Chehab msg[0].addr = ADDR_B601_VOLTAGE_18V;
178786baecfSMauro Carvalho Chehab msg[0].buf = command_18v;
179786baecfSMauro Carvalho Chehab }
180786baecfSMauro Carvalho Chehab i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
181786baecfSMauro Carvalho Chehab return 0;
182786baecfSMauro Carvalho Chehab }
183786baecfSMauro Carvalho Chehab
opera1_stv0299_set_symbol_rate(struct dvb_frontend * fe,u32 srate,u32 ratio)184786baecfSMauro Carvalho Chehab static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate,
185786baecfSMauro Carvalho Chehab u32 ratio)
186786baecfSMauro Carvalho Chehab {
187786baecfSMauro Carvalho Chehab stv0299_writereg(fe, 0x13, 0x98);
188786baecfSMauro Carvalho Chehab stv0299_writereg(fe, 0x14, 0x95);
189786baecfSMauro Carvalho Chehab stv0299_writereg(fe, REG_1F_SYMBOLRATE_BYTE0, (ratio >> 16) & 0xff);
190786baecfSMauro Carvalho Chehab stv0299_writereg(fe, REG_20_SYMBOLRATE_BYTE1, (ratio >> 8) & 0xff);
191786baecfSMauro Carvalho Chehab stv0299_writereg(fe, REG_21_SYMBOLRATE_BYTE2, (ratio) & 0xf0);
192786baecfSMauro Carvalho Chehab return 0;
193786baecfSMauro Carvalho Chehab
194786baecfSMauro Carvalho Chehab }
195786baecfSMauro Carvalho Chehab static u8 opera1_inittab[] = {
196786baecfSMauro Carvalho Chehab 0x00, 0xa1,
197786baecfSMauro Carvalho Chehab 0x01, 0x15,
198786baecfSMauro Carvalho Chehab 0x02, 0x30,
199786baecfSMauro Carvalho Chehab 0x03, 0x00,
200786baecfSMauro Carvalho Chehab 0x04, 0x7d,
201786baecfSMauro Carvalho Chehab 0x05, 0x05,
202786baecfSMauro Carvalho Chehab 0x06, 0x02,
203786baecfSMauro Carvalho Chehab 0x07, 0x00,
204786baecfSMauro Carvalho Chehab 0x0b, 0x00,
205786baecfSMauro Carvalho Chehab 0x0c, 0x01,
206786baecfSMauro Carvalho Chehab 0x0d, 0x81,
207786baecfSMauro Carvalho Chehab 0x0e, 0x44,
208786baecfSMauro Carvalho Chehab 0x0f, 0x19,
209786baecfSMauro Carvalho Chehab 0x10, 0x3f,
210786baecfSMauro Carvalho Chehab 0x11, 0x84,
211786baecfSMauro Carvalho Chehab 0x12, 0xda,
212786baecfSMauro Carvalho Chehab 0x13, 0x98,
213786baecfSMauro Carvalho Chehab 0x14, 0x95,
214786baecfSMauro Carvalho Chehab 0x15, 0xc9,
215786baecfSMauro Carvalho Chehab 0x16, 0xeb,
216786baecfSMauro Carvalho Chehab 0x17, 0x00,
217786baecfSMauro Carvalho Chehab 0x18, 0x19,
218786baecfSMauro Carvalho Chehab 0x19, 0x8b,
219786baecfSMauro Carvalho Chehab 0x1a, 0x00,
220786baecfSMauro Carvalho Chehab 0x1b, 0x82,
221786baecfSMauro Carvalho Chehab 0x1c, 0x7f,
222786baecfSMauro Carvalho Chehab 0x1d, 0x00,
223786baecfSMauro Carvalho Chehab 0x1e, 0x00,
224786baecfSMauro Carvalho Chehab REG_1F_SYMBOLRATE_BYTE0, 0x06,
225786baecfSMauro Carvalho Chehab REG_20_SYMBOLRATE_BYTE1, 0x50,
226786baecfSMauro Carvalho Chehab REG_21_SYMBOLRATE_BYTE2, 0x10,
227786baecfSMauro Carvalho Chehab 0x22, 0x00,
228786baecfSMauro Carvalho Chehab 0x23, 0x00,
229786baecfSMauro Carvalho Chehab 0x24, 0x37,
230786baecfSMauro Carvalho Chehab 0x25, 0xbc,
231786baecfSMauro Carvalho Chehab 0x26, 0x00,
232786baecfSMauro Carvalho Chehab 0x27, 0x00,
233786baecfSMauro Carvalho Chehab 0x28, 0x00,
234786baecfSMauro Carvalho Chehab 0x29, 0x1e,
235786baecfSMauro Carvalho Chehab 0x2a, 0x14,
236786baecfSMauro Carvalho Chehab 0x2b, 0x1f,
237786baecfSMauro Carvalho Chehab 0x2c, 0x09,
238786baecfSMauro Carvalho Chehab 0x2d, 0x0a,
239786baecfSMauro Carvalho Chehab 0x2e, 0x00,
240786baecfSMauro Carvalho Chehab 0x2f, 0x00,
241786baecfSMauro Carvalho Chehab 0x30, 0x00,
242786baecfSMauro Carvalho Chehab 0x31, 0x1f,
243786baecfSMauro Carvalho Chehab 0x32, 0x19,
244786baecfSMauro Carvalho Chehab 0x33, 0xfc,
245786baecfSMauro Carvalho Chehab 0x34, 0x13,
246786baecfSMauro Carvalho Chehab 0xff, 0xff,
247786baecfSMauro Carvalho Chehab };
248786baecfSMauro Carvalho Chehab
249786baecfSMauro Carvalho Chehab static struct stv0299_config opera1_stv0299_config = {
250786baecfSMauro Carvalho Chehab .demod_address = 0xd0>>1,
251786baecfSMauro Carvalho Chehab .min_delay_ms = 100,
252786baecfSMauro Carvalho Chehab .mclk = 88000000UL,
253786baecfSMauro Carvalho Chehab .invert = 1,
254786baecfSMauro Carvalho Chehab .skip_reinit = 0,
255786baecfSMauro Carvalho Chehab .lock_output = STV0299_LOCKOUTPUT_0,
256786baecfSMauro Carvalho Chehab .volt13_op0_op1 = STV0299_VOLT13_OP0,
257786baecfSMauro Carvalho Chehab .inittab = opera1_inittab,
258786baecfSMauro Carvalho Chehab .set_symbol_rate = opera1_stv0299_set_symbol_rate,
259786baecfSMauro Carvalho Chehab };
260786baecfSMauro Carvalho Chehab
opera1_frontend_attach(struct dvb_usb_adapter * d)261786baecfSMauro Carvalho Chehab static int opera1_frontend_attach(struct dvb_usb_adapter *d)
262786baecfSMauro Carvalho Chehab {
263786baecfSMauro Carvalho Chehab d->fe_adap[0].fe = dvb_attach(stv0299_attach, &opera1_stv0299_config,
264786baecfSMauro Carvalho Chehab &d->dev->i2c_adap);
265786baecfSMauro Carvalho Chehab if ((d->fe_adap[0].fe) != NULL) {
266786baecfSMauro Carvalho Chehab d->fe_adap[0].fe->ops.set_voltage = opera1_set_voltage;
267786baecfSMauro Carvalho Chehab return 0;
268786baecfSMauro Carvalho Chehab }
269786baecfSMauro Carvalho Chehab info("not attached stv0299");
270786baecfSMauro Carvalho Chehab return -EIO;
271786baecfSMauro Carvalho Chehab }
272786baecfSMauro Carvalho Chehab
opera1_tuner_attach(struct dvb_usb_adapter * adap)273786baecfSMauro Carvalho Chehab static int opera1_tuner_attach(struct dvb_usb_adapter *adap)
274786baecfSMauro Carvalho Chehab {
275786baecfSMauro Carvalho Chehab dvb_attach(
276786baecfSMauro Carvalho Chehab dvb_pll_attach, adap->fe_adap[0].fe, 0xc0>>1,
277786baecfSMauro Carvalho Chehab &adap->dev->i2c_adap, DVB_PLL_OPERA1
278786baecfSMauro Carvalho Chehab );
279786baecfSMauro Carvalho Chehab return 0;
280786baecfSMauro Carvalho Chehab }
281786baecfSMauro Carvalho Chehab
opera1_power_ctrl(struct dvb_usb_device * d,int onoff)282786baecfSMauro Carvalho Chehab static int opera1_power_ctrl(struct dvb_usb_device *d, int onoff)
283786baecfSMauro Carvalho Chehab {
284786baecfSMauro Carvalho Chehab u8 val = onoff ? 0x01 : 0x00;
285786baecfSMauro Carvalho Chehab
286786baecfSMauro Carvalho Chehab if (dvb_usb_opera1_debug)
287786baecfSMauro Carvalho Chehab info("power %s", onoff ? "on" : "off");
288786baecfSMauro Carvalho Chehab return opera1_xilinx_rw(d->udev, 0xb7, val,
289786baecfSMauro Carvalho Chehab &val, 1, OPERA_WRITE_MSG);
290786baecfSMauro Carvalho Chehab }
291786baecfSMauro Carvalho Chehab
opera1_streaming_ctrl(struct dvb_usb_adapter * adap,int onoff)292786baecfSMauro Carvalho Chehab static int opera1_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
293786baecfSMauro Carvalho Chehab {
294786baecfSMauro Carvalho Chehab static u8 buf_start[2] = { 0xff, 0x03 };
295786baecfSMauro Carvalho Chehab static u8 buf_stop[2] = { 0xff, 0x00 };
296786baecfSMauro Carvalho Chehab struct i2c_msg start_tuner[] = {
297786baecfSMauro Carvalho Chehab {.addr = ADDR_B1A6_STREAM_CTRL,.buf = onoff ? buf_start : buf_stop,.len = 2},
298786baecfSMauro Carvalho Chehab };
299786baecfSMauro Carvalho Chehab if (dvb_usb_opera1_debug)
300786baecfSMauro Carvalho Chehab info("streaming %s", onoff ? "on" : "off");
301786baecfSMauro Carvalho Chehab i2c_transfer(&adap->dev->i2c_adap, start_tuner, 1);
302786baecfSMauro Carvalho Chehab return 0;
303786baecfSMauro Carvalho Chehab }
304786baecfSMauro Carvalho Chehab
opera1_pid_filter(struct dvb_usb_adapter * adap,int index,u16 pid,int onoff)305786baecfSMauro Carvalho Chehab static int opera1_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
306786baecfSMauro Carvalho Chehab int onoff)
307786baecfSMauro Carvalho Chehab {
308786baecfSMauro Carvalho Chehab u8 b_pid[3];
309786baecfSMauro Carvalho Chehab struct i2c_msg msg[] = {
310786baecfSMauro Carvalho Chehab {.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3},
311786baecfSMauro Carvalho Chehab };
312786baecfSMauro Carvalho Chehab if (dvb_usb_opera1_debug)
313786baecfSMauro Carvalho Chehab info("pidfilter index: %d pid: %d %s", index, pid,
314786baecfSMauro Carvalho Chehab onoff ? "on" : "off");
315786baecfSMauro Carvalho Chehab b_pid[0] = (2 * index) + 4;
316786baecfSMauro Carvalho Chehab b_pid[1] = onoff ? (pid & 0xff) : (0x00);
317786baecfSMauro Carvalho Chehab b_pid[2] = onoff ? ((pid >> 8) & 0xff) : (0x00);
318786baecfSMauro Carvalho Chehab i2c_transfer(&adap->dev->i2c_adap, msg, 1);
319786baecfSMauro Carvalho Chehab return 0;
320786baecfSMauro Carvalho Chehab }
321786baecfSMauro Carvalho Chehab
opera1_pid_filter_control(struct dvb_usb_adapter * adap,int onoff)322786baecfSMauro Carvalho Chehab static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
323786baecfSMauro Carvalho Chehab {
324786baecfSMauro Carvalho Chehab int u = 0x04;
325786baecfSMauro Carvalho Chehab u8 b_pid[3];
326786baecfSMauro Carvalho Chehab struct i2c_msg msg[] = {
327786baecfSMauro Carvalho Chehab {.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3},
328786baecfSMauro Carvalho Chehab };
329786baecfSMauro Carvalho Chehab if (dvb_usb_opera1_debug)
330786baecfSMauro Carvalho Chehab info("%s hw-pidfilter", onoff ? "enable" : "disable");
331786baecfSMauro Carvalho Chehab for (; u < 0x7e; u += 2) {
332786baecfSMauro Carvalho Chehab b_pid[0] = u;
333786baecfSMauro Carvalho Chehab b_pid[1] = 0;
334786baecfSMauro Carvalho Chehab b_pid[2] = 0x80;
335786baecfSMauro Carvalho Chehab i2c_transfer(&adap->dev->i2c_adap, msg, 1);
336786baecfSMauro Carvalho Chehab }
337786baecfSMauro Carvalho Chehab return 0;
338786baecfSMauro Carvalho Chehab }
339786baecfSMauro Carvalho Chehab
340786baecfSMauro Carvalho Chehab static struct rc_map_table rc_map_opera1_table[] = {
341786baecfSMauro Carvalho Chehab {0x5fa0, KEY_1},
342786baecfSMauro Carvalho Chehab {0x51af, KEY_2},
343786baecfSMauro Carvalho Chehab {0x5da2, KEY_3},
344786baecfSMauro Carvalho Chehab {0x41be, KEY_4},
345786baecfSMauro Carvalho Chehab {0x0bf5, KEY_5},
346786baecfSMauro Carvalho Chehab {0x43bd, KEY_6},
347786baecfSMauro Carvalho Chehab {0x47b8, KEY_7},
348786baecfSMauro Carvalho Chehab {0x49b6, KEY_8},
349786baecfSMauro Carvalho Chehab {0x05fa, KEY_9},
350786baecfSMauro Carvalho Chehab {0x45ba, KEY_0},
351786baecfSMauro Carvalho Chehab {0x09f6, KEY_CHANNELUP}, /*chanup */
352786baecfSMauro Carvalho Chehab {0x1be5, KEY_CHANNELDOWN}, /*chandown */
353786baecfSMauro Carvalho Chehab {0x5da3, KEY_VOLUMEDOWN}, /*voldown */
354786baecfSMauro Carvalho Chehab {0x5fa1, KEY_VOLUMEUP}, /*volup */
355786baecfSMauro Carvalho Chehab {0x07f8, KEY_SPACE}, /*tab */
356786baecfSMauro Carvalho Chehab {0x1fe1, KEY_OK}, /*play ok */
357786baecfSMauro Carvalho Chehab {0x1be4, KEY_ZOOM}, /*zoom */
358786baecfSMauro Carvalho Chehab {0x59a6, KEY_MUTE}, /*mute */
359786baecfSMauro Carvalho Chehab {0x5ba5, KEY_RADIO}, /*tv/f */
360786baecfSMauro Carvalho Chehab {0x19e7, KEY_RECORD}, /*rec */
361786baecfSMauro Carvalho Chehab {0x01fe, KEY_STOP}, /*Stop */
362786baecfSMauro Carvalho Chehab {0x03fd, KEY_PAUSE}, /*pause */
363786baecfSMauro Carvalho Chehab {0x03fc, KEY_SCREEN}, /*<- -> */
364786baecfSMauro Carvalho Chehab {0x07f9, KEY_CAMERA}, /*capture */
365786baecfSMauro Carvalho Chehab {0x47b9, KEY_ESC}, /*exit */
366786baecfSMauro Carvalho Chehab {0x43bc, KEY_POWER2}, /*power */
367786baecfSMauro Carvalho Chehab };
368786baecfSMauro Carvalho Chehab
opera1_rc_query(struct dvb_usb_device * dev,u32 * event,int * state)369786baecfSMauro Carvalho Chehab static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state)
370786baecfSMauro Carvalho Chehab {
371786baecfSMauro Carvalho Chehab struct opera1_state *opst = dev->priv;
372786baecfSMauro Carvalho Chehab u8 rcbuffer[32];
373786baecfSMauro Carvalho Chehab const u16 startmarker1 = 0x10ed;
374786baecfSMauro Carvalho Chehab const u16 startmarker2 = 0x11ec;
375786baecfSMauro Carvalho Chehab struct i2c_msg read_remote[] = {
376786baecfSMauro Carvalho Chehab {.addr = ADDR_B880_READ_REMOTE,.buf = rcbuffer,.flags = I2C_M_RD,.len = 32},
377786baecfSMauro Carvalho Chehab };
378786baecfSMauro Carvalho Chehab int i = 0;
379786baecfSMauro Carvalho Chehab u32 send_key = 0;
380786baecfSMauro Carvalho Chehab
381786baecfSMauro Carvalho Chehab if (i2c_transfer(&dev->i2c_adap, read_remote, 1) == 1) {
382786baecfSMauro Carvalho Chehab for (i = 0; i < 32; i++) {
383786baecfSMauro Carvalho Chehab if (rcbuffer[i])
384786baecfSMauro Carvalho Chehab send_key |= 1;
385786baecfSMauro Carvalho Chehab if (i < 31)
386786baecfSMauro Carvalho Chehab send_key = send_key << 1;
387786baecfSMauro Carvalho Chehab }
388786baecfSMauro Carvalho Chehab if (send_key & 0x8000)
389786baecfSMauro Carvalho Chehab send_key = (send_key << 1) | (send_key >> 15 & 0x01);
390786baecfSMauro Carvalho Chehab
391786baecfSMauro Carvalho Chehab if (send_key == 0xffff && opst->last_key_pressed != 0) {
392786baecfSMauro Carvalho Chehab *state = REMOTE_KEY_REPEAT;
393786baecfSMauro Carvalho Chehab *event = opst->last_key_pressed;
394786baecfSMauro Carvalho Chehab return 0;
395786baecfSMauro Carvalho Chehab }
396786baecfSMauro Carvalho Chehab for (; send_key != 0;) {
397786baecfSMauro Carvalho Chehab if (send_key >> 16 == startmarker2) {
398786baecfSMauro Carvalho Chehab break;
399786baecfSMauro Carvalho Chehab } else if (send_key >> 16 == startmarker1) {
400786baecfSMauro Carvalho Chehab send_key =
401786baecfSMauro Carvalho Chehab (send_key & 0xfffeffff) | (startmarker1 << 16);
402786baecfSMauro Carvalho Chehab break;
403786baecfSMauro Carvalho Chehab } else
404786baecfSMauro Carvalho Chehab send_key >>= 1;
405786baecfSMauro Carvalho Chehab }
406786baecfSMauro Carvalho Chehab
407786baecfSMauro Carvalho Chehab if (send_key == 0)
408786baecfSMauro Carvalho Chehab return 0;
409786baecfSMauro Carvalho Chehab
410786baecfSMauro Carvalho Chehab send_key = (send_key & 0xffff) | 0x0100;
411786baecfSMauro Carvalho Chehab
412786baecfSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(rc_map_opera1_table); i++) {
413786baecfSMauro Carvalho Chehab if (rc5_scan(&rc_map_opera1_table[i]) == (send_key & 0xffff)) {
414786baecfSMauro Carvalho Chehab *state = REMOTE_KEY_PRESSED;
415786baecfSMauro Carvalho Chehab *event = rc_map_opera1_table[i].keycode;
416786baecfSMauro Carvalho Chehab opst->last_key_pressed =
417786baecfSMauro Carvalho Chehab rc_map_opera1_table[i].keycode;
418786baecfSMauro Carvalho Chehab break;
419786baecfSMauro Carvalho Chehab }
420786baecfSMauro Carvalho Chehab opst->last_key_pressed = 0;
421786baecfSMauro Carvalho Chehab }
422786baecfSMauro Carvalho Chehab } else
423786baecfSMauro Carvalho Chehab *state = REMOTE_NO_KEY_PRESSED;
424786baecfSMauro Carvalho Chehab return 0;
425786baecfSMauro Carvalho Chehab }
426786baecfSMauro Carvalho Chehab
42722127ac8SMauro Carvalho Chehab enum {
42822127ac8SMauro Carvalho Chehab CYPRESS_OPERA1_COLD,
42922127ac8SMauro Carvalho Chehab OPERA1_WARM,
43022127ac8SMauro Carvalho Chehab };
43122127ac8SMauro Carvalho Chehab
432786baecfSMauro Carvalho Chehab static struct usb_device_id opera1_table[] = {
43322127ac8SMauro Carvalho Chehab DVB_USB_DEV(CYPRESS, CYPRESS_OPERA1_COLD),
43422127ac8SMauro Carvalho Chehab DVB_USB_DEV(OPERA1, OPERA1_WARM),
435786baecfSMauro Carvalho Chehab { }
436786baecfSMauro Carvalho Chehab };
437786baecfSMauro Carvalho Chehab
438786baecfSMauro Carvalho Chehab MODULE_DEVICE_TABLE(usb, opera1_table);
439786baecfSMauro Carvalho Chehab
opera1_read_mac_address(struct dvb_usb_device * d,u8 mac[6])440786baecfSMauro Carvalho Chehab static int opera1_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
441786baecfSMauro Carvalho Chehab {
442*f7e0f1f5SZhang Shurong int ret;
443786baecfSMauro Carvalho Chehab u8 command[] = { READ_MAC_ADDR };
444*f7e0f1f5SZhang Shurong ret = opera1_xilinx_rw(d->udev, 0xb1, 0xa0, command, 1, OPERA_WRITE_MSG);
445*f7e0f1f5SZhang Shurong if (ret)
446*f7e0f1f5SZhang Shurong return ret;
447*f7e0f1f5SZhang Shurong ret = opera1_xilinx_rw(d->udev, 0xb1, 0xa1, mac, 6, OPERA_READ_MSG);
448*f7e0f1f5SZhang Shurong if (ret)
449*f7e0f1f5SZhang Shurong return ret;
450786baecfSMauro Carvalho Chehab return 0;
451786baecfSMauro Carvalho Chehab }
opera1_xilinx_load_firmware(struct usb_device * dev,const char * filename)452786baecfSMauro Carvalho Chehab static int opera1_xilinx_load_firmware(struct usb_device *dev,
453786baecfSMauro Carvalho Chehab const char *filename)
454786baecfSMauro Carvalho Chehab {
455786baecfSMauro Carvalho Chehab const struct firmware *fw = NULL;
456786baecfSMauro Carvalho Chehab u8 *b, *p;
457786baecfSMauro Carvalho Chehab int ret = 0, i,fpgasize=40;
458786baecfSMauro Carvalho Chehab u8 testval;
459786baecfSMauro Carvalho Chehab info("start downloading fpga firmware %s",filename);
460786baecfSMauro Carvalho Chehab
461786baecfSMauro Carvalho Chehab if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) {
462fe63a1a6SMauro Carvalho Chehab err("did not find the firmware file '%s'. You can use <kernel_dir>/scripts/get_dvb_firmware to get the firmware",
463786baecfSMauro Carvalho Chehab filename);
464786baecfSMauro Carvalho Chehab return ret;
465786baecfSMauro Carvalho Chehab } else {
466786baecfSMauro Carvalho Chehab p = kmalloc(fw->size, GFP_KERNEL);
467786baecfSMauro Carvalho Chehab opera1_xilinx_rw(dev, 0xbc, 0x00, &testval, 1, OPERA_READ_MSG);
468786baecfSMauro Carvalho Chehab if (p != NULL && testval != 0x67) {
469786baecfSMauro Carvalho Chehab
470786baecfSMauro Carvalho Chehab u8 reset = 0, fpga_command = 0;
471786baecfSMauro Carvalho Chehab memcpy(p, fw->data, fw->size);
472786baecfSMauro Carvalho Chehab /* clear fpga ? */
473786baecfSMauro Carvalho Chehab opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1,
474786baecfSMauro Carvalho Chehab OPERA_WRITE_MSG);
475786baecfSMauro Carvalho Chehab for (i = 0; i < fw->size;) {
476786baecfSMauro Carvalho Chehab if ( (fw->size - i) <fpgasize){
477786baecfSMauro Carvalho Chehab fpgasize=fw->size-i;
478786baecfSMauro Carvalho Chehab }
479786baecfSMauro Carvalho Chehab b = (u8 *) p + i;
480786baecfSMauro Carvalho Chehab if (opera1_xilinx_rw
481786baecfSMauro Carvalho Chehab (dev, OPERA_WRITE_FX2, 0x0, b , fpgasize,
482786baecfSMauro Carvalho Chehab OPERA_WRITE_MSG) != fpgasize
483786baecfSMauro Carvalho Chehab ) {
484786baecfSMauro Carvalho Chehab err("error while transferring firmware");
485786baecfSMauro Carvalho Chehab ret = -EINVAL;
486786baecfSMauro Carvalho Chehab break;
487786baecfSMauro Carvalho Chehab }
488786baecfSMauro Carvalho Chehab i = i + fpgasize;
489786baecfSMauro Carvalho Chehab }
490786baecfSMauro Carvalho Chehab /* restart the CPU */
491786baecfSMauro Carvalho Chehab if (ret || opera1_xilinx_rw
492786baecfSMauro Carvalho Chehab (dev, 0xa0, 0xe600, &reset, 1,
493786baecfSMauro Carvalho Chehab OPERA_WRITE_MSG) != 1) {
494786baecfSMauro Carvalho Chehab err("could not restart the USB controller CPU.");
495786baecfSMauro Carvalho Chehab ret = -EINVAL;
496786baecfSMauro Carvalho Chehab }
497786baecfSMauro Carvalho Chehab }
498786baecfSMauro Carvalho Chehab }
499786baecfSMauro Carvalho Chehab kfree(p);
500786baecfSMauro Carvalho Chehab release_firmware(fw);
501786baecfSMauro Carvalho Chehab return ret;
502786baecfSMauro Carvalho Chehab }
503786baecfSMauro Carvalho Chehab
504786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties opera1_properties = {
505786baecfSMauro Carvalho Chehab .caps = DVB_USB_IS_AN_I2C_ADAPTER,
506786baecfSMauro Carvalho Chehab .usb_ctrl = CYPRESS_FX2,
507786baecfSMauro Carvalho Chehab .firmware = "dvb-usb-opera-01.fw",
508786baecfSMauro Carvalho Chehab .size_of_priv = sizeof(struct opera1_state),
509786baecfSMauro Carvalho Chehab
510786baecfSMauro Carvalho Chehab .power_ctrl = opera1_power_ctrl,
511786baecfSMauro Carvalho Chehab .i2c_algo = &opera1_i2c_algo,
512786baecfSMauro Carvalho Chehab
513786baecfSMauro Carvalho Chehab .rc.legacy = {
514786baecfSMauro Carvalho Chehab .rc_map_table = rc_map_opera1_table,
515786baecfSMauro Carvalho Chehab .rc_map_size = ARRAY_SIZE(rc_map_opera1_table),
516786baecfSMauro Carvalho Chehab .rc_interval = 200,
517786baecfSMauro Carvalho Chehab .rc_query = opera1_rc_query,
518786baecfSMauro Carvalho Chehab },
519786baecfSMauro Carvalho Chehab .read_mac_address = opera1_read_mac_address,
520786baecfSMauro Carvalho Chehab .generic_bulk_ctrl_endpoint = 0x00,
521786baecfSMauro Carvalho Chehab /* parameter for the MPEG2-data transfer */
522786baecfSMauro Carvalho Chehab .num_adapters = 1,
523786baecfSMauro Carvalho Chehab .adapter = {
524786baecfSMauro Carvalho Chehab {
525786baecfSMauro Carvalho Chehab .num_frontends = 1,
526786baecfSMauro Carvalho Chehab .fe = {{
527786baecfSMauro Carvalho Chehab .frontend_attach = opera1_frontend_attach,
528786baecfSMauro Carvalho Chehab .streaming_ctrl = opera1_streaming_ctrl,
529786baecfSMauro Carvalho Chehab .tuner_attach = opera1_tuner_attach,
530786baecfSMauro Carvalho Chehab .caps =
531786baecfSMauro Carvalho Chehab DVB_USB_ADAP_HAS_PID_FILTER |
532786baecfSMauro Carvalho Chehab DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
533786baecfSMauro Carvalho Chehab .pid_filter = opera1_pid_filter,
534786baecfSMauro Carvalho Chehab .pid_filter_ctrl = opera1_pid_filter_control,
535786baecfSMauro Carvalho Chehab .pid_filter_count = 252,
536786baecfSMauro Carvalho Chehab .stream = {
537786baecfSMauro Carvalho Chehab .type = USB_BULK,
538786baecfSMauro Carvalho Chehab .count = 10,
539786baecfSMauro Carvalho Chehab .endpoint = 0x82,
540786baecfSMauro Carvalho Chehab .u = {
541786baecfSMauro Carvalho Chehab .bulk = {
542786baecfSMauro Carvalho Chehab .buffersize = 4096,
543786baecfSMauro Carvalho Chehab }
544786baecfSMauro Carvalho Chehab }
545786baecfSMauro Carvalho Chehab },
546786baecfSMauro Carvalho Chehab }},
547786baecfSMauro Carvalho Chehab }
548786baecfSMauro Carvalho Chehab },
549786baecfSMauro Carvalho Chehab .num_device_descs = 1,
550786baecfSMauro Carvalho Chehab .devices = {
551786baecfSMauro Carvalho Chehab {"Opera1 DVB-S USB2.0",
55222127ac8SMauro Carvalho Chehab {&opera1_table[CYPRESS_OPERA1_COLD], NULL},
55322127ac8SMauro Carvalho Chehab {&opera1_table[OPERA1_WARM], NULL},
554786baecfSMauro Carvalho Chehab },
555786baecfSMauro Carvalho Chehab }
556786baecfSMauro Carvalho Chehab };
557786baecfSMauro Carvalho Chehab
opera1_probe(struct usb_interface * intf,const struct usb_device_id * id)558786baecfSMauro Carvalho Chehab static int opera1_probe(struct usb_interface *intf,
559786baecfSMauro Carvalho Chehab const struct usb_device_id *id)
560786baecfSMauro Carvalho Chehab {
561786baecfSMauro Carvalho Chehab struct usb_device *udev = interface_to_usbdev(intf);
562786baecfSMauro Carvalho Chehab
56318d6a28aSHans Verkuil if (le16_to_cpu(udev->descriptor.idProduct) == USB_PID_OPERA1_WARM &&
56418d6a28aSHans Verkuil le16_to_cpu(udev->descriptor.idVendor) == USB_VID_OPERA1 &&
565786baecfSMauro Carvalho Chehab opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0
566786baecfSMauro Carvalho Chehab ) {
567786baecfSMauro Carvalho Chehab return -EINVAL;
568786baecfSMauro Carvalho Chehab }
569786baecfSMauro Carvalho Chehab
570786baecfSMauro Carvalho Chehab if (0 != dvb_usb_device_init(intf, &opera1_properties,
571786baecfSMauro Carvalho Chehab THIS_MODULE, NULL, adapter_nr))
572786baecfSMauro Carvalho Chehab return -EINVAL;
573786baecfSMauro Carvalho Chehab return 0;
574786baecfSMauro Carvalho Chehab }
575786baecfSMauro Carvalho Chehab
576786baecfSMauro Carvalho Chehab static struct usb_driver opera1_driver = {
577786baecfSMauro Carvalho Chehab .name = "opera1",
578786baecfSMauro Carvalho Chehab .probe = opera1_probe,
579786baecfSMauro Carvalho Chehab .disconnect = dvb_usb_device_exit,
580786baecfSMauro Carvalho Chehab .id_table = opera1_table,
581786baecfSMauro Carvalho Chehab };
582786baecfSMauro Carvalho Chehab
583786baecfSMauro Carvalho Chehab module_usb_driver(opera1_driver);
584786baecfSMauro Carvalho Chehab
585786baecfSMauro Carvalho Chehab MODULE_AUTHOR("Mario Hlawitschka (c) dh1pa@amsat.org");
586786baecfSMauro Carvalho Chehab MODULE_AUTHOR("Marco Gittler (c) g.marco@freenet.de");
587786baecfSMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for Opera1 DVB-S device");
588786baecfSMauro Carvalho Chehab MODULE_VERSION("0.1");
589786baecfSMauro Carvalho Chehab MODULE_LICENSE("GPL");
590