xref: /linux/drivers/media/usb/dvb-usb-v2/dvbsky.c (revision 82b65714)
1af64fb3fSnibble.max /*
2af64fb3fSnibble.max  * Driver for DVBSky USB2.0 receiver
3af64fb3fSnibble.max  *
4af64fb3fSnibble.max  * Copyright (C) 2013 Max nibble <nibble.max@gmail.com>
5af64fb3fSnibble.max  *
6af64fb3fSnibble.max  *    This program is free software; you can redistribute it and/or modify
7af64fb3fSnibble.max  *    it under the terms of the GNU General Public License as published by
8af64fb3fSnibble.max  *    the Free Software Foundation; either version 2 of the License, or
9af64fb3fSnibble.max  *    (at your option) any later version.
10af64fb3fSnibble.max  *
11af64fb3fSnibble.max  *    This program is distributed in the hope that it will be useful,
12af64fb3fSnibble.max  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
13af64fb3fSnibble.max  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14af64fb3fSnibble.max  *    GNU General Public License for more details.
15af64fb3fSnibble.max  *
16af64fb3fSnibble.max  *    You should have received a copy of the GNU General Public License
17af64fb3fSnibble.max  *    along with this program; if not, write to the Free Software
18af64fb3fSnibble.max  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19af64fb3fSnibble.max  */
20af64fb3fSnibble.max 
21af64fb3fSnibble.max #include "dvb_usb.h"
22af64fb3fSnibble.max #include "m88ds3103.h"
23f31a6386SAntti Palosaari #include "ts2020.h"
2424d333f3Snibble.max #include "sp2.h"
25b43a590dSNibble Max #include "si2168.h"
26b43a590dSNibble Max #include "si2157.h"
27af64fb3fSnibble.max 
28af64fb3fSnibble.max #define DVBSKY_MSG_DELAY	0/*2000*/
29af64fb3fSnibble.max #define DVBSKY_BUF_LEN	64
30af64fb3fSnibble.max 
3169e7b650SOlli Salonen static int dvb_usb_dvbsky_disable_rc;
3269e7b650SOlli Salonen module_param_named(disable_rc, dvb_usb_dvbsky_disable_rc, int, 0644);
3369e7b650SOlli Salonen MODULE_PARM_DESC(disable_rc, "Disable inbuilt IR receiver.");
3469e7b650SOlli Salonen 
35af64fb3fSnibble.max DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
36af64fb3fSnibble.max 
37af64fb3fSnibble.max struct dvbsky_state {
38af64fb3fSnibble.max 	struct mutex stream_mutex;
39af64fb3fSnibble.max 	u8 ibuf[DVBSKY_BUF_LEN];
40af64fb3fSnibble.max 	u8 obuf[DVBSKY_BUF_LEN];
41af64fb3fSnibble.max 	u8 last_lock;
42b43a590dSNibble Max 	struct i2c_client *i2c_client_demod;
43af64fb3fSnibble.max 	struct i2c_client *i2c_client_tuner;
4424d333f3Snibble.max 	struct i2c_client *i2c_client_ci;
45af64fb3fSnibble.max 
46af64fb3fSnibble.max 	/* fe hook functions*/
47af64fb3fSnibble.max 	int (*fe_set_voltage)(struct dvb_frontend *fe,
480df289a2SMauro Carvalho Chehab 		enum fe_sec_voltage voltage);
49af64fb3fSnibble.max 	int (*fe_read_status)(struct dvb_frontend *fe,
500df289a2SMauro Carvalho Chehab 		enum fe_status *status);
51af64fb3fSnibble.max };
52af64fb3fSnibble.max 
53af64fb3fSnibble.max static int dvbsky_usb_generic_rw(struct dvb_usb_device *d,
54af64fb3fSnibble.max 		u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
55af64fb3fSnibble.max {
56af64fb3fSnibble.max 	int ret;
57af64fb3fSnibble.max 	struct dvbsky_state *state = d_to_priv(d);
58af64fb3fSnibble.max 
59af64fb3fSnibble.max 	mutex_lock(&d->usb_mutex);
60af64fb3fSnibble.max 	if (wlen != 0)
61af64fb3fSnibble.max 		memcpy(state->obuf, wbuf, wlen);
62af64fb3fSnibble.max 
63af64fb3fSnibble.max 	ret = dvb_usbv2_generic_rw_locked(d, state->obuf, wlen,
64af64fb3fSnibble.max 			state->ibuf, rlen);
65af64fb3fSnibble.max 
66af64fb3fSnibble.max 	if (!ret && (rlen != 0))
67af64fb3fSnibble.max 		memcpy(rbuf, state->ibuf, rlen);
68af64fb3fSnibble.max 
69af64fb3fSnibble.max 	mutex_unlock(&d->usb_mutex);
70af64fb3fSnibble.max 	return ret;
71af64fb3fSnibble.max }
72af64fb3fSnibble.max 
73af64fb3fSnibble.max static int dvbsky_stream_ctrl(struct dvb_usb_device *d, u8 onoff)
74af64fb3fSnibble.max {
75af64fb3fSnibble.max 	struct dvbsky_state *state = d_to_priv(d);
76af64fb3fSnibble.max 	int ret;
77af64fb3fSnibble.max 	u8 obuf_pre[3] = { 0x37, 0, 0 };
78af64fb3fSnibble.max 	u8 obuf_post[3] = { 0x36, 3, 0 };
79af64fb3fSnibble.max 
80af64fb3fSnibble.max 	mutex_lock(&state->stream_mutex);
81af64fb3fSnibble.max 	ret = dvbsky_usb_generic_rw(d, obuf_pre, 3, NULL, 0);
82af64fb3fSnibble.max 	if (!ret && onoff) {
83af64fb3fSnibble.max 		msleep(20);
84af64fb3fSnibble.max 		ret = dvbsky_usb_generic_rw(d, obuf_post, 3, NULL, 0);
85af64fb3fSnibble.max 	}
86af64fb3fSnibble.max 	mutex_unlock(&state->stream_mutex);
87af64fb3fSnibble.max 	return ret;
88af64fb3fSnibble.max }
89af64fb3fSnibble.max 
90af64fb3fSnibble.max static int dvbsky_streaming_ctrl(struct dvb_frontend *fe, int onoff)
91af64fb3fSnibble.max {
92af64fb3fSnibble.max 	struct dvb_usb_device *d = fe_to_d(fe);
93af64fb3fSnibble.max 
94af64fb3fSnibble.max 	return dvbsky_stream_ctrl(d, (onoff == 0) ? 0 : 1);
95af64fb3fSnibble.max }
96af64fb3fSnibble.max 
97af64fb3fSnibble.max /* GPIO */
98af64fb3fSnibble.max static int dvbsky_gpio_ctrl(struct dvb_usb_device *d, u8 gport, u8 value)
99af64fb3fSnibble.max {
100af64fb3fSnibble.max 	int ret;
101af64fb3fSnibble.max 	u8 obuf[3], ibuf[2];
102af64fb3fSnibble.max 
103af64fb3fSnibble.max 	obuf[0] = 0x0e;
104af64fb3fSnibble.max 	obuf[1] = gport;
105af64fb3fSnibble.max 	obuf[2] = value;
106af64fb3fSnibble.max 	ret = dvbsky_usb_generic_rw(d, obuf, 3, ibuf, 1);
107af64fb3fSnibble.max 	if (ret)
10840bba097SOlli Salonen 		dev_err(&d->udev->dev, "failed=%d\n", ret);
109af64fb3fSnibble.max 	return ret;
110af64fb3fSnibble.max }
111af64fb3fSnibble.max 
112af64fb3fSnibble.max /* I2C */
113af64fb3fSnibble.max static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
114af64fb3fSnibble.max 	int num)
115af64fb3fSnibble.max {
116af64fb3fSnibble.max 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
117af64fb3fSnibble.max 	int ret = 0;
118af64fb3fSnibble.max 	u8 ibuf[64], obuf[64];
119af64fb3fSnibble.max 
120af64fb3fSnibble.max 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
121af64fb3fSnibble.max 		return -EAGAIN;
122af64fb3fSnibble.max 
123af64fb3fSnibble.max 	if (num > 2) {
124af64fb3fSnibble.max 		dev_err(&d->udev->dev,
12540bba097SOlli Salonen 		"too many i2c messages[%d], max 2.", num);
126af64fb3fSnibble.max 		ret = -EOPNOTSUPP;
127af64fb3fSnibble.max 		goto i2c_error;
128af64fb3fSnibble.max 	}
129af64fb3fSnibble.max 
130af64fb3fSnibble.max 	if (num == 1) {
131af64fb3fSnibble.max 		if (msg[0].len > 60) {
132af64fb3fSnibble.max 			dev_err(&d->udev->dev,
13340bba097SOlli Salonen 			"too many i2c bytes[%d], max 60.",
134af64fb3fSnibble.max 			msg[0].len);
135af64fb3fSnibble.max 			ret = -EOPNOTSUPP;
136af64fb3fSnibble.max 			goto i2c_error;
137af64fb3fSnibble.max 		}
138af64fb3fSnibble.max 		if (msg[0].flags & I2C_M_RD) {
139af64fb3fSnibble.max 			/* single read */
140af64fb3fSnibble.max 			obuf[0] = 0x09;
141af64fb3fSnibble.max 			obuf[1] = 0;
142af64fb3fSnibble.max 			obuf[2] = msg[0].len;
143af64fb3fSnibble.max 			obuf[3] = msg[0].addr;
144af64fb3fSnibble.max 			ret = dvbsky_usb_generic_rw(d, obuf, 4,
145af64fb3fSnibble.max 					ibuf, msg[0].len + 1);
146af64fb3fSnibble.max 			if (ret)
14740bba097SOlli Salonen 				dev_err(&d->udev->dev, "failed=%d\n", ret);
148af64fb3fSnibble.max 			if (!ret)
149af64fb3fSnibble.max 				memcpy(msg[0].buf, &ibuf[1], msg[0].len);
150af64fb3fSnibble.max 		} else {
151af64fb3fSnibble.max 			/* write */
152af64fb3fSnibble.max 			obuf[0] = 0x08;
153af64fb3fSnibble.max 			obuf[1] = msg[0].addr;
154af64fb3fSnibble.max 			obuf[2] = msg[0].len;
155af64fb3fSnibble.max 			memcpy(&obuf[3], msg[0].buf, msg[0].len);
156af64fb3fSnibble.max 			ret = dvbsky_usb_generic_rw(d, obuf,
157af64fb3fSnibble.max 					msg[0].len + 3, ibuf, 1);
158af64fb3fSnibble.max 			if (ret)
15940bba097SOlli Salonen 				dev_err(&d->udev->dev, "failed=%d\n", ret);
160af64fb3fSnibble.max 		}
161af64fb3fSnibble.max 	} else {
162af64fb3fSnibble.max 		if ((msg[0].len > 60) || (msg[1].len > 60)) {
163af64fb3fSnibble.max 			dev_err(&d->udev->dev,
16440bba097SOlli Salonen 			"too many i2c bytes[w-%d][r-%d], max 60.",
165af64fb3fSnibble.max 			msg[0].len, msg[1].len);
166af64fb3fSnibble.max 			ret = -EOPNOTSUPP;
167af64fb3fSnibble.max 			goto i2c_error;
168af64fb3fSnibble.max 		}
169af64fb3fSnibble.max 		/* write then read */
170af64fb3fSnibble.max 		obuf[0] = 0x09;
171af64fb3fSnibble.max 		obuf[1] = msg[0].len;
172af64fb3fSnibble.max 		obuf[2] = msg[1].len;
173af64fb3fSnibble.max 		obuf[3] = msg[0].addr;
174af64fb3fSnibble.max 		memcpy(&obuf[4], msg[0].buf, msg[0].len);
175af64fb3fSnibble.max 		ret = dvbsky_usb_generic_rw(d, obuf,
176af64fb3fSnibble.max 			msg[0].len + 4, ibuf, msg[1].len + 1);
177af64fb3fSnibble.max 		if (ret)
17840bba097SOlli Salonen 			dev_err(&d->udev->dev, "failed=%d\n", ret);
179af64fb3fSnibble.max 
180af64fb3fSnibble.max 		if (!ret)
181af64fb3fSnibble.max 			memcpy(msg[1].buf, &ibuf[1], msg[1].len);
182af64fb3fSnibble.max 	}
183af64fb3fSnibble.max i2c_error:
184af64fb3fSnibble.max 	mutex_unlock(&d->i2c_mutex);
185af64fb3fSnibble.max 	return (ret) ? ret : num;
186af64fb3fSnibble.max }
187af64fb3fSnibble.max 
188af64fb3fSnibble.max static u32 dvbsky_i2c_func(struct i2c_adapter *adapter)
189af64fb3fSnibble.max {
190af64fb3fSnibble.max 	return I2C_FUNC_I2C;
191af64fb3fSnibble.max }
192af64fb3fSnibble.max 
193af64fb3fSnibble.max static struct i2c_algorithm dvbsky_i2c_algo = {
194af64fb3fSnibble.max 	.master_xfer   = dvbsky_i2c_xfer,
195af64fb3fSnibble.max 	.functionality = dvbsky_i2c_func,
196af64fb3fSnibble.max };
197af64fb3fSnibble.max 
198af64fb3fSnibble.max #if IS_ENABLED(CONFIG_RC_CORE)
199af64fb3fSnibble.max static int dvbsky_rc_query(struct dvb_usb_device *d)
200af64fb3fSnibble.max {
201af64fb3fSnibble.max 	u32 code = 0xffff, scancode;
202af64fb3fSnibble.max 	u8 rc5_command, rc5_system;
203af64fb3fSnibble.max 	u8 obuf[2], ibuf[2], toggle;
204af64fb3fSnibble.max 	int ret;
205af64fb3fSnibble.max 
206af64fb3fSnibble.max 	obuf[0] = 0x10;
207af64fb3fSnibble.max 	ret = dvbsky_usb_generic_rw(d, obuf, 1, ibuf, 2);
208af64fb3fSnibble.max 	if (ret)
20940bba097SOlli Salonen 		dev_err(&d->udev->dev, "failed=%d\n", ret);
210af64fb3fSnibble.max 	if (ret == 0)
211af64fb3fSnibble.max 		code = (ibuf[0] << 8) | ibuf[1];
212af64fb3fSnibble.max 	if (code != 0xffff) {
213af64fb3fSnibble.max 		dev_dbg(&d->udev->dev, "rc code: %x\n", code);
214af64fb3fSnibble.max 		rc5_command = code & 0x3F;
215af64fb3fSnibble.max 		rc5_system = (code & 0x7C0) >> 6;
216af64fb3fSnibble.max 		toggle = (code & 0x800) ? 1 : 0;
217af64fb3fSnibble.max 		scancode = rc5_system << 8 | rc5_command;
218af64fb3fSnibble.max 		rc_keydown(d->rc_dev, RC_TYPE_RC5, scancode, toggle);
219af64fb3fSnibble.max 	}
220af64fb3fSnibble.max 	return 0;
221af64fb3fSnibble.max }
222af64fb3fSnibble.max 
223af64fb3fSnibble.max static int dvbsky_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
224af64fb3fSnibble.max {
22569e7b650SOlli Salonen 	if (dvb_usb_dvbsky_disable_rc) {
22669e7b650SOlli Salonen 		rc->map_name = NULL;
22769e7b650SOlli Salonen 		return 0;
22869e7b650SOlli Salonen 	}
22969e7b650SOlli Salonen 
230af64fb3fSnibble.max 	rc->allowed_protos = RC_BIT_RC5;
231af64fb3fSnibble.max 	rc->query          = dvbsky_rc_query;
232af64fb3fSnibble.max 	rc->interval       = 300;
233af64fb3fSnibble.max 	return 0;
234af64fb3fSnibble.max }
235af64fb3fSnibble.max #else
236af64fb3fSnibble.max 	#define dvbsky_get_rc_config NULL
237af64fb3fSnibble.max #endif
238af64fb3fSnibble.max 
239af64fb3fSnibble.max static int dvbsky_usb_set_voltage(struct dvb_frontend *fe,
2400df289a2SMauro Carvalho Chehab 	enum fe_sec_voltage voltage)
241af64fb3fSnibble.max {
242af64fb3fSnibble.max 	struct dvb_usb_device *d = fe_to_d(fe);
243af64fb3fSnibble.max 	struct dvbsky_state *state = d_to_priv(d);
244af64fb3fSnibble.max 	u8 value;
245af64fb3fSnibble.max 
246af64fb3fSnibble.max 	if (voltage == SEC_VOLTAGE_OFF)
247af64fb3fSnibble.max 		value = 0;
248af64fb3fSnibble.max 	else
249af64fb3fSnibble.max 		value = 1;
250af64fb3fSnibble.max 	dvbsky_gpio_ctrl(d, 0x80, value);
251af64fb3fSnibble.max 
252af64fb3fSnibble.max 	return state->fe_set_voltage(fe, voltage);
253af64fb3fSnibble.max }
254af64fb3fSnibble.max 
255af64fb3fSnibble.max static int dvbsky_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6])
256af64fb3fSnibble.max {
257af64fb3fSnibble.max 	struct dvb_usb_device *d = adap_to_d(adap);
258af64fb3fSnibble.max 	u8 obuf[] = { 0x1e, 0x00 };
259af64fb3fSnibble.max 	u8 ibuf[6] = { 0 };
260af64fb3fSnibble.max 	struct i2c_msg msg[] = {
261af64fb3fSnibble.max 		{
262af64fb3fSnibble.max 			.addr = 0x51,
263af64fb3fSnibble.max 			.flags = 0,
264af64fb3fSnibble.max 			.buf = obuf,
265af64fb3fSnibble.max 			.len = 2,
266af64fb3fSnibble.max 		}, {
267af64fb3fSnibble.max 			.addr = 0x51,
268af64fb3fSnibble.max 			.flags = I2C_M_RD,
269af64fb3fSnibble.max 			.buf = ibuf,
270af64fb3fSnibble.max 			.len = 6,
271af64fb3fSnibble.max 		}
272af64fb3fSnibble.max 	};
273af64fb3fSnibble.max 
274af64fb3fSnibble.max 	if (i2c_transfer(&d->i2c_adap, msg, 2) == 2)
275af64fb3fSnibble.max 		memcpy(mac, ibuf, 6);
276af64fb3fSnibble.max 
277af64fb3fSnibble.max 	return 0;
278af64fb3fSnibble.max }
279af64fb3fSnibble.max 
2800df289a2SMauro Carvalho Chehab static int dvbsky_usb_read_status(struct dvb_frontend *fe,
2810df289a2SMauro Carvalho Chehab 				  enum fe_status *status)
282af64fb3fSnibble.max {
283af64fb3fSnibble.max 	struct dvb_usb_device *d = fe_to_d(fe);
284af64fb3fSnibble.max 	struct dvbsky_state *state = d_to_priv(d);
285af64fb3fSnibble.max 	int ret;
286af64fb3fSnibble.max 
287af64fb3fSnibble.max 	ret = state->fe_read_status(fe, status);
288af64fb3fSnibble.max 
289af64fb3fSnibble.max 	/* it need resync slave fifo when signal change from unlock to lock.*/
290af64fb3fSnibble.max 	if ((*status & FE_HAS_LOCK) && (!state->last_lock))
291af64fb3fSnibble.max 		dvbsky_stream_ctrl(d, 1);
292af64fb3fSnibble.max 
293af64fb3fSnibble.max 	state->last_lock = (*status & FE_HAS_LOCK) ? 1 : 0;
294af64fb3fSnibble.max 	return ret;
295af64fb3fSnibble.max }
296af64fb3fSnibble.max 
297af64fb3fSnibble.max static const struct m88ds3103_config dvbsky_s960_m88ds3103_config = {
298af64fb3fSnibble.max 	.i2c_addr = 0x68,
299af64fb3fSnibble.max 	.clock = 27000000,
300af64fb3fSnibble.max 	.i2c_wr_max = 33,
301af64fb3fSnibble.max 	.clock_out = 0,
302af64fb3fSnibble.max 	.ts_mode = M88DS3103_TS_CI,
303af64fb3fSnibble.max 	.ts_clk = 16000,
304af64fb3fSnibble.max 	.ts_clk_pol = 0,
305af64fb3fSnibble.max 	.agc = 0x99,
306af64fb3fSnibble.max 	.lnb_hv_pol = 1,
307af64fb3fSnibble.max 	.lnb_en_pol = 1,
308af64fb3fSnibble.max };
309af64fb3fSnibble.max 
310af64fb3fSnibble.max static int dvbsky_s960_attach(struct dvb_usb_adapter *adap)
311af64fb3fSnibble.max {
312af64fb3fSnibble.max 	struct dvbsky_state *state = adap_to_priv(adap);
313af64fb3fSnibble.max 	struct dvb_usb_device *d = adap_to_d(adap);
314af64fb3fSnibble.max 	int ret = 0;
315af64fb3fSnibble.max 	/* demod I2C adapter */
316af64fb3fSnibble.max 	struct i2c_adapter *i2c_adapter;
317af64fb3fSnibble.max 	struct i2c_client *client;
318af64fb3fSnibble.max 	struct i2c_board_info info;
319f31a6386SAntti Palosaari 	struct ts2020_config ts2020_config = {};
320af64fb3fSnibble.max 	memset(&info, 0, sizeof(struct i2c_board_info));
321af64fb3fSnibble.max 
322af64fb3fSnibble.max 	/* attach demod */
323af64fb3fSnibble.max 	adap->fe[0] = dvb_attach(m88ds3103_attach,
324af64fb3fSnibble.max 			&dvbsky_s960_m88ds3103_config,
325af64fb3fSnibble.max 			&d->i2c_adap,
326af64fb3fSnibble.max 			&i2c_adapter);
327af64fb3fSnibble.max 	if (!adap->fe[0]) {
328af64fb3fSnibble.max 		dev_err(&d->udev->dev, "dvbsky_s960_attach fail.\n");
329af64fb3fSnibble.max 		ret = -ENODEV;
330af64fb3fSnibble.max 		goto fail_attach;
331af64fb3fSnibble.max 	}
332af64fb3fSnibble.max 
333af64fb3fSnibble.max 	/* attach tuner */
334f31a6386SAntti Palosaari 	ts2020_config.fe = adap->fe[0];
3350f91c9d6SDavid Howells 	ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm;
336f31a6386SAntti Palosaari 	strlcpy(info.type, "ts2020", I2C_NAME_SIZE);
337af64fb3fSnibble.max 	info.addr = 0x60;
338f31a6386SAntti Palosaari 	info.platform_data = &ts2020_config;
339f31a6386SAntti Palosaari 	request_module("ts2020");
340af64fb3fSnibble.max 	client = i2c_new_device(i2c_adapter, &info);
341af64fb3fSnibble.max 	if (client == NULL || client->dev.driver == NULL) {
342af64fb3fSnibble.max 		dvb_frontend_detach(adap->fe[0]);
343af64fb3fSnibble.max 		ret = -ENODEV;
344af64fb3fSnibble.max 		goto fail_attach;
345af64fb3fSnibble.max 	}
346af64fb3fSnibble.max 
347af64fb3fSnibble.max 	if (!try_module_get(client->dev.driver->owner)) {
348af64fb3fSnibble.max 		i2c_unregister_device(client);
349af64fb3fSnibble.max 		dvb_frontend_detach(adap->fe[0]);
350af64fb3fSnibble.max 		ret = -ENODEV;
351af64fb3fSnibble.max 		goto fail_attach;
352af64fb3fSnibble.max 	}
353af64fb3fSnibble.max 
354af64fb3fSnibble.max 	/* delegate signal strength measurement to tuner */
355af64fb3fSnibble.max 	adap->fe[0]->ops.read_signal_strength =
356af64fb3fSnibble.max 			adap->fe[0]->ops.tuner_ops.get_rf_strength;
357af64fb3fSnibble.max 
358af64fb3fSnibble.max 	/* hook fe: need to resync the slave fifo when signal locks. */
359af64fb3fSnibble.max 	state->fe_read_status = adap->fe[0]->ops.read_status;
360af64fb3fSnibble.max 	adap->fe[0]->ops.read_status = dvbsky_usb_read_status;
361af64fb3fSnibble.max 
362af64fb3fSnibble.max 	/* hook fe: LNB off/on is control by Cypress usb chip. */
363af64fb3fSnibble.max 	state->fe_set_voltage = adap->fe[0]->ops.set_voltage;
364af64fb3fSnibble.max 	adap->fe[0]->ops.set_voltage = dvbsky_usb_set_voltage;
365af64fb3fSnibble.max 
366af64fb3fSnibble.max 	state->i2c_client_tuner = client;
367af64fb3fSnibble.max 
368af64fb3fSnibble.max fail_attach:
369af64fb3fSnibble.max 	return ret;
370af64fb3fSnibble.max }
371af64fb3fSnibble.max 
37224d333f3Snibble.max static int dvbsky_usb_ci_set_voltage(struct dvb_frontend *fe,
3730df289a2SMauro Carvalho Chehab 	enum fe_sec_voltage voltage)
37424d333f3Snibble.max {
37524d333f3Snibble.max 	struct dvb_usb_device *d = fe_to_d(fe);
37624d333f3Snibble.max 	struct dvbsky_state *state = d_to_priv(d);
37724d333f3Snibble.max 	u8 value;
37824d333f3Snibble.max 
37924d333f3Snibble.max 	if (voltage == SEC_VOLTAGE_OFF)
38024d333f3Snibble.max 		value = 0;
38124d333f3Snibble.max 	else
38224d333f3Snibble.max 		value = 1;
38324d333f3Snibble.max 	dvbsky_gpio_ctrl(d, 0x00, value);
38424d333f3Snibble.max 
38524d333f3Snibble.max 	return state->fe_set_voltage(fe, voltage);
38624d333f3Snibble.max }
38724d333f3Snibble.max 
38824d333f3Snibble.max static int dvbsky_ci_ctrl(void *priv, u8 read, int addr,
38924d333f3Snibble.max 					u8 data, int *mem)
39024d333f3Snibble.max {
39124d333f3Snibble.max 	struct dvb_usb_device *d = priv;
39224d333f3Snibble.max 	int ret = 0;
39324d333f3Snibble.max 	u8 command[4], respond[2], command_size, respond_size;
39424d333f3Snibble.max 
39524d333f3Snibble.max 	command[1] = (u8)((addr >> 8) & 0xff); /*high part of address*/
39624d333f3Snibble.max 	command[2] = (u8)(addr & 0xff); /*low part of address*/
39724d333f3Snibble.max 	if (read) {
39824d333f3Snibble.max 		command[0] = 0x71;
39924d333f3Snibble.max 		command_size = 3;
40024d333f3Snibble.max 		respond_size = 2;
40124d333f3Snibble.max 	} else {
40224d333f3Snibble.max 		command[0] = 0x70;
40324d333f3Snibble.max 		command[3] = data;
40424d333f3Snibble.max 		command_size = 4;
40524d333f3Snibble.max 		respond_size = 1;
40624d333f3Snibble.max 	}
40724d333f3Snibble.max 	ret = dvbsky_usb_generic_rw(d, command, command_size,
40824d333f3Snibble.max 			respond, respond_size);
40924d333f3Snibble.max 	if (ret)
41024d333f3Snibble.max 		goto err;
41124d333f3Snibble.max 	if (read)
41224d333f3Snibble.max 		*mem = respond[1];
41324d333f3Snibble.max 	return ret;
41424d333f3Snibble.max err:
41524d333f3Snibble.max 	dev_err(&d->udev->dev, "ci control failed=%d\n", ret);
41624d333f3Snibble.max 	return ret;
41724d333f3Snibble.max }
41824d333f3Snibble.max 
41924d333f3Snibble.max static const struct m88ds3103_config dvbsky_s960c_m88ds3103_config = {
42024d333f3Snibble.max 	.i2c_addr = 0x68,
42124d333f3Snibble.max 	.clock = 27000000,
42224d333f3Snibble.max 	.i2c_wr_max = 33,
42324d333f3Snibble.max 	.clock_out = 0,
42424d333f3Snibble.max 	.ts_mode = M88DS3103_TS_CI,
42524d333f3Snibble.max 	.ts_clk = 10000,
42624d333f3Snibble.max 	.ts_clk_pol = 1,
42724d333f3Snibble.max 	.agc = 0x99,
42824d333f3Snibble.max 	.lnb_hv_pol = 0,
42924d333f3Snibble.max 	.lnb_en_pol = 1,
43024d333f3Snibble.max };
43124d333f3Snibble.max 
43224d333f3Snibble.max static int dvbsky_s960c_attach(struct dvb_usb_adapter *adap)
43324d333f3Snibble.max {
43424d333f3Snibble.max 	struct dvbsky_state *state = adap_to_priv(adap);
43524d333f3Snibble.max 	struct dvb_usb_device *d = adap_to_d(adap);
43624d333f3Snibble.max 	int ret = 0;
43724d333f3Snibble.max 	/* demod I2C adapter */
43824d333f3Snibble.max 	struct i2c_adapter *i2c_adapter;
43924d333f3Snibble.max 	struct i2c_client *client_tuner, *client_ci;
44024d333f3Snibble.max 	struct i2c_board_info info;
44124d333f3Snibble.max 	struct sp2_config sp2_config;
442f31a6386SAntti Palosaari 	struct ts2020_config ts2020_config = {};
44324d333f3Snibble.max 	memset(&info, 0, sizeof(struct i2c_board_info));
44424d333f3Snibble.max 
44524d333f3Snibble.max 	/* attach demod */
44624d333f3Snibble.max 	adap->fe[0] = dvb_attach(m88ds3103_attach,
44724d333f3Snibble.max 			&dvbsky_s960c_m88ds3103_config,
44824d333f3Snibble.max 			&d->i2c_adap,
44924d333f3Snibble.max 			&i2c_adapter);
45024d333f3Snibble.max 	if (!adap->fe[0]) {
45124d333f3Snibble.max 		dev_err(&d->udev->dev, "dvbsky_s960ci_attach fail.\n");
45224d333f3Snibble.max 		ret = -ENODEV;
45324d333f3Snibble.max 		goto fail_attach;
45424d333f3Snibble.max 	}
45524d333f3Snibble.max 
45624d333f3Snibble.max 	/* attach tuner */
457f31a6386SAntti Palosaari 	ts2020_config.fe = adap->fe[0];
4580f91c9d6SDavid Howells 	ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm;
459f31a6386SAntti Palosaari 	strlcpy(info.type, "ts2020", I2C_NAME_SIZE);
46024d333f3Snibble.max 	info.addr = 0x60;
461f31a6386SAntti Palosaari 	info.platform_data = &ts2020_config;
462f31a6386SAntti Palosaari 	request_module("ts2020");
46324d333f3Snibble.max 	client_tuner = i2c_new_device(i2c_adapter, &info);
46424d333f3Snibble.max 	if (client_tuner == NULL || client_tuner->dev.driver == NULL) {
46524d333f3Snibble.max 		ret = -ENODEV;
46624d333f3Snibble.max 		goto fail_tuner_device;
46724d333f3Snibble.max 	}
46824d333f3Snibble.max 
46924d333f3Snibble.max 	if (!try_module_get(client_tuner->dev.driver->owner)) {
47024d333f3Snibble.max 		ret = -ENODEV;
47124d333f3Snibble.max 		goto fail_tuner_module;
47224d333f3Snibble.max 	}
47324d333f3Snibble.max 
47424d333f3Snibble.max 	/* attach ci controller */
47524d333f3Snibble.max 	memset(&sp2_config, 0, sizeof(sp2_config));
47624d333f3Snibble.max 	sp2_config.dvb_adap = &adap->dvb_adap;
47724d333f3Snibble.max 	sp2_config.priv = d;
47824d333f3Snibble.max 	sp2_config.ci_control = dvbsky_ci_ctrl;
47924d333f3Snibble.max 	memset(&info, 0, sizeof(struct i2c_board_info));
48024d333f3Snibble.max 	strlcpy(info.type, "sp2", I2C_NAME_SIZE);
48124d333f3Snibble.max 	info.addr = 0x40;
48224d333f3Snibble.max 	info.platform_data = &sp2_config;
48324d333f3Snibble.max 	request_module("sp2");
484dd0a6fe2Snibble.max 	client_ci = i2c_new_device(&d->i2c_adap, &info);
48524d333f3Snibble.max 	if (client_ci == NULL || client_ci->dev.driver == NULL) {
48624d333f3Snibble.max 		ret = -ENODEV;
48724d333f3Snibble.max 		goto fail_ci_device;
48824d333f3Snibble.max 	}
48924d333f3Snibble.max 
49024d333f3Snibble.max 	if (!try_module_get(client_ci->dev.driver->owner)) {
49124d333f3Snibble.max 		ret = -ENODEV;
49224d333f3Snibble.max 		goto fail_ci_module;
49324d333f3Snibble.max 	}
49424d333f3Snibble.max 
49524d333f3Snibble.max 	/* delegate signal strength measurement to tuner */
49624d333f3Snibble.max 	adap->fe[0]->ops.read_signal_strength =
49724d333f3Snibble.max 			adap->fe[0]->ops.tuner_ops.get_rf_strength;
49824d333f3Snibble.max 
49924d333f3Snibble.max 	/* hook fe: need to resync the slave fifo when signal locks. */
50024d333f3Snibble.max 	state->fe_read_status = adap->fe[0]->ops.read_status;
50124d333f3Snibble.max 	adap->fe[0]->ops.read_status = dvbsky_usb_read_status;
50224d333f3Snibble.max 
50324d333f3Snibble.max 	/* hook fe: LNB off/on is control by Cypress usb chip. */
50424d333f3Snibble.max 	state->fe_set_voltage = adap->fe[0]->ops.set_voltage;
50524d333f3Snibble.max 	adap->fe[0]->ops.set_voltage = dvbsky_usb_ci_set_voltage;
50624d333f3Snibble.max 
50724d333f3Snibble.max 	state->i2c_client_tuner = client_tuner;
50824d333f3Snibble.max 	state->i2c_client_ci = client_ci;
50924d333f3Snibble.max 	return ret;
51024d333f3Snibble.max fail_ci_module:
51124d333f3Snibble.max 	i2c_unregister_device(client_ci);
51224d333f3Snibble.max fail_ci_device:
51324d333f3Snibble.max 	module_put(client_tuner->dev.driver->owner);
51424d333f3Snibble.max fail_tuner_module:
51524d333f3Snibble.max 	i2c_unregister_device(client_tuner);
51624d333f3Snibble.max fail_tuner_device:
51724d333f3Snibble.max 	dvb_frontend_detach(adap->fe[0]);
51824d333f3Snibble.max fail_attach:
51924d333f3Snibble.max 	return ret;
52024d333f3Snibble.max }
52124d333f3Snibble.max 
522b43a590dSNibble Max static int dvbsky_t680c_attach(struct dvb_usb_adapter *adap)
523b43a590dSNibble Max {
524b43a590dSNibble Max 	struct dvbsky_state *state = adap_to_priv(adap);
525b43a590dSNibble Max 	struct dvb_usb_device *d = adap_to_d(adap);
526b43a590dSNibble Max 	int ret = 0;
527b43a590dSNibble Max 	struct i2c_adapter *i2c_adapter;
528b43a590dSNibble Max 	struct i2c_client *client_demod, *client_tuner, *client_ci;
529b43a590dSNibble Max 	struct i2c_board_info info;
530b43a590dSNibble Max 	struct si2168_config si2168_config;
531b43a590dSNibble Max 	struct si2157_config si2157_config;
532b43a590dSNibble Max 	struct sp2_config sp2_config;
533b43a590dSNibble Max 
534b43a590dSNibble Max 	/* attach demod */
535b43a590dSNibble Max 	memset(&si2168_config, 0, sizeof(si2168_config));
536b43a590dSNibble Max 	si2168_config.i2c_adapter = &i2c_adapter;
537b43a590dSNibble Max 	si2168_config.fe = &adap->fe[0];
538b43a590dSNibble Max 	si2168_config.ts_mode = SI2168_TS_PARALLEL;
539b43a590dSNibble Max 	memset(&info, 0, sizeof(struct i2c_board_info));
540b43a590dSNibble Max 	strlcpy(info.type, "si2168", I2C_NAME_SIZE);
541b43a590dSNibble Max 	info.addr = 0x64;
542b43a590dSNibble Max 	info.platform_data = &si2168_config;
543b43a590dSNibble Max 
544b43a590dSNibble Max 	request_module(info.type);
545b43a590dSNibble Max 	client_demod = i2c_new_device(&d->i2c_adap, &info);
546b43a590dSNibble Max 	if (client_demod == NULL ||
547b43a590dSNibble Max 			client_demod->dev.driver == NULL)
548b43a590dSNibble Max 		goto fail_demod_device;
549b43a590dSNibble Max 	if (!try_module_get(client_demod->dev.driver->owner))
550b43a590dSNibble Max 		goto fail_demod_module;
551b43a590dSNibble Max 
552b43a590dSNibble Max 	/* attach tuner */
553b43a590dSNibble Max 	memset(&si2157_config, 0, sizeof(si2157_config));
554b43a590dSNibble Max 	si2157_config.fe = adap->fe[0];
555ee3c3e46SOlli Salonen 	si2157_config.if_port = 1;
556b43a590dSNibble Max 	memset(&info, 0, sizeof(struct i2c_board_info));
557b43a590dSNibble Max 	strlcpy(info.type, "si2157", I2C_NAME_SIZE);
558b43a590dSNibble Max 	info.addr = 0x60;
559b43a590dSNibble Max 	info.platform_data = &si2157_config;
560b43a590dSNibble Max 
561b43a590dSNibble Max 	request_module(info.type);
562b43a590dSNibble Max 	client_tuner = i2c_new_device(i2c_adapter, &info);
563b43a590dSNibble Max 	if (client_tuner == NULL ||
564b43a590dSNibble Max 			client_tuner->dev.driver == NULL)
565b43a590dSNibble Max 		goto fail_tuner_device;
566b43a590dSNibble Max 	if (!try_module_get(client_tuner->dev.driver->owner))
567b43a590dSNibble Max 		goto fail_tuner_module;
568b43a590dSNibble Max 
569b43a590dSNibble Max 	/* attach ci controller */
570b43a590dSNibble Max 	memset(&sp2_config, 0, sizeof(sp2_config));
571b43a590dSNibble Max 	sp2_config.dvb_adap = &adap->dvb_adap;
572b43a590dSNibble Max 	sp2_config.priv = d;
573b43a590dSNibble Max 	sp2_config.ci_control = dvbsky_ci_ctrl;
574b43a590dSNibble Max 	memset(&info, 0, sizeof(struct i2c_board_info));
575b43a590dSNibble Max 	strlcpy(info.type, "sp2", I2C_NAME_SIZE);
576b43a590dSNibble Max 	info.addr = 0x40;
577b43a590dSNibble Max 	info.platform_data = &sp2_config;
578b43a590dSNibble Max 
579b43a590dSNibble Max 	request_module(info.type);
580b43a590dSNibble Max 	client_ci = i2c_new_device(&d->i2c_adap, &info);
581b43a590dSNibble Max 
582b43a590dSNibble Max 	if (client_ci == NULL || client_ci->dev.driver == NULL)
583b43a590dSNibble Max 		goto fail_ci_device;
584b43a590dSNibble Max 
585b43a590dSNibble Max 	if (!try_module_get(client_ci->dev.driver->owner))
586b43a590dSNibble Max 		goto fail_ci_module;
587b43a590dSNibble Max 
588b43a590dSNibble Max 	state->i2c_client_demod = client_demod;
589b43a590dSNibble Max 	state->i2c_client_tuner = client_tuner;
590b43a590dSNibble Max 	state->i2c_client_ci = client_ci;
591b43a590dSNibble Max 	return ret;
592b43a590dSNibble Max fail_ci_module:
593b43a590dSNibble Max 	i2c_unregister_device(client_ci);
594b43a590dSNibble Max fail_ci_device:
595b43a590dSNibble Max 	module_put(client_tuner->dev.driver->owner);
596b43a590dSNibble Max fail_tuner_module:
597b43a590dSNibble Max 	i2c_unregister_device(client_tuner);
598b43a590dSNibble Max fail_tuner_device:
599b43a590dSNibble Max 	module_put(client_demod->dev.driver->owner);
600b43a590dSNibble Max fail_demod_module:
601b43a590dSNibble Max 	i2c_unregister_device(client_demod);
602b43a590dSNibble Max fail_demod_device:
603b43a590dSNibble Max 	ret = -ENODEV;
604b43a590dSNibble Max 	return ret;
605b43a590dSNibble Max }
606b43a590dSNibble Max 
6070a5a4f32SNibble Max static int dvbsky_t330_attach(struct dvb_usb_adapter *adap)
6080a5a4f32SNibble Max {
6090a5a4f32SNibble Max 	struct dvbsky_state *state = adap_to_priv(adap);
6100a5a4f32SNibble Max 	struct dvb_usb_device *d = adap_to_d(adap);
6110a5a4f32SNibble Max 	int ret = 0;
6120a5a4f32SNibble Max 	struct i2c_adapter *i2c_adapter;
6130a5a4f32SNibble Max 	struct i2c_client *client_demod, *client_tuner;
6140a5a4f32SNibble Max 	struct i2c_board_info info;
6150a5a4f32SNibble Max 	struct si2168_config si2168_config;
6160a5a4f32SNibble Max 	struct si2157_config si2157_config;
6170a5a4f32SNibble Max 
6180a5a4f32SNibble Max 	/* attach demod */
6190a5a4f32SNibble Max 	memset(&si2168_config, 0, sizeof(si2168_config));
6200a5a4f32SNibble Max 	si2168_config.i2c_adapter = &i2c_adapter;
6210a5a4f32SNibble Max 	si2168_config.fe = &adap->fe[0];
622c060f932SOlli Salonen 	si2168_config.ts_mode = SI2168_TS_PARALLEL;
623c060f932SOlli Salonen 	si2168_config.ts_clock_gapped = true;
6240a5a4f32SNibble Max 	memset(&info, 0, sizeof(struct i2c_board_info));
6250a5a4f32SNibble Max 	strlcpy(info.type, "si2168", I2C_NAME_SIZE);
6260a5a4f32SNibble Max 	info.addr = 0x64;
6270a5a4f32SNibble Max 	info.platform_data = &si2168_config;
6280a5a4f32SNibble Max 
6290a5a4f32SNibble Max 	request_module(info.type);
6300a5a4f32SNibble Max 	client_demod = i2c_new_device(&d->i2c_adap, &info);
6310a5a4f32SNibble Max 	if (client_demod == NULL ||
6320a5a4f32SNibble Max 			client_demod->dev.driver == NULL)
6330a5a4f32SNibble Max 		goto fail_demod_device;
6340a5a4f32SNibble Max 	if (!try_module_get(client_demod->dev.driver->owner))
6350a5a4f32SNibble Max 		goto fail_demod_module;
6360a5a4f32SNibble Max 
6370a5a4f32SNibble Max 	/* attach tuner */
6380a5a4f32SNibble Max 	memset(&si2157_config, 0, sizeof(si2157_config));
6390a5a4f32SNibble Max 	si2157_config.fe = adap->fe[0];
640ee3c3e46SOlli Salonen 	si2157_config.if_port = 1;
6410a5a4f32SNibble Max 	memset(&info, 0, sizeof(struct i2c_board_info));
6420a5a4f32SNibble Max 	strlcpy(info.type, "si2157", I2C_NAME_SIZE);
6430a5a4f32SNibble Max 	info.addr = 0x60;
6440a5a4f32SNibble Max 	info.platform_data = &si2157_config;
6450a5a4f32SNibble Max 
6460a5a4f32SNibble Max 	request_module(info.type);
6470a5a4f32SNibble Max 	client_tuner = i2c_new_device(i2c_adapter, &info);
6480a5a4f32SNibble Max 	if (client_tuner == NULL ||
6490a5a4f32SNibble Max 			client_tuner->dev.driver == NULL)
6500a5a4f32SNibble Max 		goto fail_tuner_device;
6510a5a4f32SNibble Max 	if (!try_module_get(client_tuner->dev.driver->owner))
6520a5a4f32SNibble Max 		goto fail_tuner_module;
6530a5a4f32SNibble Max 
6540a5a4f32SNibble Max 	state->i2c_client_demod = client_demod;
6550a5a4f32SNibble Max 	state->i2c_client_tuner = client_tuner;
6560a5a4f32SNibble Max 	return ret;
6570a5a4f32SNibble Max fail_tuner_module:
6580a5a4f32SNibble Max 	i2c_unregister_device(client_tuner);
6590a5a4f32SNibble Max fail_tuner_device:
6600a5a4f32SNibble Max 	module_put(client_demod->dev.driver->owner);
6610a5a4f32SNibble Max fail_demod_module:
6620a5a4f32SNibble Max 	i2c_unregister_device(client_demod);
6630a5a4f32SNibble Max fail_demod_device:
6640a5a4f32SNibble Max 	ret = -ENODEV;
6650a5a4f32SNibble Max 	return ret;
6660a5a4f32SNibble Max }
6670a5a4f32SNibble Max 
668af64fb3fSnibble.max static int dvbsky_identify_state(struct dvb_usb_device *d, const char **name)
669af64fb3fSnibble.max {
670af64fb3fSnibble.max 	dvbsky_gpio_ctrl(d, 0x04, 1);
671af64fb3fSnibble.max 	msleep(20);
672af64fb3fSnibble.max 	dvbsky_gpio_ctrl(d, 0x83, 0);
673af64fb3fSnibble.max 	dvbsky_gpio_ctrl(d, 0xc0, 1);
674af64fb3fSnibble.max 	msleep(100);
675af64fb3fSnibble.max 	dvbsky_gpio_ctrl(d, 0x83, 1);
676af64fb3fSnibble.max 	dvbsky_gpio_ctrl(d, 0xc0, 0);
677af64fb3fSnibble.max 	msleep(50);
678af64fb3fSnibble.max 
679af64fb3fSnibble.max 	return WARM;
680af64fb3fSnibble.max }
681af64fb3fSnibble.max 
682af64fb3fSnibble.max static int dvbsky_init(struct dvb_usb_device *d)
683af64fb3fSnibble.max {
684af64fb3fSnibble.max 	struct dvbsky_state *state = d_to_priv(d);
685af64fb3fSnibble.max 
686af64fb3fSnibble.max 	/* use default interface */
687af64fb3fSnibble.max 	/*
688af64fb3fSnibble.max 	ret = usb_set_interface(d->udev, 0, 0);
689af64fb3fSnibble.max 	if (ret)
690af64fb3fSnibble.max 		return ret;
691af64fb3fSnibble.max 	*/
692af64fb3fSnibble.max 	mutex_init(&state->stream_mutex);
693af64fb3fSnibble.max 
694af64fb3fSnibble.max 	state->last_lock = 0;
695af64fb3fSnibble.max 
696af64fb3fSnibble.max 	return 0;
697af64fb3fSnibble.max }
698af64fb3fSnibble.max 
699af64fb3fSnibble.max static void dvbsky_exit(struct dvb_usb_device *d)
700af64fb3fSnibble.max {
701af64fb3fSnibble.max 	struct dvbsky_state *state = d_to_priv(d);
702af64fb3fSnibble.max 	struct i2c_client *client;
703af64fb3fSnibble.max 
704af64fb3fSnibble.max 	client = state->i2c_client_tuner;
705af64fb3fSnibble.max 	/* remove I2C tuner */
706af64fb3fSnibble.max 	if (client) {
707af64fb3fSnibble.max 		module_put(client->dev.driver->owner);
708af64fb3fSnibble.max 		i2c_unregister_device(client);
709af64fb3fSnibble.max 	}
710b43a590dSNibble Max 	client = state->i2c_client_demod;
711b43a590dSNibble Max 	/* remove I2C demod */
712b43a590dSNibble Max 	if (client) {
713b43a590dSNibble Max 		module_put(client->dev.driver->owner);
714b43a590dSNibble Max 		i2c_unregister_device(client);
715b43a590dSNibble Max 	}
71624d333f3Snibble.max 	client = state->i2c_client_ci;
71724d333f3Snibble.max 	/* remove I2C ci */
71824d333f3Snibble.max 	if (client) {
71924d333f3Snibble.max 		module_put(client->dev.driver->owner);
72024d333f3Snibble.max 		i2c_unregister_device(client);
72124d333f3Snibble.max 	}
722af64fb3fSnibble.max }
723af64fb3fSnibble.max 
724af64fb3fSnibble.max /* DVB USB Driver stuff */
725af64fb3fSnibble.max static struct dvb_usb_device_properties dvbsky_s960_props = {
726af64fb3fSnibble.max 	.driver_name = KBUILD_MODNAME,
727af64fb3fSnibble.max 	.owner = THIS_MODULE,
728af64fb3fSnibble.max 	.adapter_nr = adapter_nr,
729af64fb3fSnibble.max 	.size_of_priv = sizeof(struct dvbsky_state),
730af64fb3fSnibble.max 
731af64fb3fSnibble.max 	.generic_bulk_ctrl_endpoint = 0x01,
732af64fb3fSnibble.max 	.generic_bulk_ctrl_endpoint_response = 0x81,
733af64fb3fSnibble.max 	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
734af64fb3fSnibble.max 
735af64fb3fSnibble.max 	.i2c_algo         = &dvbsky_i2c_algo,
736af64fb3fSnibble.max 	.frontend_attach  = dvbsky_s960_attach,
737af64fb3fSnibble.max 	.init             = dvbsky_init,
738af64fb3fSnibble.max 	.get_rc_config    = dvbsky_get_rc_config,
739af64fb3fSnibble.max 	.streaming_ctrl   = dvbsky_streaming_ctrl,
740af64fb3fSnibble.max 	.identify_state	  = dvbsky_identify_state,
741af64fb3fSnibble.max 	.exit             = dvbsky_exit,
742af64fb3fSnibble.max 	.read_mac_address = dvbsky_read_mac_addr,
743af64fb3fSnibble.max 
744af64fb3fSnibble.max 	.num_adapters = 1,
745af64fb3fSnibble.max 	.adapter = {
746af64fb3fSnibble.max 		{
747af64fb3fSnibble.max 			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
748af64fb3fSnibble.max 		}
749af64fb3fSnibble.max 	}
750af64fb3fSnibble.max };
751af64fb3fSnibble.max 
75224d333f3Snibble.max static struct dvb_usb_device_properties dvbsky_s960c_props = {
75324d333f3Snibble.max 	.driver_name = KBUILD_MODNAME,
75424d333f3Snibble.max 	.owner = THIS_MODULE,
75524d333f3Snibble.max 	.adapter_nr = adapter_nr,
75624d333f3Snibble.max 	.size_of_priv = sizeof(struct dvbsky_state),
75724d333f3Snibble.max 
75824d333f3Snibble.max 	.generic_bulk_ctrl_endpoint = 0x01,
75924d333f3Snibble.max 	.generic_bulk_ctrl_endpoint_response = 0x81,
76024d333f3Snibble.max 	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
76124d333f3Snibble.max 
76224d333f3Snibble.max 	.i2c_algo         = &dvbsky_i2c_algo,
76324d333f3Snibble.max 	.frontend_attach  = dvbsky_s960c_attach,
76424d333f3Snibble.max 	.init             = dvbsky_init,
76524d333f3Snibble.max 	.get_rc_config    = dvbsky_get_rc_config,
76624d333f3Snibble.max 	.streaming_ctrl   = dvbsky_streaming_ctrl,
76724d333f3Snibble.max 	.identify_state	  = dvbsky_identify_state,
76824d333f3Snibble.max 	.exit             = dvbsky_exit,
76924d333f3Snibble.max 	.read_mac_address = dvbsky_read_mac_addr,
77024d333f3Snibble.max 
77124d333f3Snibble.max 	.num_adapters = 1,
77224d333f3Snibble.max 	.adapter = {
77324d333f3Snibble.max 		{
77424d333f3Snibble.max 			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
77524d333f3Snibble.max 		}
77624d333f3Snibble.max 	}
77724d333f3Snibble.max };
77824d333f3Snibble.max 
779b43a590dSNibble Max static struct dvb_usb_device_properties dvbsky_t680c_props = {
780b43a590dSNibble Max 	.driver_name = KBUILD_MODNAME,
781b43a590dSNibble Max 	.owner = THIS_MODULE,
782b43a590dSNibble Max 	.adapter_nr = adapter_nr,
783b43a590dSNibble Max 	.size_of_priv = sizeof(struct dvbsky_state),
784b43a590dSNibble Max 
785b43a590dSNibble Max 	.generic_bulk_ctrl_endpoint = 0x01,
786b43a590dSNibble Max 	.generic_bulk_ctrl_endpoint_response = 0x81,
787b43a590dSNibble Max 	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
788b43a590dSNibble Max 
789b43a590dSNibble Max 	.i2c_algo         = &dvbsky_i2c_algo,
790b43a590dSNibble Max 	.frontend_attach  = dvbsky_t680c_attach,
791b43a590dSNibble Max 	.init             = dvbsky_init,
792b43a590dSNibble Max 	.get_rc_config    = dvbsky_get_rc_config,
793b43a590dSNibble Max 	.streaming_ctrl   = dvbsky_streaming_ctrl,
794b43a590dSNibble Max 	.identify_state	  = dvbsky_identify_state,
795b43a590dSNibble Max 	.exit             = dvbsky_exit,
796b43a590dSNibble Max 	.read_mac_address = dvbsky_read_mac_addr,
797b43a590dSNibble Max 
798b43a590dSNibble Max 	.num_adapters = 1,
799b43a590dSNibble Max 	.adapter = {
800b43a590dSNibble Max 		{
801b43a590dSNibble Max 			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
802b43a590dSNibble Max 		}
803b43a590dSNibble Max 	}
804b43a590dSNibble Max };
805b43a590dSNibble Max 
8060a5a4f32SNibble Max static struct dvb_usb_device_properties dvbsky_t330_props = {
8070a5a4f32SNibble Max 	.driver_name = KBUILD_MODNAME,
8080a5a4f32SNibble Max 	.owner = THIS_MODULE,
8090a5a4f32SNibble Max 	.adapter_nr = adapter_nr,
8100a5a4f32SNibble Max 	.size_of_priv = sizeof(struct dvbsky_state),
8110a5a4f32SNibble Max 
8120a5a4f32SNibble Max 	.generic_bulk_ctrl_endpoint = 0x01,
8130a5a4f32SNibble Max 	.generic_bulk_ctrl_endpoint_response = 0x81,
8140a5a4f32SNibble Max 	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
8150a5a4f32SNibble Max 
8160a5a4f32SNibble Max 	.i2c_algo         = &dvbsky_i2c_algo,
8170a5a4f32SNibble Max 	.frontend_attach  = dvbsky_t330_attach,
8180a5a4f32SNibble Max 	.init             = dvbsky_init,
8190a5a4f32SNibble Max 	.get_rc_config    = dvbsky_get_rc_config,
8200a5a4f32SNibble Max 	.streaming_ctrl   = dvbsky_streaming_ctrl,
8210a5a4f32SNibble Max 	.identify_state	  = dvbsky_identify_state,
8220a5a4f32SNibble Max 	.exit             = dvbsky_exit,
8230a5a4f32SNibble Max 	.read_mac_address = dvbsky_read_mac_addr,
8240a5a4f32SNibble Max 
8250a5a4f32SNibble Max 	.num_adapters = 1,
8260a5a4f32SNibble Max 	.adapter = {
8270a5a4f32SNibble Max 		{
8280a5a4f32SNibble Max 			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
8290a5a4f32SNibble Max 		}
8300a5a4f32SNibble Max 	}
8310a5a4f32SNibble Max };
8320a5a4f32SNibble Max 
833af64fb3fSnibble.max static const struct usb_device_id dvbsky_id_table[] = {
834af64fb3fSnibble.max 	{ DVB_USB_DEVICE(0x0572, 0x6831,
835af64fb3fSnibble.max 		&dvbsky_s960_props, "DVBSky S960/S860", RC_MAP_DVBSKY) },
83624d333f3Snibble.max 	{ DVB_USB_DEVICE(0x0572, 0x960c,
83724d333f3Snibble.max 		&dvbsky_s960c_props, "DVBSky S960CI", RC_MAP_DVBSKY) },
838b43a590dSNibble Max 	{ DVB_USB_DEVICE(0x0572, 0x680c,
839b43a590dSNibble Max 		&dvbsky_t680c_props, "DVBSky T680CI", RC_MAP_DVBSKY) },
8400a5a4f32SNibble Max 	{ DVB_USB_DEVICE(0x0572, 0x0320,
8410a5a4f32SNibble Max 		&dvbsky_t330_props, "DVBSky T330", RC_MAP_DVBSKY) },
842134e7e1cSNibble Max 	{ DVB_USB_DEVICE(USB_VID_TECHNOTREND,
843134e7e1cSNibble Max 		USB_PID_TECHNOTREND_TVSTICK_CT2_4400,
844134e7e1cSNibble Max 		&dvbsky_t330_props, "TechnoTrend TVStick CT2-4400",
845134e7e1cSNibble Max 		RC_MAP_TT_1500) },
846134e7e1cSNibble Max 	{ DVB_USB_DEVICE(USB_VID_TECHNOTREND,
847134e7e1cSNibble Max 		USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI,
848134e7e1cSNibble Max 		&dvbsky_t680c_props, "TechnoTrend TT-connect CT2-4650 CI",
849134e7e1cSNibble Max 		RC_MAP_TT_1500) },
850d309c8bbSTorbjörn Jansson 	{ DVB_USB_DEVICE(USB_VID_TECHNOTREND,
851d309c8bbSTorbjörn Jansson 		USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI_2,
852d309c8bbSTorbjörn Jansson 		&dvbsky_t680c_props, "TechnoTrend TT-connect CT2-4650 CI v1.1",
853d309c8bbSTorbjörn Jansson 		RC_MAP_TT_1500) },
854*82b65714SOlli Salonen 	{ DVB_USB_DEVICE(USB_VID_TECHNOTREND,
855*82b65714SOlli Salonen 		USB_PID_TECHNOTREND_CONNECT_S2_4650_CI,
856*82b65714SOlli Salonen 		&dvbsky_s960c_props, "TechnoTrend TT-connect S2-4650 CI",
857*82b65714SOlli Salonen 		RC_MAP_TT_1500) },
8582788052aSErik Andresen 	{ DVB_USB_DEVICE(USB_VID_TERRATEC,
8592788052aSErik Andresen 		USB_PID_TERRATEC_H7_3,
8602788052aSErik Andresen 		&dvbsky_t680c_props, "Terratec H7 Rev.4",
8612788052aSErik Andresen 		RC_MAP_TT_1500) },
862c5d89a49SBenjamin Larsson 	{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R4,
863c5d89a49SBenjamin Larsson 		&dvbsky_s960_props, "Terratec Cinergy S2 Rev.4",
864c5d89a49SBenjamin Larsson 		RC_MAP_DVBSKY) },
865af64fb3fSnibble.max 	{ }
866af64fb3fSnibble.max };
867af64fb3fSnibble.max MODULE_DEVICE_TABLE(usb, dvbsky_id_table);
868af64fb3fSnibble.max 
869af64fb3fSnibble.max static struct usb_driver dvbsky_usb_driver = {
870af64fb3fSnibble.max 	.name = KBUILD_MODNAME,
871af64fb3fSnibble.max 	.id_table = dvbsky_id_table,
872af64fb3fSnibble.max 	.probe = dvb_usbv2_probe,
873af64fb3fSnibble.max 	.disconnect = dvb_usbv2_disconnect,
874af64fb3fSnibble.max 	.suspend = dvb_usbv2_suspend,
875af64fb3fSnibble.max 	.resume = dvb_usbv2_resume,
876af64fb3fSnibble.max 	.reset_resume = dvb_usbv2_reset_resume,
877af64fb3fSnibble.max 	.no_dynamic_id = 1,
878af64fb3fSnibble.max 	.soft_unbind = 1,
879af64fb3fSnibble.max };
880af64fb3fSnibble.max 
881af64fb3fSnibble.max module_usb_driver(dvbsky_usb_driver);
882af64fb3fSnibble.max 
883af64fb3fSnibble.max MODULE_AUTHOR("Max nibble <nibble.max@gmail.com>");
884af64fb3fSnibble.max MODULE_DESCRIPTION("Driver for DVBSky USB");
885af64fb3fSnibble.max MODULE_LICENSE("GPL");
886