blob: b0ddebcc85ed0660b566267b11aea76e63276661 [file] [log] [blame]
Igor M. Liplianine4aab642008-09-23 15:43:57 -03001/*
2 Driver for ST STV0288 demodulator
3 Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de
4 for Reel Multimedia
5 Copyright (C) 2008 TurboSight.com, Bob Liu <bob@turbosight.com>
6 Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
7 Removed stb6000 specific tuner code and revised some
8 procedures.
Malcolm Priestley352a5872010-09-26 15:16:20 -03009 2010-09-01 Josef Pavlik <josef@pavlik.it>
10 Fixed diseqc_msg, diseqc_burst and set_tone problems
Igor M. Liplianine4aab642008-09-23 15:43:57 -030011
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
26*/
27
28#include <linux/init.h>
29#include <linux/kernel.h>
30#include <linux/module.h>
31#include <linux/string.h>
32#include <linux/slab.h>
33#include <linux/jiffies.h>
34#include <asm/div64.h>
35
36#include "dvb_frontend.h"
37#include "stv0288.h"
38
39struct stv0288_state {
40 struct i2c_adapter *i2c;
41 const struct stv0288_config *config;
42 struct dvb_frontend frontend;
43
44 u8 initialised:1;
45 u32 tuner_frequency;
46 u32 symbol_rate;
47 fe_code_rate_t fec_inner;
48 int errmode;
49};
50
51#define STATUS_BER 0
52#define STATUS_UCBLOCKS 1
53
54static int debug;
55static int debug_legacy_dish_switch;
56#define dprintk(args...) \
57 do { \
58 if (debug) \
59 printk(KERN_DEBUG "stv0288: " args); \
60 } while (0)
61
62
63static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data)
64{
65 int ret;
66 u8 buf[] = { reg, data };
67 struct i2c_msg msg = {
68 .addr = state->config->demod_address,
69 .flags = 0,
70 .buf = buf,
71 .len = 2
72 };
73
74 ret = i2c_transfer(state->i2c, &msg, 1);
75
76 if (ret != 1)
77 dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
78 "ret == %i)\n", __func__, reg, data, ret);
79
80 return (ret != 1) ? -EREMOTEIO : 0;
81}
82
lawrence rust2e4e98e2010-08-25 09:50:20 -030083static int stv0288_write(struct dvb_frontend *fe, const u8 buf[], int len)
Igor M. Liplianine4aab642008-09-23 15:43:57 -030084{
85 struct stv0288_state *state = fe->demodulator_priv;
86
87 if (len != 2)
88 return -EINVAL;
89
90 return stv0288_writeregI(state, buf[0], buf[1]);
91}
92
93static u8 stv0288_readreg(struct stv0288_state *state, u8 reg)
94{
95 int ret;
96 u8 b0[] = { reg };
97 u8 b1[] = { 0 };
98 struct i2c_msg msg[] = {
99 {
100 .addr = state->config->demod_address,
101 .flags = 0,
102 .buf = b0,
103 .len = 1
104 }, {
105 .addr = state->config->demod_address,
106 .flags = I2C_M_RD,
107 .buf = b1,
108 .len = 1
109 }
110 };
111
112 ret = i2c_transfer(state->i2c, msg, 2);
113
114 if (ret != 2)
115 dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
116 __func__, reg, ret);
117
118 return b1[0];
119}
120
121static int stv0288_set_symbolrate(struct dvb_frontend *fe, u32 srate)
122{
123 struct stv0288_state *state = fe->demodulator_priv;
124 unsigned int temp;
125 unsigned char b[3];
126
127 if ((srate < 1000000) || (srate > 45000000))
128 return -EINVAL;
129
tvboxspy59152b12011-07-10 18:37:13 -0300130 stv0288_writeregI(state, 0x22, 0);
131 stv0288_writeregI(state, 0x23, 0);
132 stv0288_writeregI(state, 0x2b, 0xff);
133 stv0288_writeregI(state, 0x2c, 0xf7);
134
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300135 temp = (unsigned int)srate / 1000;
136
137 temp = temp * 32768;
138 temp = temp / 25;
139 temp = temp / 125;
140 b[0] = (unsigned char)((temp >> 12) & 0xff);
141 b[1] = (unsigned char)((temp >> 4) & 0xff);
142 b[2] = (unsigned char)((temp << 4) & 0xf0);
143 stv0288_writeregI(state, 0x28, 0x80); /* SFRH */
144 stv0288_writeregI(state, 0x29, 0); /* SFRM */
145 stv0288_writeregI(state, 0x2a, 0); /* SFRL */
146
147 stv0288_writeregI(state, 0x28, b[0]);
148 stv0288_writeregI(state, 0x29, b[1]);
149 stv0288_writeregI(state, 0x2a, b[2]);
150 dprintk("stv0288: stv0288_set_symbolrate\n");
151
152 return 0;
153}
154
155static int stv0288_send_diseqc_msg(struct dvb_frontend *fe,
156 struct dvb_diseqc_master_cmd *m)
157{
158 struct stv0288_state *state = fe->demodulator_priv;
159
160 int i;
161
162 dprintk("%s\n", __func__);
163
164 stv0288_writeregI(state, 0x09, 0);
165 msleep(30);
Malcolm Priestley352a5872010-09-26 15:16:20 -0300166 stv0288_writeregI(state, 0x05, 0x12);/* modulated mode, single shot */
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300167
168 for (i = 0; i < m->msg_len; i++) {
169 if (stv0288_writeregI(state, 0x06, m->msg[i]))
170 return -EREMOTEIO;
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300171 }
Malcolm Priestley352a5872010-09-26 15:16:20 -0300172 msleep(m->msg_len*12);
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300173 return 0;
174}
175
176static int stv0288_send_diseqc_burst(struct dvb_frontend *fe,
177 fe_sec_mini_cmd_t burst)
178{
179 struct stv0288_state *state = fe->demodulator_priv;
180
181 dprintk("%s\n", __func__);
182
Malcolm Priestley352a5872010-09-26 15:16:20 -0300183 if (stv0288_writeregI(state, 0x05, 0x03))/* burst mode, single shot */
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300184 return -EREMOTEIO;
185
186 if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff))
187 return -EREMOTEIO;
188
Malcolm Priestley352a5872010-09-26 15:16:20 -0300189 msleep(15);
190 if (stv0288_writeregI(state, 0x05, 0x12))
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300191 return -EREMOTEIO;
192
193 return 0;
194}
195
196static int stv0288_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
197{
198 struct stv0288_state *state = fe->demodulator_priv;
199
200 switch (tone) {
201 case SEC_TONE_ON:
Malcolm Priestley352a5872010-09-26 15:16:20 -0300202 if (stv0288_writeregI(state, 0x05, 0x10))/* cont carrier */
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300203 return -EREMOTEIO;
Malcolm Priestley352a5872010-09-26 15:16:20 -0300204 break;
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300205
206 case SEC_TONE_OFF:
Malcolm Priestley352a5872010-09-26 15:16:20 -0300207 if (stv0288_writeregI(state, 0x05, 0x12))/* burst mode off*/
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300208 return -EREMOTEIO;
Malcolm Priestley352a5872010-09-26 15:16:20 -0300209 break;
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300210
211 default:
212 return -EINVAL;
213 }
Malcolm Priestley352a5872010-09-26 15:16:20 -0300214 return 0;
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300215}
216
217static u8 stv0288_inittab[] = {
218 0x01, 0x15,
219 0x02, 0x20,
220 0x09, 0x0,
221 0x0a, 0x4,
222 0x0b, 0x0,
223 0x0c, 0x0,
224 0x0d, 0x0,
225 0x0e, 0xd4,
226 0x0f, 0x30,
227 0x11, 0x80,
228 0x12, 0x03,
229 0x13, 0x48,
230 0x14, 0x84,
231 0x15, 0x45,
232 0x16, 0xb7,
233 0x17, 0x9c,
234 0x18, 0x0,
235 0x19, 0xa6,
236 0x1a, 0x88,
237 0x1b, 0x8f,
238 0x1c, 0xf0,
239 0x20, 0x0b,
240 0x21, 0x54,
241 0x22, 0x0,
242 0x23, 0x0,
243 0x2b, 0xff,
244 0x2c, 0xf7,
245 0x30, 0x0,
246 0x31, 0x1e,
247 0x32, 0x14,
248 0x33, 0x0f,
249 0x34, 0x09,
250 0x35, 0x0c,
251 0x36, 0x05,
252 0x37, 0x2f,
253 0x38, 0x16,
254 0x39, 0xbe,
255 0x3a, 0x0,
256 0x3b, 0x13,
257 0x3c, 0x11,
258 0x3d, 0x30,
259 0x40, 0x63,
260 0x41, 0x04,
Malcolm Priestleybb19a422011-04-02 10:51:53 -0300261 0x42, 0x20,
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300262 0x43, 0x00,
263 0x44, 0x00,
264 0x45, 0x00,
265 0x46, 0x00,
266 0x47, 0x00,
267 0x4a, 0x00,
268 0x50, 0x10,
269 0x51, 0x38,
270 0x52, 0x21,
271 0x58, 0x54,
272 0x59, 0x86,
273 0x5a, 0x0,
274 0x5b, 0x9b,
275 0x5c, 0x08,
276 0x5d, 0x7f,
277 0x5e, 0x0,
278 0x5f, 0xff,
279 0x70, 0x0,
280 0x71, 0x0,
281 0x72, 0x0,
282 0x74, 0x0,
283 0x75, 0x0,
284 0x76, 0x0,
285 0x81, 0x0,
286 0x82, 0x3f,
287 0x83, 0x3f,
288 0x84, 0x0,
289 0x85, 0x0,
290 0x88, 0x0,
291 0x89, 0x0,
292 0x8a, 0x0,
293 0x8b, 0x0,
294 0x8c, 0x0,
295 0x90, 0x0,
296 0x91, 0x0,
297 0x92, 0x0,
298 0x93, 0x0,
299 0x94, 0x1c,
300 0x97, 0x0,
301 0xa0, 0x48,
302 0xa1, 0x0,
303 0xb0, 0xb8,
304 0xb1, 0x3a,
305 0xb2, 0x10,
306 0xb3, 0x82,
307 0xb4, 0x80,
308 0xb5, 0x82,
309 0xb6, 0x82,
310 0xb7, 0x82,
311 0xb8, 0x20,
312 0xb9, 0x0,
313 0xf0, 0x0,
314 0xf1, 0x0,
315 0xf2, 0xc0,
316 0x51, 0x36,
317 0x52, 0x09,
318 0x53, 0x94,
319 0x54, 0x62,
320 0x55, 0x29,
321 0x56, 0x64,
322 0x57, 0x2b,
323 0xff, 0xff,
324};
325
326static int stv0288_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
327{
328 dprintk("%s: %s\n", __func__,
329 volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
330 volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
331
332 return 0;
333}
334
335static int stv0288_init(struct dvb_frontend *fe)
336{
337 struct stv0288_state *state = fe->demodulator_priv;
338 int i;
Igor M. Liplianinde9be0e2008-10-05 08:52:18 -0300339 u8 reg;
340 u8 val;
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300341
342 dprintk("stv0288: init chip\n");
343 stv0288_writeregI(state, 0x41, 0x04);
344 msleep(50);
345
Igor M. Liplianinde9be0e2008-10-05 08:52:18 -0300346 /* we have default inittab */
347 if (state->config->inittab == NULL) {
348 for (i = 0; !(stv0288_inittab[i] == 0xff &&
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300349 stv0288_inittab[i + 1] == 0xff); i += 2)
Igor M. Liplianinde9be0e2008-10-05 08:52:18 -0300350 stv0288_writeregI(state, stv0288_inittab[i],
351 stv0288_inittab[i + 1]);
352 } else {
353 for (i = 0; ; i += 2) {
354 reg = state->config->inittab[i];
355 val = state->config->inittab[i+1];
356 if (reg == 0xff && val == 0xff)
357 break;
358 stv0288_writeregI(state, reg, val);
359 }
360 }
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300361 return 0;
362}
363
364static int stv0288_read_status(struct dvb_frontend *fe, fe_status_t *status)
365{
366 struct stv0288_state *state = fe->demodulator_priv;
367
368 u8 sync = stv0288_readreg(state, 0x24);
369 if (sync == 255)
370 sync = 0;
371
372 dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync);
373
374 *status = 0;
Malcolm Priestleyb50b3a12011-03-06 13:37:00 -0300375 if (sync & 0x80)
376 *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
377 if (sync & 0x10)
378 *status |= FE_HAS_VITERBI;
379 if (sync & 0x08) {
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300380 *status |= FE_HAS_LOCK;
381 dprintk("stv0288 has locked\n");
382 }
383
384 return 0;
385}
386
387static int stv0288_read_ber(struct dvb_frontend *fe, u32 *ber)
388{
389 struct stv0288_state *state = fe->demodulator_priv;
390
391 if (state->errmode != STATUS_BER)
392 return 0;
393 *ber = (stv0288_readreg(state, 0x26) << 8) |
394 stv0288_readreg(state, 0x27);
395 dprintk("stv0288_read_ber %d\n", *ber);
396
397 return 0;
398}
399
400
401static int stv0288_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
402{
403 struct stv0288_state *state = fe->demodulator_priv;
404
405 s32 signal = 0xffff - ((stv0288_readreg(state, 0x10) << 8));
406
407
408 signal = signal * 5 / 4;
409 *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal;
410 dprintk("stv0288_read_signal_strength %d\n", *strength);
411
412 return 0;
413}
414static int stv0288_sleep(struct dvb_frontend *fe)
415{
416 struct stv0288_state *state = fe->demodulator_priv;
417
418 stv0288_writeregI(state, 0x41, 0x84);
419 state->initialised = 0;
420
421 return 0;
422}
423static int stv0288_read_snr(struct dvb_frontend *fe, u16 *snr)
424{
425 struct stv0288_state *state = fe->demodulator_priv;
426
427 s32 xsnr = 0xffff - ((stv0288_readreg(state, 0x2d) << 8)
428 | stv0288_readreg(state, 0x2e));
429 xsnr = 3 * (xsnr - 0xa100);
430 *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
431 dprintk("stv0288_read_snr %d\n", *snr);
432
433 return 0;
434}
435
436static int stv0288_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
437{
438 struct stv0288_state *state = fe->demodulator_priv;
439
440 if (state->errmode != STATUS_BER)
441 return 0;
442 *ucblocks = (stv0288_readreg(state, 0x26) << 8) |
443 stv0288_readreg(state, 0x27);
444 dprintk("stv0288_read_ber %d\n", *ucblocks);
445
446 return 0;
447}
448
449static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p)
450{
451 dprintk("%s(..)\n", __func__);
452 return 0;
453}
454
455static int stv0288_get_property(struct dvb_frontend *fe, struct dtv_property *p)
456{
457 dprintk("%s(..)\n", __func__);
458 return 0;
459}
460
Mauro Carvalho Chehab5c6b4e22011-12-26 14:25:54 -0300461static int stv0288_set_frontend(struct dvb_frontend *fe)
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300462{
463 struct stv0288_state *state = fe->demodulator_priv;
464 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
465
466 char tm;
467 unsigned char tda[3];
tvboxspy59152b12011-07-10 18:37:13 -0300468 u8 reg, time_out = 0;
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300469
470 dprintk("%s : FE_SET_FRONTEND\n", __func__);
471
472 if (c->delivery_system != SYS_DVBS) {
473 dprintk("%s: unsupported delivery "
474 "system selected (%d)\n",
475 __func__, c->delivery_system);
476 return -EOPNOTSUPP;
477 }
478
479 if (state->config->set_ts_params)
480 state->config->set_ts_params(fe, 0);
481
482 /* only frequency & symbol_rate are used for tuner*/
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300483 if (fe->ops.tuner_ops.set_params) {
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -0300484 fe->ops.tuner_ops.set_params(fe);
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300485 if (fe->ops.i2c_gate_ctrl)
486 fe->ops.i2c_gate_ctrl(fe, 0);
487 }
488
489 udelay(10);
490 stv0288_set_symbolrate(fe, c->symbol_rate);
491 /* Carrier lock control register */
492 stv0288_writeregI(state, 0x15, 0xc5);
493
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300494 tda[2] = 0x0; /* CFRL */
tvboxspy59152b12011-07-10 18:37:13 -0300495 for (tm = -9; tm < 7;) {
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300496 /* Viterbi status */
tvboxspy59152b12011-07-10 18:37:13 -0300497 reg = stv0288_readreg(state, 0x24);
498 if (reg & 0x8)
499 break;
500 if (reg & 0x80) {
501 time_out++;
502 if (time_out > 10)
503 break;
504 tda[2] += 40;
505 if (tda[2] < 40)
506 tm++;
507 } else {
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300508 tm++;
tvboxspy59152b12011-07-10 18:37:13 -0300509 tda[2] = 0;
510 time_out = 0;
511 }
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300512 tda[1] = (unsigned char)tm;
513 stv0288_writeregI(state, 0x2b, tda[1]);
514 stv0288_writeregI(state, 0x2c, tda[2]);
515 udelay(30);
516 }
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300517 state->tuner_frequency = c->frequency;
518 state->fec_inner = FEC_AUTO;
519 state->symbol_rate = c->symbol_rate;
520
521 return 0;
522}
523
524static int stv0288_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
525{
526 struct stv0288_state *state = fe->demodulator_priv;
527
528 if (enable)
529 stv0288_writeregI(state, 0x01, 0xb5);
530 else
531 stv0288_writeregI(state, 0x01, 0x35);
532
533 udelay(1);
534
535 return 0;
536}
537
538static void stv0288_release(struct dvb_frontend *fe)
539{
540 struct stv0288_state *state = fe->demodulator_priv;
541 kfree(state);
542}
543
544static struct dvb_frontend_ops stv0288_ops = {
Mauro Carvalho Chehab5c6b4e22011-12-26 14:25:54 -0300545 .delsys = { SYS_DVBS },
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300546 .info = {
547 .name = "ST STV0288 DVB-S",
548 .type = FE_QPSK,
549 .frequency_min = 950000,
550 .frequency_max = 2150000,
551 .frequency_stepsize = 1000, /* kHz for QPSK frontends */
552 .frequency_tolerance = 0,
553 .symbol_rate_min = 1000000,
554 .symbol_rate_max = 45000000,
555 .symbol_rate_tolerance = 500, /* ppm */
556 .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
557 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
558 FE_CAN_QPSK |
559 FE_CAN_FEC_AUTO
560 },
561
562 .release = stv0288_release,
563 .init = stv0288_init,
564 .sleep = stv0288_sleep,
565 .write = stv0288_write,
566 .i2c_gate_ctrl = stv0288_i2c_gate_ctrl,
567 .read_status = stv0288_read_status,
568 .read_ber = stv0288_read_ber,
569 .read_signal_strength = stv0288_read_signal_strength,
570 .read_snr = stv0288_read_snr,
571 .read_ucblocks = stv0288_read_ucblocks,
572 .diseqc_send_master_cmd = stv0288_send_diseqc_msg,
573 .diseqc_send_burst = stv0288_send_diseqc_burst,
574 .set_tone = stv0288_set_tone,
575 .set_voltage = stv0288_set_voltage,
576
577 .set_property = stv0288_set_property,
578 .get_property = stv0288_get_property,
Mauro Carvalho Chehab5c6b4e22011-12-26 14:25:54 -0300579 .set_frontend = stv0288_set_frontend,
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300580};
581
582struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
583 struct i2c_adapter *i2c)
584{
585 struct stv0288_state *state = NULL;
586 int id;
587
588 /* allocate memory for the internal state */
Matthias Schwarzott084e24a2009-08-10 22:51:01 -0300589 state = kzalloc(sizeof(struct stv0288_state), GFP_KERNEL);
Igor M. Liplianine4aab642008-09-23 15:43:57 -0300590 if (state == NULL)
591 goto error;
592
593 /* setup the state */
594 state->config = config;
595 state->i2c = i2c;
596 state->initialised = 0;
597 state->tuner_frequency = 0;
598 state->symbol_rate = 0;
599 state->fec_inner = 0;
600 state->errmode = STATUS_BER;
601
602 stv0288_writeregI(state, 0x41, 0x04);
603 msleep(200);
604 id = stv0288_readreg(state, 0x00);
605 dprintk("stv0288 id %x\n", id);
606
607 /* register 0x00 contains 0x11 for STV0288 */
608 if (id != 0x11)
609 goto error;
610
611 /* create dvb_frontend */
612 memcpy(&state->frontend.ops, &stv0288_ops,
613 sizeof(struct dvb_frontend_ops));
614 state->frontend.demodulator_priv = state;
615 return &state->frontend;
616
617error:
618 kfree(state);
619
620 return NULL;
621}
622EXPORT_SYMBOL(stv0288_attach);
623
624module_param(debug_legacy_dish_switch, int, 0444);
625MODULE_PARM_DESC(debug_legacy_dish_switch,
626 "Enable timing analysis for Dish Network legacy switches");
627
628module_param(debug, int, 0644);
629MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
630
631MODULE_DESCRIPTION("ST STV0288 DVB Demodulator driver");
632MODULE_AUTHOR("Georg Acher, Bob Liu, Igor liplianin");
633MODULE_LICENSE("GPL");
634