xref: /openbmc/linux/drivers/media/dvb-frontends/l64781.c (revision 830e4b55b02b8a2638958e4249eba71797940ee5)
19a0bf528SMauro Carvalho Chehab /*
29a0bf528SMauro Carvalho Chehab     driver for LSI L64781 COFDM demodulator
39a0bf528SMauro Carvalho Chehab 
49a0bf528SMauro Carvalho Chehab     Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH
59a0bf528SMauro Carvalho Chehab 		       Marko Kohtala <marko.kohtala@luukku.com>
69a0bf528SMauro Carvalho Chehab 
79a0bf528SMauro Carvalho Chehab     This program is free software; you can redistribute it and/or modify
89a0bf528SMauro Carvalho Chehab     it under the terms of the GNU General Public License as published by
99a0bf528SMauro Carvalho Chehab     the Free Software Foundation; either version 2 of the License, or
109a0bf528SMauro Carvalho Chehab     (at your option) any later version.
119a0bf528SMauro Carvalho Chehab 
129a0bf528SMauro Carvalho Chehab     This program is distributed in the hope that it will be useful,
139a0bf528SMauro Carvalho Chehab     but WITHOUT ANY WARRANTY; without even the implied warranty of
149a0bf528SMauro Carvalho Chehab     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
159a0bf528SMauro Carvalho Chehab     GNU General Public License for more details.
169a0bf528SMauro Carvalho Chehab 
179a0bf528SMauro Carvalho Chehab     You should have received a copy of the GNU General Public License
189a0bf528SMauro Carvalho Chehab     along with this program; if not, write to the Free Software
199a0bf528SMauro Carvalho Chehab     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
209a0bf528SMauro Carvalho Chehab 
219a0bf528SMauro Carvalho Chehab */
229a0bf528SMauro Carvalho Chehab 
239a0bf528SMauro Carvalho Chehab #include <linux/init.h>
249a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
259a0bf528SMauro Carvalho Chehab #include <linux/module.h>
269a0bf528SMauro Carvalho Chehab #include <linux/string.h>
279a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
289a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h"
299a0bf528SMauro Carvalho Chehab #include "l64781.h"
309a0bf528SMauro Carvalho Chehab 
319a0bf528SMauro Carvalho Chehab 
329a0bf528SMauro Carvalho Chehab struct l64781_state {
339a0bf528SMauro Carvalho Chehab 	struct i2c_adapter* i2c;
349a0bf528SMauro Carvalho Chehab 	const struct l64781_config* config;
359a0bf528SMauro Carvalho Chehab 	struct dvb_frontend frontend;
369a0bf528SMauro Carvalho Chehab 
379a0bf528SMauro Carvalho Chehab 	/* private demodulator data */
389a0bf528SMauro Carvalho Chehab 	unsigned int first:1;
399a0bf528SMauro Carvalho Chehab };
409a0bf528SMauro Carvalho Chehab 
419a0bf528SMauro Carvalho Chehab #define dprintk(args...) \
429a0bf528SMauro Carvalho Chehab 	do { \
439a0bf528SMauro Carvalho Chehab 		if (debug) printk(KERN_DEBUG "l64781: " args); \
449a0bf528SMauro Carvalho Chehab 	} while (0)
459a0bf528SMauro Carvalho Chehab 
469a0bf528SMauro Carvalho Chehab static int debug;
479a0bf528SMauro Carvalho Chehab 
489a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
499a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
509a0bf528SMauro Carvalho Chehab 
519a0bf528SMauro Carvalho Chehab 
529a0bf528SMauro Carvalho Chehab static int l64781_writereg (struct l64781_state* state, u8 reg, u8 data)
539a0bf528SMauro Carvalho Chehab {
549a0bf528SMauro Carvalho Chehab 	int ret;
559a0bf528SMauro Carvalho Chehab 	u8 buf [] = { reg, data };
569a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
579a0bf528SMauro Carvalho Chehab 
589a0bf528SMauro Carvalho Chehab 	if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1)
599a0bf528SMauro Carvalho Chehab 		dprintk ("%s: write_reg error (reg == %02x) = %02x!\n",
609a0bf528SMauro Carvalho Chehab 			 __func__, reg, ret);
619a0bf528SMauro Carvalho Chehab 
629a0bf528SMauro Carvalho Chehab 	return (ret != 1) ? -1 : 0;
639a0bf528SMauro Carvalho Chehab }
649a0bf528SMauro Carvalho Chehab 
659a0bf528SMauro Carvalho Chehab static int l64781_readreg (struct l64781_state* state, u8 reg)
669a0bf528SMauro Carvalho Chehab {
679a0bf528SMauro Carvalho Chehab 	int ret;
689a0bf528SMauro Carvalho Chehab 	u8 b0 [] = { reg };
699a0bf528SMauro Carvalho Chehab 	u8 b1 [] = { 0 };
709a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
719a0bf528SMauro Carvalho Chehab 			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
729a0bf528SMauro Carvalho Chehab 
739a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(state->i2c, msg, 2);
749a0bf528SMauro Carvalho Chehab 
759a0bf528SMauro Carvalho Chehab 	if (ret != 2) return ret;
769a0bf528SMauro Carvalho Chehab 
779a0bf528SMauro Carvalho Chehab 	return b1[0];
789a0bf528SMauro Carvalho Chehab }
799a0bf528SMauro Carvalho Chehab 
809a0bf528SMauro Carvalho Chehab static void apply_tps (struct l64781_state* state)
819a0bf528SMauro Carvalho Chehab {
829a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x2a, 0x00);
839a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x2a, 0x01);
849a0bf528SMauro Carvalho Chehab 
859a0bf528SMauro Carvalho Chehab 	/* This here is a little bit questionable because it enables
869a0bf528SMauro Carvalho Chehab 	   the automatic update of TPS registers. I think we'd need to
879a0bf528SMauro Carvalho Chehab 	   handle the IRQ from FE to update some other registers as
889a0bf528SMauro Carvalho Chehab 	   well, or at least implement some magic to tuning to correct
899a0bf528SMauro Carvalho Chehab 	   to the TPS received from transmission. */
909a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x2a, 0x02);
919a0bf528SMauro Carvalho Chehab }
929a0bf528SMauro Carvalho Chehab 
939a0bf528SMauro Carvalho Chehab 
949a0bf528SMauro Carvalho Chehab static void reset_afc (struct l64781_state* state)
959a0bf528SMauro Carvalho Chehab {
969a0bf528SMauro Carvalho Chehab 	/* Set AFC stall for the AFC_INIT_FRQ setting, TIM_STALL for
979a0bf528SMauro Carvalho Chehab 	   timing offset */
989a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x07, 0x9e); /* stall AFC */
999a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x08, 0);    /* AFC INIT FREQ */
1009a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x09, 0);
1019a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x0a, 0);
1029a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x07, 0x8e);
1039a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x0e, 0);    /* AGC gain to zero in beginning */
1049a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x11, 0x80); /* stall TIM */
1059a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x10, 0);    /* TIM_OFFSET_LSB */
1069a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x12, 0);
1079a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x13, 0);
1089a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x11, 0x00);
1099a0bf528SMauro Carvalho Chehab }
1109a0bf528SMauro Carvalho Chehab 
1119a0bf528SMauro Carvalho Chehab static int reset_and_configure (struct l64781_state* state)
1129a0bf528SMauro Carvalho Chehab {
1139a0bf528SMauro Carvalho Chehab 	u8 buf [] = { 0x06 };
1149a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 };
1159a0bf528SMauro Carvalho Chehab 	// NOTE: this is correct in writing to address 0x00
1169a0bf528SMauro Carvalho Chehab 
1179a0bf528SMauro Carvalho Chehab 	return (i2c_transfer(state->i2c, &msg, 1) == 1) ? 0 : -ENODEV;
1189a0bf528SMauro Carvalho Chehab }
1199a0bf528SMauro Carvalho Chehab 
1209a0bf528SMauro Carvalho Chehab static int apply_frontend_param(struct dvb_frontend *fe)
1219a0bf528SMauro Carvalho Chehab {
1229a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
1239a0bf528SMauro Carvalho Chehab 	struct l64781_state* state = fe->demodulator_priv;
1249a0bf528SMauro Carvalho Chehab 	/* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */
1259a0bf528SMauro Carvalho Chehab 	static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 };
1269a0bf528SMauro Carvalho Chehab 	/* QPSK, QAM_16, QAM_64 */
1279a0bf528SMauro Carvalho Chehab 	static const u8 qam_tab [] = { 2, 4, 0, 6 };
1289a0bf528SMauro Carvalho Chehab 	static const u8 guard_tab [] = { 1, 2, 4, 8 };
1299a0bf528SMauro Carvalho Chehab 	/* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */
1309a0bf528SMauro Carvalho Chehab 	static const u32 ppm = 8000;
1319a0bf528SMauro Carvalho Chehab 	u32 ddfs_offset_fixed;
1329a0bf528SMauro Carvalho Chehab /*	u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */
1339a0bf528SMauro Carvalho Chehab /*			bw_tab[p->bandWidth]<<10)/15625; */
1349a0bf528SMauro Carvalho Chehab 	u32 init_freq;
1359a0bf528SMauro Carvalho Chehab 	u32 spi_bias;
1369a0bf528SMauro Carvalho Chehab 	u8 val0x04;
1379a0bf528SMauro Carvalho Chehab 	u8 val0x05;
1389a0bf528SMauro Carvalho Chehab 	u8 val0x06;
1399a0bf528SMauro Carvalho Chehab 	int bw;
1409a0bf528SMauro Carvalho Chehab 
1419a0bf528SMauro Carvalho Chehab 	switch (p->bandwidth_hz) {
1429a0bf528SMauro Carvalho Chehab 	case 8000000:
1439a0bf528SMauro Carvalho Chehab 		bw = 8;
1449a0bf528SMauro Carvalho Chehab 		break;
1459a0bf528SMauro Carvalho Chehab 	case 7000000:
1469a0bf528SMauro Carvalho Chehab 		bw = 7;
1479a0bf528SMauro Carvalho Chehab 		break;
1489a0bf528SMauro Carvalho Chehab 	case 6000000:
1499a0bf528SMauro Carvalho Chehab 		bw = 6;
1509a0bf528SMauro Carvalho Chehab 		break;
1519a0bf528SMauro Carvalho Chehab 	default:
1529a0bf528SMauro Carvalho Chehab 		return -EINVAL;
1539a0bf528SMauro Carvalho Chehab 	}
1549a0bf528SMauro Carvalho Chehab 
1559a0bf528SMauro Carvalho Chehab 	if (fe->ops.tuner_ops.set_params) {
1569a0bf528SMauro Carvalho Chehab 		fe->ops.tuner_ops.set_params(fe);
1579a0bf528SMauro Carvalho Chehab 		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
1589a0bf528SMauro Carvalho Chehab 	}
1599a0bf528SMauro Carvalho Chehab 
1609a0bf528SMauro Carvalho Chehab 	if (p->inversion != INVERSION_ON &&
1619a0bf528SMauro Carvalho Chehab 	    p->inversion != INVERSION_OFF)
1629a0bf528SMauro Carvalho Chehab 		return -EINVAL;
1639a0bf528SMauro Carvalho Chehab 
1649a0bf528SMauro Carvalho Chehab 	if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 &&
1659a0bf528SMauro Carvalho Chehab 	    p->code_rate_HP != FEC_3_4 && p->code_rate_HP != FEC_5_6 &&
1669a0bf528SMauro Carvalho Chehab 	    p->code_rate_HP != FEC_7_8)
1679a0bf528SMauro Carvalho Chehab 		return -EINVAL;
1689a0bf528SMauro Carvalho Chehab 
1699a0bf528SMauro Carvalho Chehab 	if (p->hierarchy != HIERARCHY_NONE &&
1709a0bf528SMauro Carvalho Chehab 	    (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 &&
1719a0bf528SMauro Carvalho Chehab 	     p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 &&
1729a0bf528SMauro Carvalho Chehab 	     p->code_rate_LP != FEC_7_8))
1739a0bf528SMauro Carvalho Chehab 		return -EINVAL;
1749a0bf528SMauro Carvalho Chehab 
1759a0bf528SMauro Carvalho Chehab 	if (p->modulation != QPSK && p->modulation != QAM_16 &&
1769a0bf528SMauro Carvalho Chehab 	    p->modulation != QAM_64)
1779a0bf528SMauro Carvalho Chehab 		return -EINVAL;
1789a0bf528SMauro Carvalho Chehab 
1799a0bf528SMauro Carvalho Chehab 	if (p->transmission_mode != TRANSMISSION_MODE_2K &&
1809a0bf528SMauro Carvalho Chehab 	    p->transmission_mode != TRANSMISSION_MODE_8K)
1819a0bf528SMauro Carvalho Chehab 		return -EINVAL;
1829a0bf528SMauro Carvalho Chehab 
183*830e4b55SMauro Carvalho Chehab 	if ((int)p->guard_interval < GUARD_INTERVAL_1_32 ||
1849a0bf528SMauro Carvalho Chehab 	    p->guard_interval > GUARD_INTERVAL_1_4)
1859a0bf528SMauro Carvalho Chehab 		return -EINVAL;
1869a0bf528SMauro Carvalho Chehab 
187*830e4b55SMauro Carvalho Chehab 	if ((int)p->hierarchy < HIERARCHY_NONE ||
1889a0bf528SMauro Carvalho Chehab 	    p->hierarchy > HIERARCHY_4)
1899a0bf528SMauro Carvalho Chehab 		return -EINVAL;
1909a0bf528SMauro Carvalho Chehab 
1919a0bf528SMauro Carvalho Chehab 	ddfs_offset_fixed = 0x4000-(ppm<<16)/bw/1000000;
1929a0bf528SMauro Carvalho Chehab 
1939a0bf528SMauro Carvalho Chehab 	/* This works up to 20000 ppm, it overflows if too large ppm! */
1949a0bf528SMauro Carvalho Chehab 	init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) /
1959a0bf528SMauro Carvalho Chehab 			bw & 0xFFFFFF);
1969a0bf528SMauro Carvalho Chehab 
1979a0bf528SMauro Carvalho Chehab 	/* SPI bias calculation is slightly modified to fit in 32bit */
1989a0bf528SMauro Carvalho Chehab 	/* will work for high ppm only... */
1999a0bf528SMauro Carvalho Chehab 	spi_bias = 378 * (1 << 10);
2009a0bf528SMauro Carvalho Chehab 	spi_bias *= 16;
2019a0bf528SMauro Carvalho Chehab 	spi_bias *= bw;
2029a0bf528SMauro Carvalho Chehab 	spi_bias *= qam_tab[p->modulation];
2039a0bf528SMauro Carvalho Chehab 	spi_bias /= p->code_rate_HP + 1;
2049a0bf528SMauro Carvalho Chehab 	spi_bias /= (guard_tab[p->guard_interval] + 32);
2059a0bf528SMauro Carvalho Chehab 	spi_bias *= 1000;
2069a0bf528SMauro Carvalho Chehab 	spi_bias /= 1000 + ppm/1000;
2079a0bf528SMauro Carvalho Chehab 	spi_bias *= p->code_rate_HP;
2089a0bf528SMauro Carvalho Chehab 
2099a0bf528SMauro Carvalho Chehab 	val0x04 = (p->transmission_mode << 2) | p->guard_interval;
2109a0bf528SMauro Carvalho Chehab 	val0x05 = fec_tab[p->code_rate_HP];
2119a0bf528SMauro Carvalho Chehab 
2129a0bf528SMauro Carvalho Chehab 	if (p->hierarchy != HIERARCHY_NONE)
2139a0bf528SMauro Carvalho Chehab 		val0x05 |= (p->code_rate_LP - FEC_1_2) << 3;
2149a0bf528SMauro Carvalho Chehab 
2159a0bf528SMauro Carvalho Chehab 	val0x06 = (p->hierarchy << 2) | p->modulation;
2169a0bf528SMauro Carvalho Chehab 
2179a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x04, val0x04);
2189a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x05, val0x05);
2199a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x06, val0x06);
2209a0bf528SMauro Carvalho Chehab 
2219a0bf528SMauro Carvalho Chehab 	reset_afc (state);
2229a0bf528SMauro Carvalho Chehab 
2239a0bf528SMauro Carvalho Chehab 	/* Technical manual section 2.6.1, TIM_IIR_GAIN optimal values */
2249a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x15,
2259a0bf528SMauro Carvalho Chehab 			 p->transmission_mode == TRANSMISSION_MODE_2K ? 1 : 3);
2269a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x16, init_freq & 0xff);
2279a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x17, (init_freq >> 8) & 0xff);
2289a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x18, (init_freq >> 16) & 0xff);
2299a0bf528SMauro Carvalho Chehab 
2309a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x1b, spi_bias & 0xff);
2319a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x1c, (spi_bias >> 8) & 0xff);
2329a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x1d, ((spi_bias >> 16) & 0x7f) |
2339a0bf528SMauro Carvalho Chehab 		(p->inversion == INVERSION_ON ? 0x80 : 0x00));
2349a0bf528SMauro Carvalho Chehab 
2359a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x22, ddfs_offset_fixed & 0xff);
2369a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x23, (ddfs_offset_fixed >> 8) & 0x3f);
2379a0bf528SMauro Carvalho Chehab 
2389a0bf528SMauro Carvalho Chehab 	l64781_readreg (state, 0x00);  /*  clear interrupt registers... */
2399a0bf528SMauro Carvalho Chehab 	l64781_readreg (state, 0x01);  /*  dto. */
2409a0bf528SMauro Carvalho Chehab 
2419a0bf528SMauro Carvalho Chehab 	apply_tps (state);
2429a0bf528SMauro Carvalho Chehab 
2439a0bf528SMauro Carvalho Chehab 	return 0;
2449a0bf528SMauro Carvalho Chehab }
2459a0bf528SMauro Carvalho Chehab 
2469a0bf528SMauro Carvalho Chehab static int get_frontend(struct dvb_frontend *fe)
2479a0bf528SMauro Carvalho Chehab {
2489a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
2499a0bf528SMauro Carvalho Chehab 	struct l64781_state* state = fe->demodulator_priv;
2509a0bf528SMauro Carvalho Chehab 	int tmp;
2519a0bf528SMauro Carvalho Chehab 
2529a0bf528SMauro Carvalho Chehab 
2539a0bf528SMauro Carvalho Chehab 	tmp = l64781_readreg(state, 0x04);
2549a0bf528SMauro Carvalho Chehab 	switch(tmp & 3) {
2559a0bf528SMauro Carvalho Chehab 	case 0:
2569a0bf528SMauro Carvalho Chehab 		p->guard_interval = GUARD_INTERVAL_1_32;
2579a0bf528SMauro Carvalho Chehab 		break;
2589a0bf528SMauro Carvalho Chehab 	case 1:
2599a0bf528SMauro Carvalho Chehab 		p->guard_interval = GUARD_INTERVAL_1_16;
2609a0bf528SMauro Carvalho Chehab 		break;
2619a0bf528SMauro Carvalho Chehab 	case 2:
2629a0bf528SMauro Carvalho Chehab 		p->guard_interval = GUARD_INTERVAL_1_8;
2639a0bf528SMauro Carvalho Chehab 		break;
2649a0bf528SMauro Carvalho Chehab 	case 3:
2659a0bf528SMauro Carvalho Chehab 		p->guard_interval = GUARD_INTERVAL_1_4;
2669a0bf528SMauro Carvalho Chehab 		break;
2679a0bf528SMauro Carvalho Chehab 	}
2689a0bf528SMauro Carvalho Chehab 	switch((tmp >> 2) & 3) {
2699a0bf528SMauro Carvalho Chehab 	case 0:
2709a0bf528SMauro Carvalho Chehab 		p->transmission_mode = TRANSMISSION_MODE_2K;
2719a0bf528SMauro Carvalho Chehab 		break;
2729a0bf528SMauro Carvalho Chehab 	case 1:
2739a0bf528SMauro Carvalho Chehab 		p->transmission_mode = TRANSMISSION_MODE_8K;
2749a0bf528SMauro Carvalho Chehab 		break;
2759a0bf528SMauro Carvalho Chehab 	default:
2769a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "Unexpected value for transmission_mode\n");
2779a0bf528SMauro Carvalho Chehab 	}
2789a0bf528SMauro Carvalho Chehab 
2799a0bf528SMauro Carvalho Chehab 	tmp = l64781_readreg(state, 0x05);
2809a0bf528SMauro Carvalho Chehab 	switch(tmp & 7) {
2819a0bf528SMauro Carvalho Chehab 	case 0:
2829a0bf528SMauro Carvalho Chehab 		p->code_rate_HP = FEC_1_2;
2839a0bf528SMauro Carvalho Chehab 		break;
2849a0bf528SMauro Carvalho Chehab 	case 1:
2859a0bf528SMauro Carvalho Chehab 		p->code_rate_HP = FEC_2_3;
2869a0bf528SMauro Carvalho Chehab 		break;
2879a0bf528SMauro Carvalho Chehab 	case 2:
2889a0bf528SMauro Carvalho Chehab 		p->code_rate_HP = FEC_3_4;
2899a0bf528SMauro Carvalho Chehab 		break;
2909a0bf528SMauro Carvalho Chehab 	case 3:
2919a0bf528SMauro Carvalho Chehab 		p->code_rate_HP = FEC_5_6;
2929a0bf528SMauro Carvalho Chehab 		break;
2939a0bf528SMauro Carvalho Chehab 	case 4:
2949a0bf528SMauro Carvalho Chehab 		p->code_rate_HP = FEC_7_8;
2959a0bf528SMauro Carvalho Chehab 		break;
2969a0bf528SMauro Carvalho Chehab 	default:
2979a0bf528SMauro Carvalho Chehab 		printk("Unexpected value for code_rate_HP\n");
2989a0bf528SMauro Carvalho Chehab 	}
2999a0bf528SMauro Carvalho Chehab 	switch((tmp >> 3) & 7) {
3009a0bf528SMauro Carvalho Chehab 	case 0:
3019a0bf528SMauro Carvalho Chehab 		p->code_rate_LP = FEC_1_2;
3029a0bf528SMauro Carvalho Chehab 		break;
3039a0bf528SMauro Carvalho Chehab 	case 1:
3049a0bf528SMauro Carvalho Chehab 		p->code_rate_LP = FEC_2_3;
3059a0bf528SMauro Carvalho Chehab 		break;
3069a0bf528SMauro Carvalho Chehab 	case 2:
3079a0bf528SMauro Carvalho Chehab 		p->code_rate_LP = FEC_3_4;
3089a0bf528SMauro Carvalho Chehab 		break;
3099a0bf528SMauro Carvalho Chehab 	case 3:
3109a0bf528SMauro Carvalho Chehab 		p->code_rate_LP = FEC_5_6;
3119a0bf528SMauro Carvalho Chehab 		break;
3129a0bf528SMauro Carvalho Chehab 	case 4:
3139a0bf528SMauro Carvalho Chehab 		p->code_rate_LP = FEC_7_8;
3149a0bf528SMauro Carvalho Chehab 		break;
3159a0bf528SMauro Carvalho Chehab 	default:
3169a0bf528SMauro Carvalho Chehab 		printk("Unexpected value for code_rate_LP\n");
3179a0bf528SMauro Carvalho Chehab 	}
3189a0bf528SMauro Carvalho Chehab 
3199a0bf528SMauro Carvalho Chehab 	tmp = l64781_readreg(state, 0x06);
3209a0bf528SMauro Carvalho Chehab 	switch(tmp & 3) {
3219a0bf528SMauro Carvalho Chehab 	case 0:
3229a0bf528SMauro Carvalho Chehab 		p->modulation = QPSK;
3239a0bf528SMauro Carvalho Chehab 		break;
3249a0bf528SMauro Carvalho Chehab 	case 1:
3259a0bf528SMauro Carvalho Chehab 		p->modulation = QAM_16;
3269a0bf528SMauro Carvalho Chehab 		break;
3279a0bf528SMauro Carvalho Chehab 	case 2:
3289a0bf528SMauro Carvalho Chehab 		p->modulation = QAM_64;
3299a0bf528SMauro Carvalho Chehab 		break;
3309a0bf528SMauro Carvalho Chehab 	default:
3319a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "Unexpected value for modulation\n");
3329a0bf528SMauro Carvalho Chehab 	}
3339a0bf528SMauro Carvalho Chehab 	switch((tmp >> 2) & 7) {
3349a0bf528SMauro Carvalho Chehab 	case 0:
3359a0bf528SMauro Carvalho Chehab 		p->hierarchy = HIERARCHY_NONE;
3369a0bf528SMauro Carvalho Chehab 		break;
3379a0bf528SMauro Carvalho Chehab 	case 1:
3389a0bf528SMauro Carvalho Chehab 		p->hierarchy = HIERARCHY_1;
3399a0bf528SMauro Carvalho Chehab 		break;
3409a0bf528SMauro Carvalho Chehab 	case 2:
3419a0bf528SMauro Carvalho Chehab 		p->hierarchy = HIERARCHY_2;
3429a0bf528SMauro Carvalho Chehab 		break;
3439a0bf528SMauro Carvalho Chehab 	case 3:
3449a0bf528SMauro Carvalho Chehab 		p->hierarchy = HIERARCHY_4;
3459a0bf528SMauro Carvalho Chehab 		break;
3469a0bf528SMauro Carvalho Chehab 	default:
3479a0bf528SMauro Carvalho Chehab 		printk("Unexpected value for hierarchy\n");
3489a0bf528SMauro Carvalho Chehab 	}
3499a0bf528SMauro Carvalho Chehab 
3509a0bf528SMauro Carvalho Chehab 
3519a0bf528SMauro Carvalho Chehab 	tmp = l64781_readreg (state, 0x1d);
3529a0bf528SMauro Carvalho Chehab 	p->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF;
3539a0bf528SMauro Carvalho Chehab 
3549a0bf528SMauro Carvalho Chehab 	tmp = (int) (l64781_readreg (state, 0x08) |
3559a0bf528SMauro Carvalho Chehab 		     (l64781_readreg (state, 0x09) << 8) |
3569a0bf528SMauro Carvalho Chehab 		     (l64781_readreg (state, 0x0a) << 16));
3579a0bf528SMauro Carvalho Chehab 	p->frequency += tmp;
3589a0bf528SMauro Carvalho Chehab 
3599a0bf528SMauro Carvalho Chehab 	return 0;
3609a0bf528SMauro Carvalho Chehab }
3619a0bf528SMauro Carvalho Chehab 
3629a0bf528SMauro Carvalho Chehab static int l64781_read_status(struct dvb_frontend* fe, fe_status_t* status)
3639a0bf528SMauro Carvalho Chehab {
3649a0bf528SMauro Carvalho Chehab 	struct l64781_state* state = fe->demodulator_priv;
3659a0bf528SMauro Carvalho Chehab 	int sync = l64781_readreg (state, 0x32);
3669a0bf528SMauro Carvalho Chehab 	int gain = l64781_readreg (state, 0x0e);
3679a0bf528SMauro Carvalho Chehab 
3689a0bf528SMauro Carvalho Chehab 	l64781_readreg (state, 0x00);  /*  clear interrupt registers... */
3699a0bf528SMauro Carvalho Chehab 	l64781_readreg (state, 0x01);  /*  dto. */
3709a0bf528SMauro Carvalho Chehab 
3719a0bf528SMauro Carvalho Chehab 	*status = 0;
3729a0bf528SMauro Carvalho Chehab 
3739a0bf528SMauro Carvalho Chehab 	if (gain > 5)
3749a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SIGNAL;
3759a0bf528SMauro Carvalho Chehab 
3769a0bf528SMauro Carvalho Chehab 	if (sync & 0x02) /* VCXO locked, this criteria should be ok */
3779a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_CARRIER;
3789a0bf528SMauro Carvalho Chehab 
3799a0bf528SMauro Carvalho Chehab 	if (sync & 0x20)
3809a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_VITERBI;
3819a0bf528SMauro Carvalho Chehab 
3829a0bf528SMauro Carvalho Chehab 	if (sync & 0x40)
3839a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SYNC;
3849a0bf528SMauro Carvalho Chehab 
3859a0bf528SMauro Carvalho Chehab 	if (sync == 0x7f)
3869a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_LOCK;
3879a0bf528SMauro Carvalho Chehab 
3889a0bf528SMauro Carvalho Chehab 	return 0;
3899a0bf528SMauro Carvalho Chehab }
3909a0bf528SMauro Carvalho Chehab 
3919a0bf528SMauro Carvalho Chehab static int l64781_read_ber(struct dvb_frontend* fe, u32* ber)
3929a0bf528SMauro Carvalho Chehab {
3939a0bf528SMauro Carvalho Chehab 	struct l64781_state* state = fe->demodulator_priv;
3949a0bf528SMauro Carvalho Chehab 
3959a0bf528SMauro Carvalho Chehab 	/*   XXX FIXME: set up counting period (reg 0x26...0x28)
3969a0bf528SMauro Carvalho Chehab 	 */
3979a0bf528SMauro Carvalho Chehab 	*ber = l64781_readreg (state, 0x39)
3989a0bf528SMauro Carvalho Chehab 	    | (l64781_readreg (state, 0x3a) << 8);
3999a0bf528SMauro Carvalho Chehab 
4009a0bf528SMauro Carvalho Chehab 	return 0;
4019a0bf528SMauro Carvalho Chehab }
4029a0bf528SMauro Carvalho Chehab 
4039a0bf528SMauro Carvalho Chehab static int l64781_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
4049a0bf528SMauro Carvalho Chehab {
4059a0bf528SMauro Carvalho Chehab 	struct l64781_state* state = fe->demodulator_priv;
4069a0bf528SMauro Carvalho Chehab 
4079a0bf528SMauro Carvalho Chehab 	u8 gain = l64781_readreg (state, 0x0e);
4089a0bf528SMauro Carvalho Chehab 	*signal_strength = (gain << 8) | gain;
4099a0bf528SMauro Carvalho Chehab 
4109a0bf528SMauro Carvalho Chehab 	return 0;
4119a0bf528SMauro Carvalho Chehab }
4129a0bf528SMauro Carvalho Chehab 
4139a0bf528SMauro Carvalho Chehab static int l64781_read_snr(struct dvb_frontend* fe, u16* snr)
4149a0bf528SMauro Carvalho Chehab {
4159a0bf528SMauro Carvalho Chehab 	struct l64781_state* state = fe->demodulator_priv;
4169a0bf528SMauro Carvalho Chehab 
4179a0bf528SMauro Carvalho Chehab 	u8 avg_quality = 0xff - l64781_readreg (state, 0x33);
4189a0bf528SMauro Carvalho Chehab 	*snr = (avg_quality << 8) | avg_quality; /* not exact, but...*/
4199a0bf528SMauro Carvalho Chehab 
4209a0bf528SMauro Carvalho Chehab 	return 0;
4219a0bf528SMauro Carvalho Chehab }
4229a0bf528SMauro Carvalho Chehab 
4239a0bf528SMauro Carvalho Chehab static int l64781_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
4249a0bf528SMauro Carvalho Chehab {
4259a0bf528SMauro Carvalho Chehab 	struct l64781_state* state = fe->demodulator_priv;
4269a0bf528SMauro Carvalho Chehab 
4279a0bf528SMauro Carvalho Chehab 	*ucblocks = l64781_readreg (state, 0x37)
4289a0bf528SMauro Carvalho Chehab 	   | (l64781_readreg (state, 0x38) << 8);
4299a0bf528SMauro Carvalho Chehab 
4309a0bf528SMauro Carvalho Chehab 	return 0;
4319a0bf528SMauro Carvalho Chehab }
4329a0bf528SMauro Carvalho Chehab 
4339a0bf528SMauro Carvalho Chehab static int l64781_sleep(struct dvb_frontend* fe)
4349a0bf528SMauro Carvalho Chehab {
4359a0bf528SMauro Carvalho Chehab 	struct l64781_state* state = fe->demodulator_priv;
4369a0bf528SMauro Carvalho Chehab 
4379a0bf528SMauro Carvalho Chehab 	/* Power down */
4389a0bf528SMauro Carvalho Chehab 	return l64781_writereg (state, 0x3e, 0x5a);
4399a0bf528SMauro Carvalho Chehab }
4409a0bf528SMauro Carvalho Chehab 
4419a0bf528SMauro Carvalho Chehab static int l64781_init(struct dvb_frontend* fe)
4429a0bf528SMauro Carvalho Chehab {
4439a0bf528SMauro Carvalho Chehab 	struct l64781_state* state = fe->demodulator_priv;
4449a0bf528SMauro Carvalho Chehab 
4459a0bf528SMauro Carvalho Chehab 	reset_and_configure (state);
4469a0bf528SMauro Carvalho Chehab 
4479a0bf528SMauro Carvalho Chehab 	/* Power up */
4489a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x3e, 0xa5);
4499a0bf528SMauro Carvalho Chehab 
4509a0bf528SMauro Carvalho Chehab 	/* Reset hard */
4519a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x2a, 0x04);
4529a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x2a, 0x00);
4539a0bf528SMauro Carvalho Chehab 
4549a0bf528SMauro Carvalho Chehab 	/* Set tuner specific things */
4559a0bf528SMauro Carvalho Chehab 	/* AFC_POL, set also in reset_afc */
4569a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x07, 0x8e);
4579a0bf528SMauro Carvalho Chehab 
4589a0bf528SMauro Carvalho Chehab 	/* Use internal ADC */
4599a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x0b, 0x81);
4609a0bf528SMauro Carvalho Chehab 
4619a0bf528SMauro Carvalho Chehab 	/* AGC loop gain, and polarity is positive */
4629a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x0c, 0x84);
4639a0bf528SMauro Carvalho Chehab 
4649a0bf528SMauro Carvalho Chehab 	/* Internal ADC outputs two's complement */
4659a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x0d, 0x8c);
4669a0bf528SMauro Carvalho Chehab 
4679a0bf528SMauro Carvalho Chehab 	/* With ppm=8000, it seems the DTR_SENSITIVITY will result in
4689a0bf528SMauro Carvalho Chehab 	   value of 2 with all possible bandwidths and guard
4699a0bf528SMauro Carvalho Chehab 	   intervals, which is the initial value anyway. */
4709a0bf528SMauro Carvalho Chehab 	/*l64781_writereg (state, 0x19, 0x92);*/
4719a0bf528SMauro Carvalho Chehab 
4729a0bf528SMauro Carvalho Chehab 	/* Everything is two's complement, soft bit and CSI_OUT too */
4739a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x1e, 0x09);
4749a0bf528SMauro Carvalho Chehab 
4759a0bf528SMauro Carvalho Chehab 	/* delay a bit after first init attempt */
4769a0bf528SMauro Carvalho Chehab 	if (state->first) {
4779a0bf528SMauro Carvalho Chehab 		state->first = 0;
4789a0bf528SMauro Carvalho Chehab 		msleep(200);
4799a0bf528SMauro Carvalho Chehab 	}
4809a0bf528SMauro Carvalho Chehab 
4819a0bf528SMauro Carvalho Chehab 	return 0;
4829a0bf528SMauro Carvalho Chehab }
4839a0bf528SMauro Carvalho Chehab 
4849a0bf528SMauro Carvalho Chehab static int l64781_get_tune_settings(struct dvb_frontend* fe,
4859a0bf528SMauro Carvalho Chehab 				    struct dvb_frontend_tune_settings* fesettings)
4869a0bf528SMauro Carvalho Chehab {
4879a0bf528SMauro Carvalho Chehab 	fesettings->min_delay_ms = 4000;
4889a0bf528SMauro Carvalho Chehab 	fesettings->step_size = 0;
4899a0bf528SMauro Carvalho Chehab 	fesettings->max_drift = 0;
4909a0bf528SMauro Carvalho Chehab 	return 0;
4919a0bf528SMauro Carvalho Chehab }
4929a0bf528SMauro Carvalho Chehab 
4939a0bf528SMauro Carvalho Chehab static void l64781_release(struct dvb_frontend* fe)
4949a0bf528SMauro Carvalho Chehab {
4959a0bf528SMauro Carvalho Chehab 	struct l64781_state* state = fe->demodulator_priv;
4969a0bf528SMauro Carvalho Chehab 	kfree(state);
4979a0bf528SMauro Carvalho Chehab }
4989a0bf528SMauro Carvalho Chehab 
4999a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops l64781_ops;
5009a0bf528SMauro Carvalho Chehab 
5019a0bf528SMauro Carvalho Chehab struct dvb_frontend* l64781_attach(const struct l64781_config* config,
5029a0bf528SMauro Carvalho Chehab 				   struct i2c_adapter* i2c)
5039a0bf528SMauro Carvalho Chehab {
5049a0bf528SMauro Carvalho Chehab 	struct l64781_state* state = NULL;
5059a0bf528SMauro Carvalho Chehab 	int reg0x3e = -1;
5069a0bf528SMauro Carvalho Chehab 	u8 b0 [] = { 0x1a };
5079a0bf528SMauro Carvalho Chehab 	u8 b1 [] = { 0x00 };
5089a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg [] = { { .addr = config->demod_address, .flags = 0, .buf = b0, .len = 1 },
5099a0bf528SMauro Carvalho Chehab 			   { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
5109a0bf528SMauro Carvalho Chehab 
5119a0bf528SMauro Carvalho Chehab 	/* allocate memory for the internal state */
5129a0bf528SMauro Carvalho Chehab 	state = kzalloc(sizeof(struct l64781_state), GFP_KERNEL);
5139a0bf528SMauro Carvalho Chehab 	if (state == NULL) goto error;
5149a0bf528SMauro Carvalho Chehab 
5159a0bf528SMauro Carvalho Chehab 	/* setup the state */
5169a0bf528SMauro Carvalho Chehab 	state->config = config;
5179a0bf528SMauro Carvalho Chehab 	state->i2c = i2c;
5189a0bf528SMauro Carvalho Chehab 	state->first = 1;
5199a0bf528SMauro Carvalho Chehab 
5209a0bf528SMauro Carvalho Chehab 	/**
5219a0bf528SMauro Carvalho Chehab 	 *  the L64781 won't show up before we send the reset_and_configure()
5229a0bf528SMauro Carvalho Chehab 	 *  broadcast. If nothing responds there is no L64781 on the bus...
5239a0bf528SMauro Carvalho Chehab 	 */
5249a0bf528SMauro Carvalho Chehab 	if (reset_and_configure(state) < 0) {
5259a0bf528SMauro Carvalho Chehab 		dprintk("No response to reset and configure broadcast...\n");
5269a0bf528SMauro Carvalho Chehab 		goto error;
5279a0bf528SMauro Carvalho Chehab 	}
5289a0bf528SMauro Carvalho Chehab 
5299a0bf528SMauro Carvalho Chehab 	/* The chip always responds to reads */
5309a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(state->i2c, msg, 2) != 2) {
5319a0bf528SMauro Carvalho Chehab 		dprintk("No response to read on I2C bus\n");
5329a0bf528SMauro Carvalho Chehab 		goto error;
5339a0bf528SMauro Carvalho Chehab 	}
5349a0bf528SMauro Carvalho Chehab 
5359a0bf528SMauro Carvalho Chehab 	/* Save current register contents for bailout */
5369a0bf528SMauro Carvalho Chehab 	reg0x3e = l64781_readreg(state, 0x3e);
5379a0bf528SMauro Carvalho Chehab 
5389a0bf528SMauro Carvalho Chehab 	/* Reading the POWER_DOWN register always returns 0 */
5399a0bf528SMauro Carvalho Chehab 	if (reg0x3e != 0) {
5409a0bf528SMauro Carvalho Chehab 		dprintk("Device doesn't look like L64781\n");
5419a0bf528SMauro Carvalho Chehab 		goto error;
5429a0bf528SMauro Carvalho Chehab 	}
5439a0bf528SMauro Carvalho Chehab 
5449a0bf528SMauro Carvalho Chehab 	/* Turn the chip off */
5459a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x3e, 0x5a);
5469a0bf528SMauro Carvalho Chehab 
5479a0bf528SMauro Carvalho Chehab 	/* Responds to all reads with 0 */
5489a0bf528SMauro Carvalho Chehab 	if (l64781_readreg(state, 0x1a) != 0) {
5499a0bf528SMauro Carvalho Chehab 		dprintk("Read 1 returned unexpcted value\n");
5509a0bf528SMauro Carvalho Chehab 		goto error;
5519a0bf528SMauro Carvalho Chehab 	}
5529a0bf528SMauro Carvalho Chehab 
5539a0bf528SMauro Carvalho Chehab 	/* Turn the chip on */
5549a0bf528SMauro Carvalho Chehab 	l64781_writereg (state, 0x3e, 0xa5);
5559a0bf528SMauro Carvalho Chehab 
5569a0bf528SMauro Carvalho Chehab 	/* Responds with register default value */
5579a0bf528SMauro Carvalho Chehab 	if (l64781_readreg(state, 0x1a) != 0xa1) {
5589a0bf528SMauro Carvalho Chehab 		dprintk("Read 2 returned unexpcted value\n");
5599a0bf528SMauro Carvalho Chehab 		goto error;
5609a0bf528SMauro Carvalho Chehab 	}
5619a0bf528SMauro Carvalho Chehab 
5629a0bf528SMauro Carvalho Chehab 	/* create dvb_frontend */
5639a0bf528SMauro Carvalho Chehab 	memcpy(&state->frontend.ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
5649a0bf528SMauro Carvalho Chehab 	state->frontend.demodulator_priv = state;
5659a0bf528SMauro Carvalho Chehab 	return &state->frontend;
5669a0bf528SMauro Carvalho Chehab 
5679a0bf528SMauro Carvalho Chehab error:
5689a0bf528SMauro Carvalho Chehab 	if (reg0x3e >= 0)
5699a0bf528SMauro Carvalho Chehab 		l64781_writereg (state, 0x3e, reg0x3e);  /* restore reg 0x3e */
5709a0bf528SMauro Carvalho Chehab 	kfree(state);
5719a0bf528SMauro Carvalho Chehab 	return NULL;
5729a0bf528SMauro Carvalho Chehab }
5739a0bf528SMauro Carvalho Chehab 
5749a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops l64781_ops = {
5759a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_DVBT },
5769a0bf528SMauro Carvalho Chehab 	.info = {
5779a0bf528SMauro Carvalho Chehab 		.name = "LSI L64781 DVB-T",
5789a0bf528SMauro Carvalho Chehab 	/*	.frequency_min = ???,*/
5799a0bf528SMauro Carvalho Chehab 	/*	.frequency_max = ???,*/
5809a0bf528SMauro Carvalho Chehab 		.frequency_stepsize = 166666,
5819a0bf528SMauro Carvalho Chehab 	/*      .frequency_tolerance = ???,*/
5829a0bf528SMauro Carvalho Chehab 	/*      .symbol_rate_tolerance = ???,*/
5839a0bf528SMauro Carvalho Chehab 		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
5849a0bf528SMauro Carvalho Chehab 		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
5859a0bf528SMauro Carvalho Chehab 		      FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
5869a0bf528SMauro Carvalho Chehab 		      FE_CAN_MUTE_TS
5879a0bf528SMauro Carvalho Chehab 	},
5889a0bf528SMauro Carvalho Chehab 
5899a0bf528SMauro Carvalho Chehab 	.release = l64781_release,
5909a0bf528SMauro Carvalho Chehab 
5919a0bf528SMauro Carvalho Chehab 	.init = l64781_init,
5929a0bf528SMauro Carvalho Chehab 	.sleep = l64781_sleep,
5939a0bf528SMauro Carvalho Chehab 
5949a0bf528SMauro Carvalho Chehab 	.set_frontend = apply_frontend_param,
5959a0bf528SMauro Carvalho Chehab 	.get_frontend = get_frontend,
5969a0bf528SMauro Carvalho Chehab 	.get_tune_settings = l64781_get_tune_settings,
5979a0bf528SMauro Carvalho Chehab 
5989a0bf528SMauro Carvalho Chehab 	.read_status = l64781_read_status,
5999a0bf528SMauro Carvalho Chehab 	.read_ber = l64781_read_ber,
6009a0bf528SMauro Carvalho Chehab 	.read_signal_strength = l64781_read_signal_strength,
6019a0bf528SMauro Carvalho Chehab 	.read_snr = l64781_read_snr,
6029a0bf528SMauro Carvalho Chehab 	.read_ucblocks = l64781_read_ucblocks,
6039a0bf528SMauro Carvalho Chehab };
6049a0bf528SMauro Carvalho Chehab 
6059a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("LSI L64781 DVB-T Demodulator driver");
6069a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Holger Waechtler, Marko Kohtala");
6079a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
6089a0bf528SMauro Carvalho Chehab 
6099a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(l64781_attach);
610