• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     driver for LSI L64781 COFDM demodulator
3 
4     Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH
5 		       Marko Kohtala <marko.kohtala@luukku.com>
6 
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
23 #include <linux/init.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/string.h>
27 #include <linux/slab.h>
28 #include "dvb_frontend.h"
29 #include "l64781.h"
30 
31 
32 struct l64781_state {
33 	struct i2c_adapter* i2c;
34 	const struct l64781_config* config;
35 	struct dvb_frontend frontend;
36 
37 	/* private demodulator data */
38 	unsigned int first:1;
39 };
40 
41 #define dprintk(args...) \
42 	do { \
43 		if (debug) printk(KERN_DEBUG "l64781: " args); \
44 	} while (0)
45 
46 static int debug;
47 
48 module_param(debug, int, 0644);
49 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
50 
51 
l64781_writereg(struct l64781_state * state,u8 reg,u8 data)52 static int l64781_writereg (struct l64781_state* state, u8 reg, u8 data)
53 {
54 	int ret;
55 	u8 buf [] = { reg, data };
56 	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
57 
58 	if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1)
59 		dprintk ("%s: write_reg error (reg == %02x) = %02x!\n",
60 			 __func__, reg, ret);
61 
62 	return (ret != 1) ? -1 : 0;
63 }
64 
l64781_readreg(struct l64781_state * state,u8 reg)65 static int l64781_readreg (struct l64781_state* state, u8 reg)
66 {
67 	int ret;
68 	u8 b0 [] = { reg };
69 	u8 b1 [] = { 0 };
70 	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
71 			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
72 
73 	ret = i2c_transfer(state->i2c, msg, 2);
74 
75 	if (ret != 2) return ret;
76 
77 	return b1[0];
78 }
79 
apply_tps(struct l64781_state * state)80 static void apply_tps (struct l64781_state* state)
81 {
82 	l64781_writereg (state, 0x2a, 0x00);
83 	l64781_writereg (state, 0x2a, 0x01);
84 
85 	/* This here is a little bit questionable because it enables
86 	   the automatic update of TPS registers. I think we'd need to
87 	   handle the IRQ from FE to update some other registers as
88 	   well, or at least implement some magic to tuning to correct
89 	   to the TPS received from transmission. */
90 	l64781_writereg (state, 0x2a, 0x02);
91 }
92 
93 
reset_afc(struct l64781_state * state)94 static void reset_afc (struct l64781_state* state)
95 {
96 	/* Set AFC stall for the AFC_INIT_FRQ setting, TIM_STALL for
97 	   timing offset */
98 	l64781_writereg (state, 0x07, 0x9e); /* stall AFC */
99 	l64781_writereg (state, 0x08, 0);    /* AFC INIT FREQ */
100 	l64781_writereg (state, 0x09, 0);
101 	l64781_writereg (state, 0x0a, 0);
102 	l64781_writereg (state, 0x07, 0x8e);
103 	l64781_writereg (state, 0x0e, 0);    /* AGC gain to zero in beginning */
104 	l64781_writereg (state, 0x11, 0x80); /* stall TIM */
105 	l64781_writereg (state, 0x10, 0);    /* TIM_OFFSET_LSB */
106 	l64781_writereg (state, 0x12, 0);
107 	l64781_writereg (state, 0x13, 0);
108 	l64781_writereg (state, 0x11, 0x00);
109 }
110 
reset_and_configure(struct l64781_state * state)111 static int reset_and_configure (struct l64781_state* state)
112 {
113 	u8 buf [] = { 0x06 };
114 	struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 };
115 	// NOTE: this is correct in writing to address 0x00
116 
117 	return (i2c_transfer(state->i2c, &msg, 1) == 1) ? 0 : -ENODEV;
118 }
119 
apply_frontend_param(struct dvb_frontend * fe,struct dvb_frontend_parameters * param)120 static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_parameters *param)
121 {
122 	struct l64781_state* state = fe->demodulator_priv;
123 	/* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */
124 	static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 };
125 	/* QPSK, QAM_16, QAM_64 */
126 	static const u8 qam_tab [] = { 2, 4, 0, 6 };
127 	static const u8 bw_tab [] = { 8, 7, 6 };  /* 8Mhz, 7MHz, 6MHz */
128 	static const u8 guard_tab [] = { 1, 2, 4, 8 };
129 	/* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */
130 	static const u32 ppm = 8000;
131 	struct dvb_ofdm_parameters *p = &param->u.ofdm;
132 	u32 ddfs_offset_fixed;
133 /*	u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */
134 /*			bw_tab[p->bandWidth]<<10)/15625; */
135 	u32 init_freq;
136 	u32 spi_bias;
137 	u8 val0x04;
138 	u8 val0x05;
139 	u8 val0x06;
140 	int bw = p->bandwidth - BANDWIDTH_8_MHZ;
141 
142 	if (fe->ops.tuner_ops.set_params) {
143 		fe->ops.tuner_ops.set_params(fe, param);
144 		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
145 	}
146 
147 	if (param->inversion != INVERSION_ON &&
148 	    param->inversion != INVERSION_OFF)
149 		return -EINVAL;
150 
151 	if (bw < 0 || bw > 2)
152 		return -EINVAL;
153 
154 	if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 &&
155 	    p->code_rate_HP != FEC_3_4 && p->code_rate_HP != FEC_5_6 &&
156 	    p->code_rate_HP != FEC_7_8)
157 		return -EINVAL;
158 
159 	if (p->hierarchy_information != HIERARCHY_NONE &&
160 	    (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 &&
161 	     p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 &&
162 	     p->code_rate_LP != FEC_7_8))
163 		return -EINVAL;
164 
165 	if (p->constellation != QPSK && p->constellation != QAM_16 &&
166 	    p->constellation != QAM_64)
167 		return -EINVAL;
168 
169 	if (p->transmission_mode != TRANSMISSION_MODE_2K &&
170 	    p->transmission_mode != TRANSMISSION_MODE_8K)
171 		return -EINVAL;
172 
173 	if (p->guard_interval < GUARD_INTERVAL_1_32 ||
174 	    p->guard_interval > GUARD_INTERVAL_1_4)
175 		return -EINVAL;
176 
177 	if (p->hierarchy_information < HIERARCHY_NONE ||
178 	    p->hierarchy_information > HIERARCHY_4)
179 		return -EINVAL;
180 
181 	ddfs_offset_fixed = 0x4000-(ppm<<16)/bw_tab[p->bandwidth]/1000000;
182 
183 	/* This works up to 20000 ppm, it overflows if too large ppm! */
184 	init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) /
185 			bw_tab[p->bandwidth] & 0xFFFFFF);
186 
187 	/* SPI bias calculation is slightly modified to fit in 32bit */
188 	/* will work for high ppm only... */
189 	spi_bias = 378 * (1 << 10);
190 	spi_bias *= 16;
191 	spi_bias *= bw_tab[p->bandwidth];
192 	spi_bias *= qam_tab[p->constellation];
193 	spi_bias /= p->code_rate_HP + 1;
194 	spi_bias /= (guard_tab[p->guard_interval] + 32);
195 	spi_bias *= 1000ULL;
196 	spi_bias /= 1000ULL + ppm/1000;
197 	spi_bias *= p->code_rate_HP;
198 
199 	val0x04 = (p->transmission_mode << 2) | p->guard_interval;
200 	val0x05 = fec_tab[p->code_rate_HP];
201 
202 	if (p->hierarchy_information != HIERARCHY_NONE)
203 		val0x05 |= (p->code_rate_LP - FEC_1_2) << 3;
204 
205 	val0x06 = (p->hierarchy_information << 2) | p->constellation;
206 
207 	l64781_writereg (state, 0x04, val0x04);
208 	l64781_writereg (state, 0x05, val0x05);
209 	l64781_writereg (state, 0x06, val0x06);
210 
211 	reset_afc (state);
212 
213 	/* Technical manual section 2.6.1, TIM_IIR_GAIN optimal values */
214 	l64781_writereg (state, 0x15,
215 			 p->transmission_mode == TRANSMISSION_MODE_2K ? 1 : 3);
216 	l64781_writereg (state, 0x16, init_freq & 0xff);
217 	l64781_writereg (state, 0x17, (init_freq >> 8) & 0xff);
218 	l64781_writereg (state, 0x18, (init_freq >> 16) & 0xff);
219 
220 	l64781_writereg (state, 0x1b, spi_bias & 0xff);
221 	l64781_writereg (state, 0x1c, (spi_bias >> 8) & 0xff);
222 	l64781_writereg (state, 0x1d, ((spi_bias >> 16) & 0x7f) |
223 		(param->inversion == INVERSION_ON ? 0x80 : 0x00));
224 
225 	l64781_writereg (state, 0x22, ddfs_offset_fixed & 0xff);
226 	l64781_writereg (state, 0x23, (ddfs_offset_fixed >> 8) & 0x3f);
227 
228 	l64781_readreg (state, 0x00);  /*  clear interrupt registers... */
229 	l64781_readreg (state, 0x01);  /*  dto. */
230 
231 	apply_tps (state);
232 
233 	return 0;
234 }
235 
get_frontend(struct dvb_frontend * fe,struct dvb_frontend_parameters * param)236 static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* param)
237 {
238 	struct l64781_state* state = fe->demodulator_priv;
239 	int tmp;
240 
241 
242 	tmp = l64781_readreg(state, 0x04);
243 	switch(tmp & 3) {
244 	case 0:
245 		param->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
246 		break;
247 	case 1:
248 		param->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
249 		break;
250 	case 2:
251 		param->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
252 		break;
253 	case 3:
254 		param->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
255 		break;
256 	}
257 	switch((tmp >> 2) & 3) {
258 	case 0:
259 		param->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
260 		break;
261 	case 1:
262 		param->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
263 		break;
264 	default:
265 		printk("Unexpected value for transmission_mode\n");
266 	}
267 
268 
269 
270 	tmp = l64781_readreg(state, 0x05);
271 	switch(tmp & 7) {
272 	case 0:
273 		param->u.ofdm.code_rate_HP = FEC_1_2;
274 		break;
275 	case 1:
276 		param->u.ofdm.code_rate_HP = FEC_2_3;
277 		break;
278 	case 2:
279 		param->u.ofdm.code_rate_HP = FEC_3_4;
280 		break;
281 	case 3:
282 		param->u.ofdm.code_rate_HP = FEC_5_6;
283 		break;
284 	case 4:
285 		param->u.ofdm.code_rate_HP = FEC_7_8;
286 		break;
287 	default:
288 		printk("Unexpected value for code_rate_HP\n");
289 	}
290 	switch((tmp >> 3) & 7) {
291 	case 0:
292 		param->u.ofdm.code_rate_LP = FEC_1_2;
293 		break;
294 	case 1:
295 		param->u.ofdm.code_rate_LP = FEC_2_3;
296 		break;
297 	case 2:
298 		param->u.ofdm.code_rate_LP = FEC_3_4;
299 		break;
300 	case 3:
301 		param->u.ofdm.code_rate_LP = FEC_5_6;
302 		break;
303 	case 4:
304 		param->u.ofdm.code_rate_LP = FEC_7_8;
305 		break;
306 	default:
307 		printk("Unexpected value for code_rate_LP\n");
308 	}
309 
310 
311 	tmp = l64781_readreg(state, 0x06);
312 	switch(tmp & 3) {
313 	case 0:
314 		param->u.ofdm.constellation = QPSK;
315 		break;
316 	case 1:
317 		param->u.ofdm.constellation = QAM_16;
318 		break;
319 	case 2:
320 		param->u.ofdm.constellation = QAM_64;
321 		break;
322 	default:
323 		printk("Unexpected value for constellation\n");
324 	}
325 	switch((tmp >> 2) & 7) {
326 	case 0:
327 		param->u.ofdm.hierarchy_information = HIERARCHY_NONE;
328 		break;
329 	case 1:
330 		param->u.ofdm.hierarchy_information = HIERARCHY_1;
331 		break;
332 	case 2:
333 		param->u.ofdm.hierarchy_information = HIERARCHY_2;
334 		break;
335 	case 3:
336 		param->u.ofdm.hierarchy_information = HIERARCHY_4;
337 		break;
338 	default:
339 		printk("Unexpected value for hierarchy\n");
340 	}
341 
342 
343 	tmp = l64781_readreg (state, 0x1d);
344 	param->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF;
345 
346 	tmp = (int) (l64781_readreg (state, 0x08) |
347 		     (l64781_readreg (state, 0x09) << 8) |
348 		     (l64781_readreg (state, 0x0a) << 16));
349 	param->frequency += tmp;
350 
351 	return 0;
352 }
353 
l64781_read_status(struct dvb_frontend * fe,fe_status_t * status)354 static int l64781_read_status(struct dvb_frontend* fe, fe_status_t* status)
355 {
356 	struct l64781_state* state = fe->demodulator_priv;
357 	int sync = l64781_readreg (state, 0x32);
358 	int gain = l64781_readreg (state, 0x0e);
359 
360 	l64781_readreg (state, 0x00);  /*  clear interrupt registers... */
361 	l64781_readreg (state, 0x01);  /*  dto. */
362 
363 	*status = 0;
364 
365 	if (gain > 5)
366 		*status |= FE_HAS_SIGNAL;
367 
368 	if (sync & 0x02) /* VCXO locked, this criteria should be ok */
369 		*status |= FE_HAS_CARRIER;
370 
371 	if (sync & 0x20)
372 		*status |= FE_HAS_VITERBI;
373 
374 	if (sync & 0x40)
375 		*status |= FE_HAS_SYNC;
376 
377 	if (sync == 0x7f)
378 		*status |= FE_HAS_LOCK;
379 
380 	return 0;
381 }
382 
l64781_read_ber(struct dvb_frontend * fe,u32 * ber)383 static int l64781_read_ber(struct dvb_frontend* fe, u32* ber)
384 {
385 	struct l64781_state* state = fe->demodulator_priv;
386 
387 	/*   XXX FIXME: set up counting period (reg 0x26...0x28)
388 	 */
389 	*ber = l64781_readreg (state, 0x39)
390 	    | (l64781_readreg (state, 0x3a) << 8);
391 
392 	return 0;
393 }
394 
l64781_read_signal_strength(struct dvb_frontend * fe,u16 * signal_strength)395 static int l64781_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
396 {
397 	struct l64781_state* state = fe->demodulator_priv;
398 
399 	u8 gain = l64781_readreg (state, 0x0e);
400 	*signal_strength = (gain << 8) | gain;
401 
402 	return 0;
403 }
404 
l64781_read_snr(struct dvb_frontend * fe,u16 * snr)405 static int l64781_read_snr(struct dvb_frontend* fe, u16* snr)
406 {
407 	struct l64781_state* state = fe->demodulator_priv;
408 
409 	u8 avg_quality = 0xff - l64781_readreg (state, 0x33);
410 	*snr = (avg_quality << 8) | avg_quality; /* not exact, but...*/
411 
412 	return 0;
413 }
414 
l64781_read_ucblocks(struct dvb_frontend * fe,u32 * ucblocks)415 static int l64781_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
416 {
417 	struct l64781_state* state = fe->demodulator_priv;
418 
419 	*ucblocks = l64781_readreg (state, 0x37)
420 	   | (l64781_readreg (state, 0x38) << 8);
421 
422 	return 0;
423 }
424 
l64781_sleep(struct dvb_frontend * fe)425 static int l64781_sleep(struct dvb_frontend* fe)
426 {
427 	struct l64781_state* state = fe->demodulator_priv;
428 
429 	/* Power down */
430 	return l64781_writereg (state, 0x3e, 0x5a);
431 }
432 
l64781_init(struct dvb_frontend * fe)433 static int l64781_init(struct dvb_frontend* fe)
434 {
435 	struct l64781_state* state = fe->demodulator_priv;
436 
437 	reset_and_configure (state);
438 
439 	/* Power up */
440 	l64781_writereg (state, 0x3e, 0xa5);
441 
442 	/* Reset hard */
443 	l64781_writereg (state, 0x2a, 0x04);
444 	l64781_writereg (state, 0x2a, 0x00);
445 
446 	/* Set tuner specific things */
447 	/* AFC_POL, set also in reset_afc */
448 	l64781_writereg (state, 0x07, 0x8e);
449 
450 	/* Use internal ADC */
451 	l64781_writereg (state, 0x0b, 0x81);
452 
453 	/* AGC loop gain, and polarity is positive */
454 	l64781_writereg (state, 0x0c, 0x84);
455 
456 	/* Internal ADC outputs two's complement */
457 	l64781_writereg (state, 0x0d, 0x8c);
458 
459 	/* With ppm=8000, it seems the DTR_SENSITIVITY will result in
460 	   value of 2 with all possible bandwidths and guard
461 	   intervals, which is the initial value anyway. */
462 	/*l64781_writereg (state, 0x19, 0x92);*/
463 
464 	/* Everything is two's complement, soft bit and CSI_OUT too */
465 	l64781_writereg (state, 0x1e, 0x09);
466 
467 	/* delay a bit after first init attempt */
468 	if (state->first) {
469 		state->first = 0;
470 		msleep(200);
471 	}
472 
473 	return 0;
474 }
475 
l64781_get_tune_settings(struct dvb_frontend * fe,struct dvb_frontend_tune_settings * fesettings)476 static int l64781_get_tune_settings(struct dvb_frontend* fe,
477 				    struct dvb_frontend_tune_settings* fesettings)
478 {
479 	fesettings->min_delay_ms = 4000;
480 	fesettings->step_size = 0;
481 	fesettings->max_drift = 0;
482 	return 0;
483 }
484 
l64781_release(struct dvb_frontend * fe)485 static void l64781_release(struct dvb_frontend* fe)
486 {
487 	struct l64781_state* state = fe->demodulator_priv;
488 	kfree(state);
489 }
490 
491 static struct dvb_frontend_ops l64781_ops;
492 
l64781_attach(const struct l64781_config * config,struct i2c_adapter * i2c)493 struct dvb_frontend* l64781_attach(const struct l64781_config* config,
494 				   struct i2c_adapter* i2c)
495 {
496 	struct l64781_state* state = NULL;
497 	int reg0x3e = -1;
498 	u8 b0 [] = { 0x1a };
499 	u8 b1 [] = { 0x00 };
500 	struct i2c_msg msg [] = { { .addr = config->demod_address, .flags = 0, .buf = b0, .len = 1 },
501 			   { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
502 
503 	/* allocate memory for the internal state */
504 	state = kmalloc(sizeof(struct l64781_state), GFP_KERNEL);
505 	if (state == NULL) goto error;
506 
507 	/* setup the state */
508 	state->config = config;
509 	state->i2c = i2c;
510 	state->first = 1;
511 
512 	/**
513 	 *  the L64781 won't show up before we send the reset_and_configure()
514 	 *  broadcast. If nothing responds there is no L64781 on the bus...
515 	 */
516 	if (reset_and_configure(state) < 0) {
517 		dprintk("No response to reset and configure broadcast...\n");
518 		goto error;
519 	}
520 
521 	/* The chip always responds to reads */
522 	if (i2c_transfer(state->i2c, msg, 2) != 2) {
523 		dprintk("No response to read on I2C bus\n");
524 		goto error;
525 	}
526 
527 	/* Save current register contents for bailout */
528 	reg0x3e = l64781_readreg(state, 0x3e);
529 
530 	/* Reading the POWER_DOWN register always returns 0 */
531 	if (reg0x3e != 0) {
532 		dprintk("Device doesn't look like L64781\n");
533 		goto error;
534 	}
535 
536 	/* Turn the chip off */
537 	l64781_writereg (state, 0x3e, 0x5a);
538 
539 	/* Responds to all reads with 0 */
540 	if (l64781_readreg(state, 0x1a) != 0) {
541 		dprintk("Read 1 returned unexpcted value\n");
542 		goto error;
543 	}
544 
545 	/* Turn the chip on */
546 	l64781_writereg (state, 0x3e, 0xa5);
547 
548 	/* Responds with register default value */
549 	if (l64781_readreg(state, 0x1a) != 0xa1) {
550 		dprintk("Read 2 returned unexpcted value\n");
551 		goto error;
552 	}
553 
554 	/* create dvb_frontend */
555 	memcpy(&state->frontend.ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
556 	state->frontend.demodulator_priv = state;
557 	return &state->frontend;
558 
559 error:
560 	if (reg0x3e >= 0)
561 		l64781_writereg (state, 0x3e, reg0x3e);  /* restore reg 0x3e */
562 	kfree(state);
563 	return NULL;
564 }
565 
566 static struct dvb_frontend_ops l64781_ops = {
567 
568 	.info = {
569 		.name = "LSI L64781 DVB-T",
570 		.type = FE_OFDM,
571 	/*	.frequency_min = ???,*/
572 	/*	.frequency_max = ???,*/
573 		.frequency_stepsize = 166666,
574 	/*      .frequency_tolerance = ???,*/
575 	/*      .symbol_rate_tolerance = ???,*/
576 		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
577 		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
578 		      FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
579 		      FE_CAN_MUTE_TS
580 	},
581 
582 	.release = l64781_release,
583 
584 	.init = l64781_init,
585 	.sleep = l64781_sleep,
586 
587 	.set_frontend = apply_frontend_param,
588 	.get_frontend = get_frontend,
589 	.get_tune_settings = l64781_get_tune_settings,
590 
591 	.read_status = l64781_read_status,
592 	.read_ber = l64781_read_ber,
593 	.read_signal_strength = l64781_read_signal_strength,
594 	.read_snr = l64781_read_snr,
595 	.read_ucblocks = l64781_read_ucblocks,
596 };
597 
598 MODULE_DESCRIPTION("LSI L64781 DVB-T Demodulator driver");
599 MODULE_AUTHOR("Holger Waechtler, Marko Kohtala");
600 MODULE_LICENSE("GPL");
601 
602 EXPORT_SYMBOL(l64781_attach);
603