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