xref: /openbmc/linux/drivers/media/dvb-frontends/or51211.c (revision 9a0bf528b4d66b605f02634236da085595c22101)
1*9a0bf528SMauro Carvalho Chehab /*
2*9a0bf528SMauro Carvalho Chehab  *    Support for OR51211 (pcHDTV HD-2000) - VSB
3*9a0bf528SMauro Carvalho Chehab  *
4*9a0bf528SMauro Carvalho Chehab  *    Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com>
5*9a0bf528SMauro Carvalho Chehab  *
6*9a0bf528SMauro Carvalho Chehab  *    Based on code from Jack Kelliher (kelliher@xmission.com)
7*9a0bf528SMauro Carvalho Chehab  *                           Copyright (C) 2002 & pcHDTV, inc.
8*9a0bf528SMauro Carvalho Chehab  *
9*9a0bf528SMauro Carvalho Chehab  *    This program is free software; you can redistribute it and/or modify
10*9a0bf528SMauro Carvalho Chehab  *    it under the terms of the GNU General Public License as published by
11*9a0bf528SMauro Carvalho Chehab  *    the Free Software Foundation; either version 2 of the License, or
12*9a0bf528SMauro Carvalho Chehab  *    (at your option) any later version.
13*9a0bf528SMauro Carvalho Chehab  *
14*9a0bf528SMauro Carvalho Chehab  *    This program is distributed in the hope that it will be useful,
15*9a0bf528SMauro Carvalho Chehab  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
16*9a0bf528SMauro Carvalho Chehab  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17*9a0bf528SMauro Carvalho Chehab  *    GNU General Public License for more details.
18*9a0bf528SMauro Carvalho Chehab  *
19*9a0bf528SMauro Carvalho Chehab  *    You should have received a copy of the GNU General Public License
20*9a0bf528SMauro Carvalho Chehab  *    along with this program; if not, write to the Free Software
21*9a0bf528SMauro Carvalho Chehab  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*9a0bf528SMauro Carvalho Chehab  *
23*9a0bf528SMauro Carvalho Chehab */
24*9a0bf528SMauro Carvalho Chehab 
25*9a0bf528SMauro Carvalho Chehab /*
26*9a0bf528SMauro Carvalho Chehab  * This driver needs external firmware. Please use the command
27*9a0bf528SMauro Carvalho Chehab  * "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
28*9a0bf528SMauro Carvalho Chehab  * download/extract it, and then copy it to /usr/lib/hotplug/firmware
29*9a0bf528SMauro Carvalho Chehab  * or /lib/firmware (depending on configuration of firmware hotplug).
30*9a0bf528SMauro Carvalho Chehab  */
31*9a0bf528SMauro Carvalho Chehab #define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw"
32*9a0bf528SMauro Carvalho Chehab 
33*9a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
34*9a0bf528SMauro Carvalho Chehab #include <linux/module.h>
35*9a0bf528SMauro Carvalho Chehab #include <linux/device.h>
36*9a0bf528SMauro Carvalho Chehab #include <linux/firmware.h>
37*9a0bf528SMauro Carvalho Chehab #include <linux/string.h>
38*9a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
39*9a0bf528SMauro Carvalho Chehab #include <asm/byteorder.h>
40*9a0bf528SMauro Carvalho Chehab 
41*9a0bf528SMauro Carvalho Chehab #include "dvb_math.h"
42*9a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h"
43*9a0bf528SMauro Carvalho Chehab #include "or51211.h"
44*9a0bf528SMauro Carvalho Chehab 
45*9a0bf528SMauro Carvalho Chehab static int debug;
46*9a0bf528SMauro Carvalho Chehab #define dprintk(args...) \
47*9a0bf528SMauro Carvalho Chehab 	do { \
48*9a0bf528SMauro Carvalho Chehab 		if (debug) printk(KERN_DEBUG "or51211: " args); \
49*9a0bf528SMauro Carvalho Chehab 	} while (0)
50*9a0bf528SMauro Carvalho Chehab 
51*9a0bf528SMauro Carvalho Chehab static u8 run_buf[] = {0x7f,0x01};
52*9a0bf528SMauro Carvalho Chehab static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC
53*9a0bf528SMauro Carvalho Chehab 
54*9a0bf528SMauro Carvalho Chehab struct or51211_state {
55*9a0bf528SMauro Carvalho Chehab 
56*9a0bf528SMauro Carvalho Chehab 	struct i2c_adapter* i2c;
57*9a0bf528SMauro Carvalho Chehab 
58*9a0bf528SMauro Carvalho Chehab 	/* Configuration settings */
59*9a0bf528SMauro Carvalho Chehab 	const struct or51211_config* config;
60*9a0bf528SMauro Carvalho Chehab 
61*9a0bf528SMauro Carvalho Chehab 	struct dvb_frontend frontend;
62*9a0bf528SMauro Carvalho Chehab 	struct bt878* bt;
63*9a0bf528SMauro Carvalho Chehab 
64*9a0bf528SMauro Carvalho Chehab 	/* Demodulator private data */
65*9a0bf528SMauro Carvalho Chehab 	u8 initialized:1;
66*9a0bf528SMauro Carvalho Chehab 	u32 snr; /* Result of last SNR claculation */
67*9a0bf528SMauro Carvalho Chehab 
68*9a0bf528SMauro Carvalho Chehab 	/* Tuner private data */
69*9a0bf528SMauro Carvalho Chehab 	u32 current_frequency;
70*9a0bf528SMauro Carvalho Chehab };
71*9a0bf528SMauro Carvalho Chehab 
72*9a0bf528SMauro Carvalho Chehab static int i2c_writebytes (struct or51211_state* state, u8 reg, const u8 *buf,
73*9a0bf528SMauro Carvalho Chehab 			   int len)
74*9a0bf528SMauro Carvalho Chehab {
75*9a0bf528SMauro Carvalho Chehab 	int err;
76*9a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg;
77*9a0bf528SMauro Carvalho Chehab 	msg.addr	= reg;
78*9a0bf528SMauro Carvalho Chehab 	msg.flags	= 0;
79*9a0bf528SMauro Carvalho Chehab 	msg.len		= len;
80*9a0bf528SMauro Carvalho Chehab 	msg.buf		= (u8 *)buf;
81*9a0bf528SMauro Carvalho Chehab 
82*9a0bf528SMauro Carvalho Chehab 	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
83*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "or51211: i2c_writebytes error "
84*9a0bf528SMauro Carvalho Chehab 		       "(addr %02x, err == %i)\n", reg, err);
85*9a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO;
86*9a0bf528SMauro Carvalho Chehab 	}
87*9a0bf528SMauro Carvalho Chehab 
88*9a0bf528SMauro Carvalho Chehab 	return 0;
89*9a0bf528SMauro Carvalho Chehab }
90*9a0bf528SMauro Carvalho Chehab 
91*9a0bf528SMauro Carvalho Chehab static int i2c_readbytes(struct or51211_state *state, u8 reg, u8 *buf, int len)
92*9a0bf528SMauro Carvalho Chehab {
93*9a0bf528SMauro Carvalho Chehab 	int err;
94*9a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg;
95*9a0bf528SMauro Carvalho Chehab 	msg.addr	= reg;
96*9a0bf528SMauro Carvalho Chehab 	msg.flags	= I2C_M_RD;
97*9a0bf528SMauro Carvalho Chehab 	msg.len		= len;
98*9a0bf528SMauro Carvalho Chehab 	msg.buf		= buf;
99*9a0bf528SMauro Carvalho Chehab 
100*9a0bf528SMauro Carvalho Chehab 	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
101*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "or51211: i2c_readbytes error "
102*9a0bf528SMauro Carvalho Chehab 		       "(addr %02x, err == %i)\n", reg, err);
103*9a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO;
104*9a0bf528SMauro Carvalho Chehab 	}
105*9a0bf528SMauro Carvalho Chehab 
106*9a0bf528SMauro Carvalho Chehab 	return 0;
107*9a0bf528SMauro Carvalho Chehab }
108*9a0bf528SMauro Carvalho Chehab 
109*9a0bf528SMauro Carvalho Chehab static int or51211_load_firmware (struct dvb_frontend* fe,
110*9a0bf528SMauro Carvalho Chehab 				  const struct firmware *fw)
111*9a0bf528SMauro Carvalho Chehab {
112*9a0bf528SMauro Carvalho Chehab 	struct or51211_state* state = fe->demodulator_priv;
113*9a0bf528SMauro Carvalho Chehab 	u8 tudata[585];
114*9a0bf528SMauro Carvalho Chehab 	int i;
115*9a0bf528SMauro Carvalho Chehab 
116*9a0bf528SMauro Carvalho Chehab 	dprintk("Firmware is %zd bytes\n",fw->size);
117*9a0bf528SMauro Carvalho Chehab 
118*9a0bf528SMauro Carvalho Chehab 	/* Get eprom data */
119*9a0bf528SMauro Carvalho Chehab 	tudata[0] = 17;
120*9a0bf528SMauro Carvalho Chehab 	if (i2c_writebytes(state,0x50,tudata,1)) {
121*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "or51211:load_firmware error eprom addr\n");
122*9a0bf528SMauro Carvalho Chehab 		return -1;
123*9a0bf528SMauro Carvalho Chehab 	}
124*9a0bf528SMauro Carvalho Chehab 	if (i2c_readbytes(state,0x50,&tudata[145],192)) {
125*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "or51211: load_firmware error eprom\n");
126*9a0bf528SMauro Carvalho Chehab 		return -1;
127*9a0bf528SMauro Carvalho Chehab 	}
128*9a0bf528SMauro Carvalho Chehab 
129*9a0bf528SMauro Carvalho Chehab 	/* Create firmware buffer */
130*9a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 145; i++)
131*9a0bf528SMauro Carvalho Chehab 		tudata[i] = fw->data[i];
132*9a0bf528SMauro Carvalho Chehab 
133*9a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 248; i++)
134*9a0bf528SMauro Carvalho Chehab 		tudata[i+337] = fw->data[145+i];
135*9a0bf528SMauro Carvalho Chehab 
136*9a0bf528SMauro Carvalho Chehab 	state->config->reset(fe);
137*9a0bf528SMauro Carvalho Chehab 
138*9a0bf528SMauro Carvalho Chehab 	if (i2c_writebytes(state,state->config->demod_address,tudata,585)) {
139*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "or51211: load_firmware error 1\n");
140*9a0bf528SMauro Carvalho Chehab 		return -1;
141*9a0bf528SMauro Carvalho Chehab 	}
142*9a0bf528SMauro Carvalho Chehab 	msleep(1);
143*9a0bf528SMauro Carvalho Chehab 
144*9a0bf528SMauro Carvalho Chehab 	if (i2c_writebytes(state,state->config->demod_address,
145*9a0bf528SMauro Carvalho Chehab 			   &fw->data[393],8125)) {
146*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "or51211: load_firmware error 2\n");
147*9a0bf528SMauro Carvalho Chehab 		return -1;
148*9a0bf528SMauro Carvalho Chehab 	}
149*9a0bf528SMauro Carvalho Chehab 	msleep(1);
150*9a0bf528SMauro Carvalho Chehab 
151*9a0bf528SMauro Carvalho Chehab 	if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
152*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "or51211: load_firmware error 3\n");
153*9a0bf528SMauro Carvalho Chehab 		return -1;
154*9a0bf528SMauro Carvalho Chehab 	}
155*9a0bf528SMauro Carvalho Chehab 
156*9a0bf528SMauro Carvalho Chehab 	/* Wait at least 5 msec */
157*9a0bf528SMauro Carvalho Chehab 	msleep(10);
158*9a0bf528SMauro Carvalho Chehab 	if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
159*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "or51211: load_firmware error 4\n");
160*9a0bf528SMauro Carvalho Chehab 		return -1;
161*9a0bf528SMauro Carvalho Chehab 	}
162*9a0bf528SMauro Carvalho Chehab 	msleep(10);
163*9a0bf528SMauro Carvalho Chehab 
164*9a0bf528SMauro Carvalho Chehab 	printk("or51211: Done.\n");
165*9a0bf528SMauro Carvalho Chehab 	return 0;
166*9a0bf528SMauro Carvalho Chehab };
167*9a0bf528SMauro Carvalho Chehab 
168*9a0bf528SMauro Carvalho Chehab static int or51211_setmode(struct dvb_frontend* fe, int mode)
169*9a0bf528SMauro Carvalho Chehab {
170*9a0bf528SMauro Carvalho Chehab 	struct or51211_state* state = fe->demodulator_priv;
171*9a0bf528SMauro Carvalho Chehab 	u8 rec_buf[14];
172*9a0bf528SMauro Carvalho Chehab 
173*9a0bf528SMauro Carvalho Chehab 	state->config->setmode(fe, mode);
174*9a0bf528SMauro Carvalho Chehab 
175*9a0bf528SMauro Carvalho Chehab 	if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
176*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "or51211: setmode error 1\n");
177*9a0bf528SMauro Carvalho Chehab 		return -1;
178*9a0bf528SMauro Carvalho Chehab 	}
179*9a0bf528SMauro Carvalho Chehab 
180*9a0bf528SMauro Carvalho Chehab 	/* Wait at least 5 msec */
181*9a0bf528SMauro Carvalho Chehab 	msleep(10);
182*9a0bf528SMauro Carvalho Chehab 	if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
183*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "or51211: setmode error 2\n");
184*9a0bf528SMauro Carvalho Chehab 		return -1;
185*9a0bf528SMauro Carvalho Chehab 	}
186*9a0bf528SMauro Carvalho Chehab 
187*9a0bf528SMauro Carvalho Chehab 	msleep(10);
188*9a0bf528SMauro Carvalho Chehab 
189*9a0bf528SMauro Carvalho Chehab 	/* Set operation mode in Receiver 1 register;
190*9a0bf528SMauro Carvalho Chehab 	 * type 1:
191*9a0bf528SMauro Carvalho Chehab 	 * data 0x50h  Automatic sets receiver channel conditions
192*9a0bf528SMauro Carvalho Chehab 	 *             Automatic NTSC rejection filter
193*9a0bf528SMauro Carvalho Chehab 	 *             Enable  MPEG serial data output
194*9a0bf528SMauro Carvalho Chehab 	 *             MPEG2tr
195*9a0bf528SMauro Carvalho Chehab 	 *             High tuner phase noise
196*9a0bf528SMauro Carvalho Chehab 	 *             normal +/-150kHz Carrier acquisition range
197*9a0bf528SMauro Carvalho Chehab 	 */
198*9a0bf528SMauro Carvalho Chehab 	if (i2c_writebytes(state,state->config->demod_address,cmd_buf,3)) {
199*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "or51211: setmode error 3\n");
200*9a0bf528SMauro Carvalho Chehab 		return -1;
201*9a0bf528SMauro Carvalho Chehab 	}
202*9a0bf528SMauro Carvalho Chehab 
203*9a0bf528SMauro Carvalho Chehab 	rec_buf[0] = 0x04;
204*9a0bf528SMauro Carvalho Chehab 	rec_buf[1] = 0x00;
205*9a0bf528SMauro Carvalho Chehab 	rec_buf[2] = 0x03;
206*9a0bf528SMauro Carvalho Chehab 	rec_buf[3] = 0x00;
207*9a0bf528SMauro Carvalho Chehab 	msleep(20);
208*9a0bf528SMauro Carvalho Chehab 	if (i2c_writebytes(state,state->config->demod_address,rec_buf,3)) {
209*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "or51211: setmode error 5\n");
210*9a0bf528SMauro Carvalho Chehab 	}
211*9a0bf528SMauro Carvalho Chehab 	msleep(3);
212*9a0bf528SMauro Carvalho Chehab 	if (i2c_readbytes(state,state->config->demod_address,&rec_buf[10],2)) {
213*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "or51211: setmode error 6");
214*9a0bf528SMauro Carvalho Chehab 		return -1;
215*9a0bf528SMauro Carvalho Chehab 	}
216*9a0bf528SMauro Carvalho Chehab 	dprintk("setmode rec status %02x %02x\n",rec_buf[10],rec_buf[11]);
217*9a0bf528SMauro Carvalho Chehab 
218*9a0bf528SMauro Carvalho Chehab 	return 0;
219*9a0bf528SMauro Carvalho Chehab }
220*9a0bf528SMauro Carvalho Chehab 
221*9a0bf528SMauro Carvalho Chehab static int or51211_set_parameters(struct dvb_frontend *fe)
222*9a0bf528SMauro Carvalho Chehab {
223*9a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
224*9a0bf528SMauro Carvalho Chehab 	struct or51211_state* state = fe->demodulator_priv;
225*9a0bf528SMauro Carvalho Chehab 
226*9a0bf528SMauro Carvalho Chehab 	/* Change only if we are actually changing the channel */
227*9a0bf528SMauro Carvalho Chehab 	if (state->current_frequency != p->frequency) {
228*9a0bf528SMauro Carvalho Chehab 		if (fe->ops.tuner_ops.set_params) {
229*9a0bf528SMauro Carvalho Chehab 			fe->ops.tuner_ops.set_params(fe);
230*9a0bf528SMauro Carvalho Chehab 			if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
231*9a0bf528SMauro Carvalho Chehab 		}
232*9a0bf528SMauro Carvalho Chehab 
233*9a0bf528SMauro Carvalho Chehab 		/* Set to ATSC mode */
234*9a0bf528SMauro Carvalho Chehab 		or51211_setmode(fe,0);
235*9a0bf528SMauro Carvalho Chehab 
236*9a0bf528SMauro Carvalho Chehab 		/* Update current frequency */
237*9a0bf528SMauro Carvalho Chehab 		state->current_frequency = p->frequency;
238*9a0bf528SMauro Carvalho Chehab 	}
239*9a0bf528SMauro Carvalho Chehab 	return 0;
240*9a0bf528SMauro Carvalho Chehab }
241*9a0bf528SMauro Carvalho Chehab 
242*9a0bf528SMauro Carvalho Chehab static int or51211_read_status(struct dvb_frontend* fe, fe_status_t* status)
243*9a0bf528SMauro Carvalho Chehab {
244*9a0bf528SMauro Carvalho Chehab 	struct or51211_state* state = fe->demodulator_priv;
245*9a0bf528SMauro Carvalho Chehab 	unsigned char rec_buf[2];
246*9a0bf528SMauro Carvalho Chehab 	unsigned char snd_buf[] = {0x04,0x00,0x03,0x00};
247*9a0bf528SMauro Carvalho Chehab 	*status = 0;
248*9a0bf528SMauro Carvalho Chehab 
249*9a0bf528SMauro Carvalho Chehab 	/* Receiver Status */
250*9a0bf528SMauro Carvalho Chehab 	if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
251*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "or51132: read_status write error\n");
252*9a0bf528SMauro Carvalho Chehab 		return -1;
253*9a0bf528SMauro Carvalho Chehab 	}
254*9a0bf528SMauro Carvalho Chehab 	msleep(3);
255*9a0bf528SMauro Carvalho Chehab 	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
256*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "or51132: read_status read error\n");
257*9a0bf528SMauro Carvalho Chehab 		return -1;
258*9a0bf528SMauro Carvalho Chehab 	}
259*9a0bf528SMauro Carvalho Chehab 	dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]);
260*9a0bf528SMauro Carvalho Chehab 
261*9a0bf528SMauro Carvalho Chehab 	if (rec_buf[0] &  0x01) { /* Receiver Lock */
262*9a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SIGNAL;
263*9a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_CARRIER;
264*9a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_VITERBI;
265*9a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_SYNC;
266*9a0bf528SMauro Carvalho Chehab 		*status |= FE_HAS_LOCK;
267*9a0bf528SMauro Carvalho Chehab 	}
268*9a0bf528SMauro Carvalho Chehab 	return 0;
269*9a0bf528SMauro Carvalho Chehab }
270*9a0bf528SMauro Carvalho Chehab 
271*9a0bf528SMauro Carvalho Chehab /* Calculate SNR estimation (scaled by 2^24)
272*9a0bf528SMauro Carvalho Chehab 
273*9a0bf528SMauro Carvalho Chehab    8-VSB SNR equation from Oren datasheets
274*9a0bf528SMauro Carvalho Chehab 
275*9a0bf528SMauro Carvalho Chehab    For 8-VSB:
276*9a0bf528SMauro Carvalho Chehab      SNR[dB] = 10 * log10(219037.9454 / MSE^2 )
277*9a0bf528SMauro Carvalho Chehab 
278*9a0bf528SMauro Carvalho Chehab    We re-write the snr equation as:
279*9a0bf528SMauro Carvalho Chehab      SNR * 2^24 = 10*(c - 2*intlog10(MSE))
280*9a0bf528SMauro Carvalho Chehab    Where for 8-VSB, c = log10(219037.9454) * 2^24 */
281*9a0bf528SMauro Carvalho Chehab 
282*9a0bf528SMauro Carvalho Chehab static u32 calculate_snr(u32 mse, u32 c)
283*9a0bf528SMauro Carvalho Chehab {
284*9a0bf528SMauro Carvalho Chehab 	if (mse == 0) /* No signal */
285*9a0bf528SMauro Carvalho Chehab 		return 0;
286*9a0bf528SMauro Carvalho Chehab 
287*9a0bf528SMauro Carvalho Chehab 	mse = 2*intlog10(mse);
288*9a0bf528SMauro Carvalho Chehab 	if (mse > c) {
289*9a0bf528SMauro Carvalho Chehab 		/* Negative SNR, which is possible, but realisticly the
290*9a0bf528SMauro Carvalho Chehab 		demod will lose lock before the signal gets this bad.  The
291*9a0bf528SMauro Carvalho Chehab 		API only allows for unsigned values, so just return 0 */
292*9a0bf528SMauro Carvalho Chehab 		return 0;
293*9a0bf528SMauro Carvalho Chehab 	}
294*9a0bf528SMauro Carvalho Chehab 	return 10*(c - mse);
295*9a0bf528SMauro Carvalho Chehab }
296*9a0bf528SMauro Carvalho Chehab 
297*9a0bf528SMauro Carvalho Chehab static int or51211_read_snr(struct dvb_frontend* fe, u16* snr)
298*9a0bf528SMauro Carvalho Chehab {
299*9a0bf528SMauro Carvalho Chehab 	struct or51211_state* state = fe->demodulator_priv;
300*9a0bf528SMauro Carvalho Chehab 	u8 rec_buf[2];
301*9a0bf528SMauro Carvalho Chehab 	u8 snd_buf[3];
302*9a0bf528SMauro Carvalho Chehab 
303*9a0bf528SMauro Carvalho Chehab 	/* SNR after Equalizer */
304*9a0bf528SMauro Carvalho Chehab 	snd_buf[0] = 0x04;
305*9a0bf528SMauro Carvalho Chehab 	snd_buf[1] = 0x00;
306*9a0bf528SMauro Carvalho Chehab 	snd_buf[2] = 0x04;
307*9a0bf528SMauro Carvalho Chehab 
308*9a0bf528SMauro Carvalho Chehab 	if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
309*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "%s: error writing snr reg\n",
310*9a0bf528SMauro Carvalho Chehab 		       __func__);
311*9a0bf528SMauro Carvalho Chehab 		return -1;
312*9a0bf528SMauro Carvalho Chehab 	}
313*9a0bf528SMauro Carvalho Chehab 	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
314*9a0bf528SMauro Carvalho Chehab 		printk(KERN_WARNING "%s: read_status read error\n",
315*9a0bf528SMauro Carvalho Chehab 		       __func__);
316*9a0bf528SMauro Carvalho Chehab 		return -1;
317*9a0bf528SMauro Carvalho Chehab 	}
318*9a0bf528SMauro Carvalho Chehab 
319*9a0bf528SMauro Carvalho Chehab 	state->snr = calculate_snr(rec_buf[0], 89599047);
320*9a0bf528SMauro Carvalho Chehab 	*snr = (state->snr) >> 16;
321*9a0bf528SMauro Carvalho Chehab 
322*9a0bf528SMauro Carvalho Chehab 	dprintk("%s: noise = 0x%02x, snr = %d.%02d dB\n", __func__, rec_buf[0],
323*9a0bf528SMauro Carvalho Chehab 		state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
324*9a0bf528SMauro Carvalho Chehab 
325*9a0bf528SMauro Carvalho Chehab 	return 0;
326*9a0bf528SMauro Carvalho Chehab }
327*9a0bf528SMauro Carvalho Chehab 
328*9a0bf528SMauro Carvalho Chehab static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength)
329*9a0bf528SMauro Carvalho Chehab {
330*9a0bf528SMauro Carvalho Chehab 	/* Calculate Strength from SNR up to 35dB */
331*9a0bf528SMauro Carvalho Chehab 	/* Even though the SNR can go higher than 35dB, there is some comfort */
332*9a0bf528SMauro Carvalho Chehab 	/* factor in having a range of strong signals that can show at 100%   */
333*9a0bf528SMauro Carvalho Chehab 	struct or51211_state* state = (struct or51211_state*)fe->demodulator_priv;
334*9a0bf528SMauro Carvalho Chehab 	u16 snr;
335*9a0bf528SMauro Carvalho Chehab 	int ret;
336*9a0bf528SMauro Carvalho Chehab 
337*9a0bf528SMauro Carvalho Chehab 	ret = fe->ops.read_snr(fe, &snr);
338*9a0bf528SMauro Carvalho Chehab 	if (ret != 0)
339*9a0bf528SMauro Carvalho Chehab 		return ret;
340*9a0bf528SMauro Carvalho Chehab 	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
341*9a0bf528SMauro Carvalho Chehab 	/* scale the range 0 - 35*2^24 into 0 - 65535 */
342*9a0bf528SMauro Carvalho Chehab 	if (state->snr >= 8960 * 0x10000)
343*9a0bf528SMauro Carvalho Chehab 		*strength = 0xffff;
344*9a0bf528SMauro Carvalho Chehab 	else
345*9a0bf528SMauro Carvalho Chehab 		*strength = state->snr / 8960;
346*9a0bf528SMauro Carvalho Chehab 
347*9a0bf528SMauro Carvalho Chehab 	return 0;
348*9a0bf528SMauro Carvalho Chehab }
349*9a0bf528SMauro Carvalho Chehab 
350*9a0bf528SMauro Carvalho Chehab static int or51211_read_ber(struct dvb_frontend* fe, u32* ber)
351*9a0bf528SMauro Carvalho Chehab {
352*9a0bf528SMauro Carvalho Chehab 	*ber = -ENOSYS;
353*9a0bf528SMauro Carvalho Chehab 	return 0;
354*9a0bf528SMauro Carvalho Chehab }
355*9a0bf528SMauro Carvalho Chehab 
356*9a0bf528SMauro Carvalho Chehab static int or51211_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
357*9a0bf528SMauro Carvalho Chehab {
358*9a0bf528SMauro Carvalho Chehab 	*ucblocks = -ENOSYS;
359*9a0bf528SMauro Carvalho Chehab 	return 0;
360*9a0bf528SMauro Carvalho Chehab }
361*9a0bf528SMauro Carvalho Chehab 
362*9a0bf528SMauro Carvalho Chehab static int or51211_sleep(struct dvb_frontend* fe)
363*9a0bf528SMauro Carvalho Chehab {
364*9a0bf528SMauro Carvalho Chehab 	return 0;
365*9a0bf528SMauro Carvalho Chehab }
366*9a0bf528SMauro Carvalho Chehab 
367*9a0bf528SMauro Carvalho Chehab static int or51211_init(struct dvb_frontend* fe)
368*9a0bf528SMauro Carvalho Chehab {
369*9a0bf528SMauro Carvalho Chehab 	struct or51211_state* state = fe->demodulator_priv;
370*9a0bf528SMauro Carvalho Chehab 	const struct or51211_config* config = state->config;
371*9a0bf528SMauro Carvalho Chehab 	const struct firmware* fw;
372*9a0bf528SMauro Carvalho Chehab 	unsigned char get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00};
373*9a0bf528SMauro Carvalho Chehab 	unsigned char rec_buf[14];
374*9a0bf528SMauro Carvalho Chehab 	int ret,i;
375*9a0bf528SMauro Carvalho Chehab 
376*9a0bf528SMauro Carvalho Chehab 	if (!state->initialized) {
377*9a0bf528SMauro Carvalho Chehab 		/* Request the firmware, this will block until it uploads */
378*9a0bf528SMauro Carvalho Chehab 		printk(KERN_INFO "or51211: Waiting for firmware upload "
379*9a0bf528SMauro Carvalho Chehab 		       "(%s)...\n", OR51211_DEFAULT_FIRMWARE);
380*9a0bf528SMauro Carvalho Chehab 		ret = config->request_firmware(fe, &fw,
381*9a0bf528SMauro Carvalho Chehab 					       OR51211_DEFAULT_FIRMWARE);
382*9a0bf528SMauro Carvalho Chehab 		printk(KERN_INFO "or51211:Got Hotplug firmware\n");
383*9a0bf528SMauro Carvalho Chehab 		if (ret) {
384*9a0bf528SMauro Carvalho Chehab 			printk(KERN_WARNING "or51211: No firmware uploaded "
385*9a0bf528SMauro Carvalho Chehab 			       "(timeout or file not found?)\n");
386*9a0bf528SMauro Carvalho Chehab 			return ret;
387*9a0bf528SMauro Carvalho Chehab 		}
388*9a0bf528SMauro Carvalho Chehab 
389*9a0bf528SMauro Carvalho Chehab 		ret = or51211_load_firmware(fe, fw);
390*9a0bf528SMauro Carvalho Chehab 		release_firmware(fw);
391*9a0bf528SMauro Carvalho Chehab 		if (ret) {
392*9a0bf528SMauro Carvalho Chehab 			printk(KERN_WARNING "or51211: Writing firmware to "
393*9a0bf528SMauro Carvalho Chehab 			       "device failed!\n");
394*9a0bf528SMauro Carvalho Chehab 			return ret;
395*9a0bf528SMauro Carvalho Chehab 		}
396*9a0bf528SMauro Carvalho Chehab 		printk(KERN_INFO "or51211: Firmware upload complete.\n");
397*9a0bf528SMauro Carvalho Chehab 
398*9a0bf528SMauro Carvalho Chehab 		/* Set operation mode in Receiver 1 register;
399*9a0bf528SMauro Carvalho Chehab 		 * type 1:
400*9a0bf528SMauro Carvalho Chehab 		 * data 0x50h  Automatic sets receiver channel conditions
401*9a0bf528SMauro Carvalho Chehab 		 *             Automatic NTSC rejection filter
402*9a0bf528SMauro Carvalho Chehab 		 *             Enable  MPEG serial data output
403*9a0bf528SMauro Carvalho Chehab 		 *             MPEG2tr
404*9a0bf528SMauro Carvalho Chehab 		 *             High tuner phase noise
405*9a0bf528SMauro Carvalho Chehab 		 *             normal +/-150kHz Carrier acquisition range
406*9a0bf528SMauro Carvalho Chehab 		 */
407*9a0bf528SMauro Carvalho Chehab 		if (i2c_writebytes(state,state->config->demod_address,
408*9a0bf528SMauro Carvalho Chehab 				   cmd_buf,3)) {
409*9a0bf528SMauro Carvalho Chehab 			printk(KERN_WARNING "or51211: Load DVR Error 5\n");
410*9a0bf528SMauro Carvalho Chehab 			return -1;
411*9a0bf528SMauro Carvalho Chehab 		}
412*9a0bf528SMauro Carvalho Chehab 
413*9a0bf528SMauro Carvalho Chehab 		/* Read back ucode version to besure we loaded correctly */
414*9a0bf528SMauro Carvalho Chehab 		/* and are really up and running */
415*9a0bf528SMauro Carvalho Chehab 		rec_buf[0] = 0x04;
416*9a0bf528SMauro Carvalho Chehab 		rec_buf[1] = 0x00;
417*9a0bf528SMauro Carvalho Chehab 		rec_buf[2] = 0x03;
418*9a0bf528SMauro Carvalho Chehab 		rec_buf[3] = 0x00;
419*9a0bf528SMauro Carvalho Chehab 		msleep(30);
420*9a0bf528SMauro Carvalho Chehab 		if (i2c_writebytes(state,state->config->demod_address,
421*9a0bf528SMauro Carvalho Chehab 				   rec_buf,3)) {
422*9a0bf528SMauro Carvalho Chehab 			printk(KERN_WARNING "or51211: Load DVR Error A\n");
423*9a0bf528SMauro Carvalho Chehab 			return -1;
424*9a0bf528SMauro Carvalho Chehab 		}
425*9a0bf528SMauro Carvalho Chehab 		msleep(3);
426*9a0bf528SMauro Carvalho Chehab 		if (i2c_readbytes(state,state->config->demod_address,
427*9a0bf528SMauro Carvalho Chehab 				  &rec_buf[10],2)) {
428*9a0bf528SMauro Carvalho Chehab 			printk(KERN_WARNING "or51211: Load DVR Error B\n");
429*9a0bf528SMauro Carvalho Chehab 			return -1;
430*9a0bf528SMauro Carvalho Chehab 		}
431*9a0bf528SMauro Carvalho Chehab 
432*9a0bf528SMauro Carvalho Chehab 		rec_buf[0] = 0x04;
433*9a0bf528SMauro Carvalho Chehab 		rec_buf[1] = 0x00;
434*9a0bf528SMauro Carvalho Chehab 		rec_buf[2] = 0x01;
435*9a0bf528SMauro Carvalho Chehab 		rec_buf[3] = 0x00;
436*9a0bf528SMauro Carvalho Chehab 		msleep(20);
437*9a0bf528SMauro Carvalho Chehab 		if (i2c_writebytes(state,state->config->demod_address,
438*9a0bf528SMauro Carvalho Chehab 				   rec_buf,3)) {
439*9a0bf528SMauro Carvalho Chehab 			printk(KERN_WARNING "or51211: Load DVR Error C\n");
440*9a0bf528SMauro Carvalho Chehab 			return -1;
441*9a0bf528SMauro Carvalho Chehab 		}
442*9a0bf528SMauro Carvalho Chehab 		msleep(3);
443*9a0bf528SMauro Carvalho Chehab 		if (i2c_readbytes(state,state->config->demod_address,
444*9a0bf528SMauro Carvalho Chehab 				  &rec_buf[12],2)) {
445*9a0bf528SMauro Carvalho Chehab 			printk(KERN_WARNING "or51211: Load DVR Error D\n");
446*9a0bf528SMauro Carvalho Chehab 			return -1;
447*9a0bf528SMauro Carvalho Chehab 		}
448*9a0bf528SMauro Carvalho Chehab 
449*9a0bf528SMauro Carvalho Chehab 		for (i = 0; i < 8; i++)
450*9a0bf528SMauro Carvalho Chehab 			rec_buf[i]=0xed;
451*9a0bf528SMauro Carvalho Chehab 
452*9a0bf528SMauro Carvalho Chehab 		for (i = 0; i < 5; i++) {
453*9a0bf528SMauro Carvalho Chehab 			msleep(30);
454*9a0bf528SMauro Carvalho Chehab 			get_ver_buf[4] = i+1;
455*9a0bf528SMauro Carvalho Chehab 			if (i2c_writebytes(state,state->config->demod_address,
456*9a0bf528SMauro Carvalho Chehab 					   get_ver_buf,5)) {
457*9a0bf528SMauro Carvalho Chehab 				printk(KERN_WARNING "or51211:Load DVR Error 6"
458*9a0bf528SMauro Carvalho Chehab 				       " - %d\n",i);
459*9a0bf528SMauro Carvalho Chehab 				return -1;
460*9a0bf528SMauro Carvalho Chehab 			}
461*9a0bf528SMauro Carvalho Chehab 			msleep(3);
462*9a0bf528SMauro Carvalho Chehab 
463*9a0bf528SMauro Carvalho Chehab 			if (i2c_readbytes(state,state->config->demod_address,
464*9a0bf528SMauro Carvalho Chehab 					  &rec_buf[i*2],2)) {
465*9a0bf528SMauro Carvalho Chehab 				printk(KERN_WARNING "or51211:Load DVR Error 7"
466*9a0bf528SMauro Carvalho Chehab 				       " - %d\n",i);
467*9a0bf528SMauro Carvalho Chehab 				return -1;
468*9a0bf528SMauro Carvalho Chehab 			}
469*9a0bf528SMauro Carvalho Chehab 			/* If we didn't receive the right index, try again */
470*9a0bf528SMauro Carvalho Chehab 			if ((int)rec_buf[i*2+1]!=i+1){
471*9a0bf528SMauro Carvalho Chehab 			  i--;
472*9a0bf528SMauro Carvalho Chehab 			}
473*9a0bf528SMauro Carvalho Chehab 		}
474*9a0bf528SMauro Carvalho Chehab 		dprintk("read_fwbits %x %x %x %x %x %x %x %x %x %x\n",
475*9a0bf528SMauro Carvalho Chehab 			rec_buf[0], rec_buf[1], rec_buf[2], rec_buf[3],
476*9a0bf528SMauro Carvalho Chehab 			rec_buf[4], rec_buf[5], rec_buf[6], rec_buf[7],
477*9a0bf528SMauro Carvalho Chehab 			rec_buf[8], rec_buf[9]);
478*9a0bf528SMauro Carvalho Chehab 
479*9a0bf528SMauro Carvalho Chehab 		printk(KERN_INFO "or51211: ver TU%02x%02x%02x VSB mode %02x"
480*9a0bf528SMauro Carvalho Chehab 		       " Status %02x\n",
481*9a0bf528SMauro Carvalho Chehab 		       rec_buf[2], rec_buf[4],rec_buf[6],
482*9a0bf528SMauro Carvalho Chehab 		       rec_buf[12],rec_buf[10]);
483*9a0bf528SMauro Carvalho Chehab 
484*9a0bf528SMauro Carvalho Chehab 		rec_buf[0] = 0x04;
485*9a0bf528SMauro Carvalho Chehab 		rec_buf[1] = 0x00;
486*9a0bf528SMauro Carvalho Chehab 		rec_buf[2] = 0x03;
487*9a0bf528SMauro Carvalho Chehab 		rec_buf[3] = 0x00;
488*9a0bf528SMauro Carvalho Chehab 		msleep(20);
489*9a0bf528SMauro Carvalho Chehab 		if (i2c_writebytes(state,state->config->demod_address,
490*9a0bf528SMauro Carvalho Chehab 				   rec_buf,3)) {
491*9a0bf528SMauro Carvalho Chehab 			printk(KERN_WARNING "or51211: Load DVR Error 8\n");
492*9a0bf528SMauro Carvalho Chehab 			return -1;
493*9a0bf528SMauro Carvalho Chehab 		}
494*9a0bf528SMauro Carvalho Chehab 		msleep(20);
495*9a0bf528SMauro Carvalho Chehab 		if (i2c_readbytes(state,state->config->demod_address,
496*9a0bf528SMauro Carvalho Chehab 				  &rec_buf[8],2)) {
497*9a0bf528SMauro Carvalho Chehab 			printk(KERN_WARNING "or51211: Load DVR Error 9\n");
498*9a0bf528SMauro Carvalho Chehab 			return -1;
499*9a0bf528SMauro Carvalho Chehab 		}
500*9a0bf528SMauro Carvalho Chehab 		state->initialized = 1;
501*9a0bf528SMauro Carvalho Chehab 	}
502*9a0bf528SMauro Carvalho Chehab 
503*9a0bf528SMauro Carvalho Chehab 	return 0;
504*9a0bf528SMauro Carvalho Chehab }
505*9a0bf528SMauro Carvalho Chehab 
506*9a0bf528SMauro Carvalho Chehab static int or51211_get_tune_settings(struct dvb_frontend* fe,
507*9a0bf528SMauro Carvalho Chehab 				     struct dvb_frontend_tune_settings* fesettings)
508*9a0bf528SMauro Carvalho Chehab {
509*9a0bf528SMauro Carvalho Chehab 	fesettings->min_delay_ms = 500;
510*9a0bf528SMauro Carvalho Chehab 	fesettings->step_size = 0;
511*9a0bf528SMauro Carvalho Chehab 	fesettings->max_drift = 0;
512*9a0bf528SMauro Carvalho Chehab 	return 0;
513*9a0bf528SMauro Carvalho Chehab }
514*9a0bf528SMauro Carvalho Chehab 
515*9a0bf528SMauro Carvalho Chehab static void or51211_release(struct dvb_frontend* fe)
516*9a0bf528SMauro Carvalho Chehab {
517*9a0bf528SMauro Carvalho Chehab 	struct or51211_state* state = fe->demodulator_priv;
518*9a0bf528SMauro Carvalho Chehab 	state->config->sleep(fe);
519*9a0bf528SMauro Carvalho Chehab 	kfree(state);
520*9a0bf528SMauro Carvalho Chehab }
521*9a0bf528SMauro Carvalho Chehab 
522*9a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops or51211_ops;
523*9a0bf528SMauro Carvalho Chehab 
524*9a0bf528SMauro Carvalho Chehab struct dvb_frontend* or51211_attach(const struct or51211_config* config,
525*9a0bf528SMauro Carvalho Chehab 				    struct i2c_adapter* i2c)
526*9a0bf528SMauro Carvalho Chehab {
527*9a0bf528SMauro Carvalho Chehab 	struct or51211_state* state = NULL;
528*9a0bf528SMauro Carvalho Chehab 
529*9a0bf528SMauro Carvalho Chehab 	/* Allocate memory for the internal state */
530*9a0bf528SMauro Carvalho Chehab 	state = kzalloc(sizeof(struct or51211_state), GFP_KERNEL);
531*9a0bf528SMauro Carvalho Chehab 	if (state == NULL)
532*9a0bf528SMauro Carvalho Chehab 		return NULL;
533*9a0bf528SMauro Carvalho Chehab 
534*9a0bf528SMauro Carvalho Chehab 	/* Setup the state */
535*9a0bf528SMauro Carvalho Chehab 	state->config = config;
536*9a0bf528SMauro Carvalho Chehab 	state->i2c = i2c;
537*9a0bf528SMauro Carvalho Chehab 	state->initialized = 0;
538*9a0bf528SMauro Carvalho Chehab 	state->current_frequency = 0;
539*9a0bf528SMauro Carvalho Chehab 
540*9a0bf528SMauro Carvalho Chehab 	/* Create dvb_frontend */
541*9a0bf528SMauro Carvalho Chehab 	memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
542*9a0bf528SMauro Carvalho Chehab 	state->frontend.demodulator_priv = state;
543*9a0bf528SMauro Carvalho Chehab 	return &state->frontend;
544*9a0bf528SMauro Carvalho Chehab }
545*9a0bf528SMauro Carvalho Chehab 
546*9a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops or51211_ops = {
547*9a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
548*9a0bf528SMauro Carvalho Chehab 	.info = {
549*9a0bf528SMauro Carvalho Chehab 		.name               = "Oren OR51211 VSB Frontend",
550*9a0bf528SMauro Carvalho Chehab 		.frequency_min      = 44000000,
551*9a0bf528SMauro Carvalho Chehab 		.frequency_max      = 958000000,
552*9a0bf528SMauro Carvalho Chehab 		.frequency_stepsize = 166666,
553*9a0bf528SMauro Carvalho Chehab 		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
554*9a0bf528SMauro Carvalho Chehab 			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
555*9a0bf528SMauro Carvalho Chehab 			FE_CAN_8VSB
556*9a0bf528SMauro Carvalho Chehab 	},
557*9a0bf528SMauro Carvalho Chehab 
558*9a0bf528SMauro Carvalho Chehab 	.release = or51211_release,
559*9a0bf528SMauro Carvalho Chehab 
560*9a0bf528SMauro Carvalho Chehab 	.init = or51211_init,
561*9a0bf528SMauro Carvalho Chehab 	.sleep = or51211_sleep,
562*9a0bf528SMauro Carvalho Chehab 
563*9a0bf528SMauro Carvalho Chehab 	.set_frontend = or51211_set_parameters,
564*9a0bf528SMauro Carvalho Chehab 	.get_tune_settings = or51211_get_tune_settings,
565*9a0bf528SMauro Carvalho Chehab 
566*9a0bf528SMauro Carvalho Chehab 	.read_status = or51211_read_status,
567*9a0bf528SMauro Carvalho Chehab 	.read_ber = or51211_read_ber,
568*9a0bf528SMauro Carvalho Chehab 	.read_signal_strength = or51211_read_signal_strength,
569*9a0bf528SMauro Carvalho Chehab 	.read_snr = or51211_read_snr,
570*9a0bf528SMauro Carvalho Chehab 	.read_ucblocks = or51211_read_ucblocks,
571*9a0bf528SMauro Carvalho Chehab };
572*9a0bf528SMauro Carvalho Chehab 
573*9a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
574*9a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
575*9a0bf528SMauro Carvalho Chehab 
576*9a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Oren OR51211 VSB [pcHDTV HD-2000] Demodulator Driver");
577*9a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Kirk Lapray");
578*9a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
579*9a0bf528SMauro Carvalho Chehab 
580*9a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(or51211_attach);
581*9a0bf528SMauro Carvalho Chehab 
582