xref: /OK3568_Linux_fs/kernel/drivers/media/dvb-frontends/bcm3510.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC)
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  *  Copyright (C) 2001-5, B2C2 inc.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *  GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@posteo.de>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *  This driver is "hard-coded" to be used with the 1st generation of
9*4882a593Smuzhiyun  *  Technisat/B2C2's Air2PC ATSC PCI/USB cards/boxes. The pll-programming
10*4882a593Smuzhiyun  *  (Panasonic CT10S) is located here, which is actually wrong. Unless there is
11*4882a593Smuzhiyun  *  another device with a BCM3510, this is no problem.
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  *  The driver works also with QAM64 DVB-C, but had an unreasonable high
14*4882a593Smuzhiyun  *  UNC. (Tested with the Air2PC ATSC 1st generation)
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  *  You'll need a firmware for this driver in order to get it running. It is
17*4882a593Smuzhiyun  *  called "dvb-fe-bcm3510-01.fw".
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify it
20*4882a593Smuzhiyun  * under the terms of the GNU General Public License as published by the Free
21*4882a593Smuzhiyun  * Software Foundation; either version 2 of the License, or (at your option)
22*4882a593Smuzhiyun  * any later version.
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful, but WITHOUT
25*4882a593Smuzhiyun  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
26*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
27*4882a593Smuzhiyun  * more details.
28*4882a593Smuzhiyun  *
29*4882a593Smuzhiyun  * You should have received a copy of the GNU General Public License along with
30*4882a593Smuzhiyun  * this program; if not, write to the Free Software Foundation, Inc., 675 Mass
31*4882a593Smuzhiyun  * Ave, Cambridge, MA 02139, USA.
32*4882a593Smuzhiyun  */
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #include <linux/init.h>
35*4882a593Smuzhiyun #include <linux/module.h>
36*4882a593Smuzhiyun #include <linux/device.h>
37*4882a593Smuzhiyun #include <linux/firmware.h>
38*4882a593Smuzhiyun #include <linux/jiffies.h>
39*4882a593Smuzhiyun #include <linux/string.h>
40*4882a593Smuzhiyun #include <linux/slab.h>
41*4882a593Smuzhiyun #include <linux/mutex.h>
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #include <media/dvb_frontend.h>
44*4882a593Smuzhiyun #include "bcm3510.h"
45*4882a593Smuzhiyun #include "bcm3510_priv.h"
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun /* Max transfer size done by bcm3510_do_hab_cmd() function */
48*4882a593Smuzhiyun #define MAX_XFER_SIZE	128
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun struct bcm3510_state {
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	struct i2c_adapter* i2c;
53*4882a593Smuzhiyun 	const struct bcm3510_config* config;
54*4882a593Smuzhiyun 	struct dvb_frontend frontend;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	/* demodulator private data */
57*4882a593Smuzhiyun 	struct mutex hab_mutex;
58*4882a593Smuzhiyun 	u8 firmware_loaded:1;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	unsigned long next_status_check;
61*4882a593Smuzhiyun 	unsigned long status_check_interval;
62*4882a593Smuzhiyun 	struct bcm3510_hab_cmd_status1 status1;
63*4882a593Smuzhiyun 	struct bcm3510_hab_cmd_status2 status2;
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun static int debug;
67*4882a593Smuzhiyun module_param(debug, int, 0644);
68*4882a593Smuzhiyun MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c (|-able)).");
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun #define dprintk(level,x...) if (level & debug) printk(x)
71*4882a593Smuzhiyun #define dbufout(b,l,m) {\
72*4882a593Smuzhiyun 	    int i; \
73*4882a593Smuzhiyun 	    for (i = 0; i < l; i++) \
74*4882a593Smuzhiyun 		m("%02x ",b[i]); \
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun #define deb_info(args...) dprintk(0x01,args)
77*4882a593Smuzhiyun #define deb_i2c(args...)  dprintk(0x02,args)
78*4882a593Smuzhiyun #define deb_hab(args...)  dprintk(0x04,args)
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun /* transfer functions */
bcm3510_writebytes(struct bcm3510_state * state,u8 reg,u8 * buf,u8 len)81*4882a593Smuzhiyun static int bcm3510_writebytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	u8 b[256];
84*4882a593Smuzhiyun 	int err;
85*4882a593Smuzhiyun 	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = len + 1 };
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	b[0] = reg;
88*4882a593Smuzhiyun 	memcpy(&b[1],buf,len);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	deb_i2c("i2c wr %02x: ",reg);
91*4882a593Smuzhiyun 	dbufout(buf,len,deb_i2c);
92*4882a593Smuzhiyun 	deb_i2c("\n");
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 		deb_info("%s: i2c write error (addr %02x, reg %02x, err == %i)\n",
97*4882a593Smuzhiyun 			__func__, state->config->demod_address, reg,  err);
98*4882a593Smuzhiyun 		return -EREMOTEIO;
99*4882a593Smuzhiyun 	}
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	return 0;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun 
bcm3510_readbytes(struct bcm3510_state * state,u8 reg,u8 * buf,u8 len)104*4882a593Smuzhiyun static int bcm3510_readbytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun 	struct i2c_msg msg[] = {
107*4882a593Smuzhiyun 		{ .addr = state->config->demod_address, .flags = 0,        .buf = &reg, .len = 1 },
108*4882a593Smuzhiyun 		{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf,  .len = len }
109*4882a593Smuzhiyun 	};
110*4882a593Smuzhiyun 	int err;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	memset(buf,0,len);
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
115*4882a593Smuzhiyun 		deb_info("%s: i2c read error (addr %02x, reg %02x, err == %i)\n",
116*4882a593Smuzhiyun 			__func__, state->config->demod_address, reg,  err);
117*4882a593Smuzhiyun 		return -EREMOTEIO;
118*4882a593Smuzhiyun 	}
119*4882a593Smuzhiyun 	deb_i2c("i2c rd %02x: ",reg);
120*4882a593Smuzhiyun 	dbufout(buf,len,deb_i2c);
121*4882a593Smuzhiyun 	deb_i2c("\n");
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	return 0;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun 
bcm3510_writeB(struct bcm3510_state * state,u8 reg,bcm3510_register_value v)126*4882a593Smuzhiyun static int bcm3510_writeB(struct bcm3510_state *state, u8 reg, bcm3510_register_value v)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	return bcm3510_writebytes(state,reg,&v.raw,1);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun 
bcm3510_readB(struct bcm3510_state * state,u8 reg,bcm3510_register_value * v)131*4882a593Smuzhiyun static int bcm3510_readB(struct bcm3510_state *state, u8 reg, bcm3510_register_value *v)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	return bcm3510_readbytes(state,reg,&v->raw,1);
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun /* Host Access Buffer transfers */
bcm3510_hab_get_response(struct bcm3510_state * st,u8 * buf,int len)137*4882a593Smuzhiyun static int bcm3510_hab_get_response(struct bcm3510_state *st, u8 *buf, int len)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun 	bcm3510_register_value v;
140*4882a593Smuzhiyun 	int ret,i;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	v.HABADR_a6.HABADR = 0;
143*4882a593Smuzhiyun 	if ((ret = bcm3510_writeB(st,0xa6,v)) < 0)
144*4882a593Smuzhiyun 		return ret;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	for (i = 0; i < len; i++) {
147*4882a593Smuzhiyun 		if ((ret = bcm3510_readB(st,0xa7,&v)) < 0)
148*4882a593Smuzhiyun 			return ret;
149*4882a593Smuzhiyun 		buf[i] = v.HABDATA_a7;
150*4882a593Smuzhiyun 	}
151*4882a593Smuzhiyun 	return 0;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun 
bcm3510_hab_send_request(struct bcm3510_state * st,u8 * buf,int len)154*4882a593Smuzhiyun static int bcm3510_hab_send_request(struct bcm3510_state *st, u8 *buf, int len)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun 	bcm3510_register_value v,hab;
157*4882a593Smuzhiyun 	int ret,i;
158*4882a593Smuzhiyun 	unsigned long t;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun /* Check if any previous HAB request still needs to be serviced by the
161*4882a593Smuzhiyun  * Acquisition Processor before sending new request */
162*4882a593Smuzhiyun 	if ((ret = bcm3510_readB(st,0xa8,&v)) < 0)
163*4882a593Smuzhiyun 		return ret;
164*4882a593Smuzhiyun 	if (v.HABSTAT_a8.HABR) {
165*4882a593Smuzhiyun 		deb_info("HAB is running already - clearing it.\n");
166*4882a593Smuzhiyun 		v.HABSTAT_a8.HABR = 0;
167*4882a593Smuzhiyun 		bcm3510_writeB(st,0xa8,v);
168*4882a593Smuzhiyun //		return -EBUSY;
169*4882a593Smuzhiyun 	}
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun /* Send the start HAB Address (automatically incremented after write of
172*4882a593Smuzhiyun  * HABDATA) and write the HAB Data */
173*4882a593Smuzhiyun 	hab.HABADR_a6.HABADR = 0;
174*4882a593Smuzhiyun 	if ((ret = bcm3510_writeB(st,0xa6,hab)) < 0)
175*4882a593Smuzhiyun 		return ret;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	for (i = 0; i < len; i++) {
178*4882a593Smuzhiyun 		hab.HABDATA_a7 = buf[i];
179*4882a593Smuzhiyun 		if ((ret = bcm3510_writeB(st,0xa7,hab)) < 0)
180*4882a593Smuzhiyun 			return ret;
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun /* Set the HABR bit to indicate AP request in progress (LBHABR allows HABR to
184*4882a593Smuzhiyun  * be written) */
185*4882a593Smuzhiyun 	v.raw = 0; v.HABSTAT_a8.HABR = 1; v.HABSTAT_a8.LDHABR = 1;
186*4882a593Smuzhiyun 	if ((ret = bcm3510_writeB(st,0xa8,v)) < 0)
187*4882a593Smuzhiyun 		return ret;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun /* Polling method: Wait until the AP finishes processing the HAB request */
190*4882a593Smuzhiyun 	t = jiffies + 1*HZ;
191*4882a593Smuzhiyun 	while (time_before(jiffies, t)) {
192*4882a593Smuzhiyun 		deb_info("waiting for HAB to complete\n");
193*4882a593Smuzhiyun 		msleep(10);
194*4882a593Smuzhiyun 		if ((ret = bcm3510_readB(st,0xa8,&v)) < 0)
195*4882a593Smuzhiyun 			return ret;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 		if (!v.HABSTAT_a8.HABR)
198*4882a593Smuzhiyun 			return 0;
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	deb_info("send_request execution timed out.\n");
202*4882a593Smuzhiyun 	return -ETIMEDOUT;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
bcm3510_do_hab_cmd(struct bcm3510_state * st,u8 cmd,u8 msgid,u8 * obuf,u8 olen,u8 * ibuf,u8 ilen)205*4882a593Smuzhiyun static int bcm3510_do_hab_cmd(struct bcm3510_state *st, u8 cmd, u8 msgid, u8 *obuf, u8 olen, u8 *ibuf, u8 ilen)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun 	u8 ob[MAX_XFER_SIZE], ib[MAX_XFER_SIZE];
208*4882a593Smuzhiyun 	int ret = 0;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	if (ilen + 2 > sizeof(ib)) {
211*4882a593Smuzhiyun 		deb_hab("do_hab_cmd: ilen=%d is too big!\n", ilen);
212*4882a593Smuzhiyun 		return -EINVAL;
213*4882a593Smuzhiyun 	}
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	if (olen + 2 > sizeof(ob)) {
216*4882a593Smuzhiyun 		deb_hab("do_hab_cmd: olen=%d is too big!\n", olen);
217*4882a593Smuzhiyun 		return -EINVAL;
218*4882a593Smuzhiyun 	}
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	ob[0] = cmd;
221*4882a593Smuzhiyun 	ob[1] = msgid;
222*4882a593Smuzhiyun 	memcpy(&ob[2],obuf,olen);
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	deb_hab("hab snd: ");
225*4882a593Smuzhiyun 	dbufout(ob,olen+2,deb_hab);
226*4882a593Smuzhiyun 	deb_hab("\n");
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	if (mutex_lock_interruptible(&st->hab_mutex) < 0)
229*4882a593Smuzhiyun 		return -EAGAIN;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	if ((ret = bcm3510_hab_send_request(st, ob, olen+2)) < 0 ||
232*4882a593Smuzhiyun 		(ret = bcm3510_hab_get_response(st, ib, ilen+2)) < 0)
233*4882a593Smuzhiyun 		goto error;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	deb_hab("hab get: ");
236*4882a593Smuzhiyun 	dbufout(ib,ilen+2,deb_hab);
237*4882a593Smuzhiyun 	deb_hab("\n");
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	memcpy(ibuf,&ib[2],ilen);
240*4882a593Smuzhiyun error:
241*4882a593Smuzhiyun 	mutex_unlock(&st->hab_mutex);
242*4882a593Smuzhiyun 	return ret;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun #if 0
246*4882a593Smuzhiyun /* not needed, we use a semaphore to prevent HAB races */
247*4882a593Smuzhiyun static int bcm3510_is_ap_ready(struct bcm3510_state *st)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun 	bcm3510_register_value ap,hab;
250*4882a593Smuzhiyun 	int ret;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	if ((ret = bcm3510_readB(st,0xa8,&hab)) < 0 ||
253*4882a593Smuzhiyun 		(ret = bcm3510_readB(st,0xa2,&ap) < 0))
254*4882a593Smuzhiyun 		return ret;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	if (ap.APSTAT1_a2.RESET || ap.APSTAT1_a2.IDLE || ap.APSTAT1_a2.STOP || hab.HABSTAT_a8.HABR) {
257*4882a593Smuzhiyun 		deb_info("AP is busy\n");
258*4882a593Smuzhiyun 		return -EBUSY;
259*4882a593Smuzhiyun 	}
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	return 0;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun #endif
264*4882a593Smuzhiyun 
bcm3510_bert_reset(struct bcm3510_state * st)265*4882a593Smuzhiyun static int bcm3510_bert_reset(struct bcm3510_state *st)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun 	bcm3510_register_value b;
268*4882a593Smuzhiyun 	int ret;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	if ((ret = bcm3510_readB(st,0xfa,&b)) < 0)
271*4882a593Smuzhiyun 		return ret;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
274*4882a593Smuzhiyun 	b.BERCTL_fa.RESYNC = 1; bcm3510_writeB(st,0xfa,b);
275*4882a593Smuzhiyun 	b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
276*4882a593Smuzhiyun 	b.BERCTL_fa.CNTCTL = 1; b.BERCTL_fa.BITCNT = 1; bcm3510_writeB(st,0xfa,b);
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	/* clear residual bit counter TODO  */
279*4882a593Smuzhiyun 	return 0;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun 
bcm3510_refresh_state(struct bcm3510_state * st)282*4882a593Smuzhiyun static int bcm3510_refresh_state(struct bcm3510_state *st)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun 	if (time_after(jiffies,st->next_status_check)) {
285*4882a593Smuzhiyun 		bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS1, NULL,0, (u8 *)&st->status1, sizeof(st->status1));
286*4882a593Smuzhiyun 		bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS2, NULL,0, (u8 *)&st->status2, sizeof(st->status2));
287*4882a593Smuzhiyun 		st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
288*4882a593Smuzhiyun 	}
289*4882a593Smuzhiyun 	return 0;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun 
bcm3510_read_status(struct dvb_frontend * fe,enum fe_status * status)292*4882a593Smuzhiyun static int bcm3510_read_status(struct dvb_frontend *fe, enum fe_status *status)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	struct bcm3510_state* st = fe->demodulator_priv;
295*4882a593Smuzhiyun 	bcm3510_refresh_state(st);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	*status = 0;
298*4882a593Smuzhiyun 	if (st->status1.STATUS1.RECEIVER_LOCK)
299*4882a593Smuzhiyun 		*status |= FE_HAS_LOCK | FE_HAS_SYNC;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	if (st->status1.STATUS1.FEC_LOCK)
302*4882a593Smuzhiyun 		*status |= FE_HAS_VITERBI;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	if (st->status1.STATUS1.OUT_PLL_LOCK)
305*4882a593Smuzhiyun 		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	if (*status & FE_HAS_LOCK)
308*4882a593Smuzhiyun 		st->status_check_interval = 1500;
309*4882a593Smuzhiyun 	else /* more frequently checks if no lock has been achieved yet */
310*4882a593Smuzhiyun 		st->status_check_interval = 500;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	deb_info("real_status: %02x\n",*status);
313*4882a593Smuzhiyun 	return 0;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun 
bcm3510_read_ber(struct dvb_frontend * fe,u32 * ber)316*4882a593Smuzhiyun static int bcm3510_read_ber(struct dvb_frontend* fe, u32* ber)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun 	struct bcm3510_state* st = fe->demodulator_priv;
319*4882a593Smuzhiyun 	bcm3510_refresh_state(st);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	*ber = (st->status2.LDBER0 << 16) | (st->status2.LDBER1 << 8) | st->status2.LDBER2;
322*4882a593Smuzhiyun 	return 0;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun 
bcm3510_read_unc(struct dvb_frontend * fe,u32 * unc)325*4882a593Smuzhiyun static int bcm3510_read_unc(struct dvb_frontend* fe, u32* unc)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun 	struct bcm3510_state* st = fe->demodulator_priv;
328*4882a593Smuzhiyun 	bcm3510_refresh_state(st);
329*4882a593Smuzhiyun 	*unc = (st->status2.LDUERC0 << 8) | st->status2.LDUERC1;
330*4882a593Smuzhiyun 	return 0;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun 
bcm3510_read_signal_strength(struct dvb_frontend * fe,u16 * strength)333*4882a593Smuzhiyun static int bcm3510_read_signal_strength(struct dvb_frontend* fe, u16* strength)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun 	struct bcm3510_state* st = fe->demodulator_priv;
336*4882a593Smuzhiyun 	s32 t;
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	bcm3510_refresh_state(st);
339*4882a593Smuzhiyun 	t = st->status2.SIGNAL;
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	if (t > 190)
342*4882a593Smuzhiyun 		t = 190;
343*4882a593Smuzhiyun 	if (t < 90)
344*4882a593Smuzhiyun 		t = 90;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	t -= 90;
347*4882a593Smuzhiyun 	t = t * 0xff / 100;
348*4882a593Smuzhiyun 	/* normalize if necessary */
349*4882a593Smuzhiyun 	*strength = (t << 8) | t;
350*4882a593Smuzhiyun 	return 0;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun 
bcm3510_read_snr(struct dvb_frontend * fe,u16 * snr)353*4882a593Smuzhiyun static int bcm3510_read_snr(struct dvb_frontend* fe, u16* snr)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun 	struct bcm3510_state* st = fe->demodulator_priv;
356*4882a593Smuzhiyun 	bcm3510_refresh_state(st);
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	*snr = st->status1.SNR_EST0*1000 + ((st->status1.SNR_EST1*1000) >> 8);
359*4882a593Smuzhiyun 	return 0;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun /* tuner frontend programming */
bcm3510_tuner_cmd(struct bcm3510_state * st,u8 bc,u16 n,u8 a)363*4882a593Smuzhiyun static int bcm3510_tuner_cmd(struct bcm3510_state* st,u8 bc, u16 n, u8 a)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun 	struct bcm3510_hab_cmd_tune c;
366*4882a593Smuzhiyun 	memset(&c,0,sizeof(struct bcm3510_hab_cmd_tune));
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun /* I2C Mode disabled,  set 16 control / Data pairs */
369*4882a593Smuzhiyun 	c.length = 0x10;
370*4882a593Smuzhiyun 	c.clock_width = 0;
371*4882a593Smuzhiyun /* CS1, CS0, DATA, CLK bits control the tuner RF_AGC_SEL pin is set to
372*4882a593Smuzhiyun  * logic high (as Configuration) */
373*4882a593Smuzhiyun 	c.misc = 0x10;
374*4882a593Smuzhiyun /* Set duration of the initial state of TUNCTL = 3.34 micro Sec */
375*4882a593Smuzhiyun 	c.TUNCTL_state = 0x40;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun /* PRESCALER DIVIDE RATIO | BC1_2_3_4; (band switch), 1stosc REFERENCE COUNTER REF_S12 and REF_S11 */
378*4882a593Smuzhiyun 	c.ctl_dat[0].ctrl.size = BITS_8;
379*4882a593Smuzhiyun 	c.ctl_dat[0].data      = 0x80 | bc;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun /* Control DATA pin, 1stosc REFERENCE COUNTER REF_S10 to REF_S3 */
382*4882a593Smuzhiyun 	c.ctl_dat[1].ctrl.size = BITS_8;
383*4882a593Smuzhiyun 	c.ctl_dat[1].data      = 4;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun /* set CONTROL BIT 1 to 1, 1stosc REFERENCE COUNTER REF_S2 to REF_S1 */
386*4882a593Smuzhiyun 	c.ctl_dat[2].ctrl.size = BITS_3;
387*4882a593Smuzhiyun 	c.ctl_dat[2].data      = 0x20;
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun /* control CS0 pin, pulse byte ? */
390*4882a593Smuzhiyun 	c.ctl_dat[3].ctrl.size = BITS_3;
391*4882a593Smuzhiyun 	c.ctl_dat[3].ctrl.clk_off = 1;
392*4882a593Smuzhiyun 	c.ctl_dat[3].ctrl.cs0  = 1;
393*4882a593Smuzhiyun 	c.ctl_dat[3].data      = 0x40;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun /* PGM_S18 to PGM_S11 */
396*4882a593Smuzhiyun 	c.ctl_dat[4].ctrl.size = BITS_8;
397*4882a593Smuzhiyun 	c.ctl_dat[4].data      = n >> 3;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun /* PGM_S10 to PGM_S8, SWL_S7 to SWL_S3 */
400*4882a593Smuzhiyun 	c.ctl_dat[5].ctrl.size = BITS_8;
401*4882a593Smuzhiyun 	c.ctl_dat[5].data      = ((n & 0x7) << 5) | (a >> 2);
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun /* SWL_S2 and SWL_S1, set CONTROL BIT 2 to 0 */
404*4882a593Smuzhiyun 	c.ctl_dat[6].ctrl.size = BITS_3;
405*4882a593Smuzhiyun 	c.ctl_dat[6].data      = (a << 6) & 0xdf;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun /* control CS0 pin, pulse byte ? */
408*4882a593Smuzhiyun 	c.ctl_dat[7].ctrl.size = BITS_3;
409*4882a593Smuzhiyun 	c.ctl_dat[7].ctrl.clk_off = 1;
410*4882a593Smuzhiyun 	c.ctl_dat[7].ctrl.cs0  = 1;
411*4882a593Smuzhiyun 	c.ctl_dat[7].data      = 0x40;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun /* PRESCALER DIVIDE RATIO, 2ndosc REFERENCE COUNTER REF_S12 and REF_S11 */
414*4882a593Smuzhiyun 	c.ctl_dat[8].ctrl.size = BITS_8;
415*4882a593Smuzhiyun 	c.ctl_dat[8].data      = 0x80;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun /* 2ndosc REFERENCE COUNTER REF_S10 to REF_S3 */
418*4882a593Smuzhiyun 	c.ctl_dat[9].ctrl.size = BITS_8;
419*4882a593Smuzhiyun 	c.ctl_dat[9].data      = 0x10;
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun /* set CONTROL BIT 1 to 1, 2ndosc REFERENCE COUNTER REF_S2 to REF_S1 */
422*4882a593Smuzhiyun 	c.ctl_dat[10].ctrl.size = BITS_3;
423*4882a593Smuzhiyun 	c.ctl_dat[10].data      = 0x20;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun /* pulse byte */
426*4882a593Smuzhiyun 	c.ctl_dat[11].ctrl.size = BITS_3;
427*4882a593Smuzhiyun 	c.ctl_dat[11].ctrl.clk_off = 1;
428*4882a593Smuzhiyun 	c.ctl_dat[11].ctrl.cs1  = 1;
429*4882a593Smuzhiyun 	c.ctl_dat[11].data      = 0x40;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun /* PGM_S18 to PGM_S11 */
432*4882a593Smuzhiyun 	c.ctl_dat[12].ctrl.size = BITS_8;
433*4882a593Smuzhiyun 	c.ctl_dat[12].data      = 0x2a;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun /* PGM_S10 to PGM_S8 and SWL_S7 to SWL_S3 */
436*4882a593Smuzhiyun 	c.ctl_dat[13].ctrl.size = BITS_8;
437*4882a593Smuzhiyun 	c.ctl_dat[13].data      = 0x8e;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun /* SWL_S2 and SWL_S1 and set CONTROL BIT 2 to 0 */
440*4882a593Smuzhiyun 	c.ctl_dat[14].ctrl.size = BITS_3;
441*4882a593Smuzhiyun 	c.ctl_dat[14].data      = 0;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun /* Pulse Byte */
444*4882a593Smuzhiyun 	c.ctl_dat[15].ctrl.size = BITS_3;
445*4882a593Smuzhiyun 	c.ctl_dat[15].ctrl.clk_off = 1;
446*4882a593Smuzhiyun 	c.ctl_dat[15].ctrl.cs1  = 1;
447*4882a593Smuzhiyun 	c.ctl_dat[15].data      = 0x40;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	return bcm3510_do_hab_cmd(st,CMD_TUNE, MSGID_TUNE,(u8 *) &c,sizeof(c), NULL, 0);
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun 
bcm3510_set_freq(struct bcm3510_state * st,u32 freq)452*4882a593Smuzhiyun static int bcm3510_set_freq(struct bcm3510_state* st,u32 freq)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun 	u8 bc,a;
455*4882a593Smuzhiyun 	u16 n;
456*4882a593Smuzhiyun 	s32 YIntercept,Tfvco1;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	freq /= 1000;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	deb_info("%dkHz:",freq);
461*4882a593Smuzhiyun 	/* set Band Switch */
462*4882a593Smuzhiyun 	if (freq <= 168000)
463*4882a593Smuzhiyun 		bc = 0x1c;
464*4882a593Smuzhiyun 	else if (freq <= 378000)
465*4882a593Smuzhiyun 		bc = 0x2c;
466*4882a593Smuzhiyun 	else
467*4882a593Smuzhiyun 		bc = 0x30;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	if (freq >= 470000) {
470*4882a593Smuzhiyun 		freq -= 470001;
471*4882a593Smuzhiyun 		YIntercept = 18805;
472*4882a593Smuzhiyun 	} else if (freq >= 90000) {
473*4882a593Smuzhiyun 		freq -= 90001;
474*4882a593Smuzhiyun 		YIntercept = 15005;
475*4882a593Smuzhiyun 	} else if (freq >= 76000){
476*4882a593Smuzhiyun 		freq -= 76001;
477*4882a593Smuzhiyun 		YIntercept = 14865;
478*4882a593Smuzhiyun 	} else {
479*4882a593Smuzhiyun 		freq -= 54001;
480*4882a593Smuzhiyun 		YIntercept = 14645;
481*4882a593Smuzhiyun 	}
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	Tfvco1 = (((freq/6000)*60 + YIntercept)*4)/10;
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	n = Tfvco1 >> 6;
486*4882a593Smuzhiyun 	a = Tfvco1 & 0x3f;
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	deb_info(" BC1_2_3_4: %x, N: %x A: %x\n", bc, n, a);
489*4882a593Smuzhiyun 	if (n >= 16 && n <= 2047)
490*4882a593Smuzhiyun 		return bcm3510_tuner_cmd(st,bc,n,a);
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	return -EINVAL;
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun 
bcm3510_set_frontend(struct dvb_frontend * fe)495*4882a593Smuzhiyun static int bcm3510_set_frontend(struct dvb_frontend *fe)
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
498*4882a593Smuzhiyun 	struct bcm3510_state* st = fe->demodulator_priv;
499*4882a593Smuzhiyun 	struct bcm3510_hab_cmd_ext_acquire cmd;
500*4882a593Smuzhiyun 	struct bcm3510_hab_cmd_bert_control bert;
501*4882a593Smuzhiyun 	int ret;
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	memset(&cmd,0,sizeof(cmd));
504*4882a593Smuzhiyun 	switch (c->modulation) {
505*4882a593Smuzhiyun 		case QAM_256:
506*4882a593Smuzhiyun 			cmd.ACQUIRE0.MODE = 0x1;
507*4882a593Smuzhiyun 			cmd.ACQUIRE1.SYM_RATE = 0x1;
508*4882a593Smuzhiyun 			cmd.ACQUIRE1.IF_FREQ = 0x1;
509*4882a593Smuzhiyun 			break;
510*4882a593Smuzhiyun 		case QAM_64:
511*4882a593Smuzhiyun 			cmd.ACQUIRE0.MODE = 0x2;
512*4882a593Smuzhiyun 			cmd.ACQUIRE1.SYM_RATE = 0x2;
513*4882a593Smuzhiyun 			cmd.ACQUIRE1.IF_FREQ = 0x1;
514*4882a593Smuzhiyun 			break;
515*4882a593Smuzhiyun #if 0
516*4882a593Smuzhiyun 		case QAM_256:
517*4882a593Smuzhiyun 			cmd.ACQUIRE0.MODE = 0x3;
518*4882a593Smuzhiyun 			break;
519*4882a593Smuzhiyun 		case QAM_128:
520*4882a593Smuzhiyun 			cmd.ACQUIRE0.MODE = 0x4;
521*4882a593Smuzhiyun 			break;
522*4882a593Smuzhiyun 		case QAM_64:
523*4882a593Smuzhiyun 			cmd.ACQUIRE0.MODE = 0x5;
524*4882a593Smuzhiyun 			break;
525*4882a593Smuzhiyun 		case QAM_32:
526*4882a593Smuzhiyun 			cmd.ACQUIRE0.MODE = 0x6;
527*4882a593Smuzhiyun 			break;
528*4882a593Smuzhiyun 		case QAM_16:
529*4882a593Smuzhiyun 			cmd.ACQUIRE0.MODE = 0x7;
530*4882a593Smuzhiyun 			break;
531*4882a593Smuzhiyun #endif
532*4882a593Smuzhiyun 		case VSB_8:
533*4882a593Smuzhiyun 			cmd.ACQUIRE0.MODE = 0x8;
534*4882a593Smuzhiyun 			cmd.ACQUIRE1.SYM_RATE = 0x0;
535*4882a593Smuzhiyun 			cmd.ACQUIRE1.IF_FREQ = 0x0;
536*4882a593Smuzhiyun 			break;
537*4882a593Smuzhiyun 		case VSB_16:
538*4882a593Smuzhiyun 			cmd.ACQUIRE0.MODE = 0x9;
539*4882a593Smuzhiyun 			cmd.ACQUIRE1.SYM_RATE = 0x0;
540*4882a593Smuzhiyun 			cmd.ACQUIRE1.IF_FREQ = 0x0;
541*4882a593Smuzhiyun 			break;
542*4882a593Smuzhiyun 		default:
543*4882a593Smuzhiyun 			return -EINVAL;
544*4882a593Smuzhiyun 	}
545*4882a593Smuzhiyun 	cmd.ACQUIRE0.OFFSET = 0;
546*4882a593Smuzhiyun 	cmd.ACQUIRE0.NTSCSWEEP = 1;
547*4882a593Smuzhiyun 	cmd.ACQUIRE0.FA = 1;
548*4882a593Smuzhiyun 	cmd.ACQUIRE0.BW = 0;
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun /*	if (enableOffset) {
551*4882a593Smuzhiyun 		cmd.IF_OFFSET0 = xx;
552*4882a593Smuzhiyun 		cmd.IF_OFFSET1 = xx;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 		cmd.SYM_OFFSET0 = xx;
555*4882a593Smuzhiyun 		cmd.SYM_OFFSET1 = xx;
556*4882a593Smuzhiyun 		if (enableNtscSweep) {
557*4882a593Smuzhiyun 			cmd.NTSC_OFFSET0;
558*4882a593Smuzhiyun 			cmd.NTSC_OFFSET1;
559*4882a593Smuzhiyun 		}
560*4882a593Smuzhiyun 	} */
561*4882a593Smuzhiyun 	bcm3510_do_hab_cmd(st, CMD_ACQUIRE, MSGID_EXT_TUNER_ACQUIRE, (u8 *) &cmd, sizeof(cmd), NULL, 0);
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun /* doing it with different MSGIDs, data book and source differs */
564*4882a593Smuzhiyun 	bert.BE = 0;
565*4882a593Smuzhiyun 	bert.unused = 0;
566*4882a593Smuzhiyun 	bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_CONTROL, (u8 *) &bert, sizeof(bert), NULL, 0);
567*4882a593Smuzhiyun 	bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_SET, (u8 *) &bert, sizeof(bert), NULL, 0);
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	bcm3510_bert_reset(st);
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	ret = bcm3510_set_freq(st, c->frequency);
572*4882a593Smuzhiyun 	if (ret < 0)
573*4882a593Smuzhiyun 		return ret;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	memset(&st->status1,0,sizeof(st->status1));
576*4882a593Smuzhiyun 	memset(&st->status2,0,sizeof(st->status2));
577*4882a593Smuzhiyun 	st->status_check_interval = 500;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun /* Give the AP some time */
580*4882a593Smuzhiyun 	msleep(200);
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	return 0;
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun 
bcm3510_sleep(struct dvb_frontend * fe)585*4882a593Smuzhiyun static int bcm3510_sleep(struct dvb_frontend* fe)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun 	return 0;
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun 
bcm3510_get_tune_settings(struct dvb_frontend * fe,struct dvb_frontend_tune_settings * s)590*4882a593Smuzhiyun static int bcm3510_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *s)
591*4882a593Smuzhiyun {
592*4882a593Smuzhiyun 	s->min_delay_ms = 1000;
593*4882a593Smuzhiyun 	s->step_size = 0;
594*4882a593Smuzhiyun 	s->max_drift = 0;
595*4882a593Smuzhiyun 	return 0;
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun 
bcm3510_release(struct dvb_frontend * fe)598*4882a593Smuzhiyun static void bcm3510_release(struct dvb_frontend* fe)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun 	struct bcm3510_state* state = fe->demodulator_priv;
601*4882a593Smuzhiyun 	kfree(state);
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun /* firmware download:
605*4882a593Smuzhiyun  * firmware file is build up like this:
606*4882a593Smuzhiyun  * 16bit addr, 16bit length, 8byte of length
607*4882a593Smuzhiyun  */
608*4882a593Smuzhiyun #define BCM3510_DEFAULT_FIRMWARE "dvb-fe-bcm3510-01.fw"
609*4882a593Smuzhiyun 
bcm3510_write_ram(struct bcm3510_state * st,u16 addr,const u8 * b,u16 len)610*4882a593Smuzhiyun static int bcm3510_write_ram(struct bcm3510_state *st, u16 addr, const u8 *b,
611*4882a593Smuzhiyun 			     u16 len)
612*4882a593Smuzhiyun {
613*4882a593Smuzhiyun 	int ret = 0,i;
614*4882a593Smuzhiyun 	bcm3510_register_value vH, vL,vD;
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	vH.MADRH_a9 = addr >> 8;
617*4882a593Smuzhiyun 	vL.MADRL_aa = addr;
618*4882a593Smuzhiyun 	if ((ret = bcm3510_writeB(st,0xa9,vH)) < 0) return ret;
619*4882a593Smuzhiyun 	if ((ret = bcm3510_writeB(st,0xaa,vL)) < 0) return ret;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	for (i = 0; i < len; i++) {
622*4882a593Smuzhiyun 		vD.MDATA_ab = b[i];
623*4882a593Smuzhiyun 		if ((ret = bcm3510_writeB(st,0xab,vD)) < 0)
624*4882a593Smuzhiyun 			return ret;
625*4882a593Smuzhiyun 	}
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 	return 0;
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun 
bcm3510_download_firmware(struct dvb_frontend * fe)630*4882a593Smuzhiyun static int bcm3510_download_firmware(struct dvb_frontend* fe)
631*4882a593Smuzhiyun {
632*4882a593Smuzhiyun 	struct bcm3510_state* st = fe->demodulator_priv;
633*4882a593Smuzhiyun 	const struct firmware *fw;
634*4882a593Smuzhiyun 	u16 addr,len;
635*4882a593Smuzhiyun 	const u8 *b;
636*4882a593Smuzhiyun 	int ret,i;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	deb_info("requesting firmware\n");
639*4882a593Smuzhiyun 	if ((ret = st->config->request_firmware(fe, &fw, BCM3510_DEFAULT_FIRMWARE)) < 0) {
640*4882a593Smuzhiyun 		err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret);
641*4882a593Smuzhiyun 		return ret;
642*4882a593Smuzhiyun 	}
643*4882a593Smuzhiyun 	deb_info("got firmware: %zu\n", fw->size);
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	b = fw->data;
646*4882a593Smuzhiyun 	for (i = 0; i < fw->size;) {
647*4882a593Smuzhiyun 		addr = le16_to_cpu(*((__le16 *)&b[i]));
648*4882a593Smuzhiyun 		len  = le16_to_cpu(*((__le16 *)&b[i+2]));
649*4882a593Smuzhiyun 		deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size);
650*4882a593Smuzhiyun 		if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) {
651*4882a593Smuzhiyun 			err("firmware download failed: %d\n",ret);
652*4882a593Smuzhiyun 			return ret;
653*4882a593Smuzhiyun 		}
654*4882a593Smuzhiyun 		i += 4 + len;
655*4882a593Smuzhiyun 	}
656*4882a593Smuzhiyun 	release_firmware(fw);
657*4882a593Smuzhiyun 	deb_info("firmware download successfully completed\n");
658*4882a593Smuzhiyun 	return 0;
659*4882a593Smuzhiyun }
660*4882a593Smuzhiyun 
bcm3510_check_firmware_version(struct bcm3510_state * st)661*4882a593Smuzhiyun static int bcm3510_check_firmware_version(struct bcm3510_state *st)
662*4882a593Smuzhiyun {
663*4882a593Smuzhiyun 	struct bcm3510_hab_cmd_get_version_info ver;
664*4882a593Smuzhiyun 	bcm3510_do_hab_cmd(st,CMD_GET_VERSION_INFO,MSGID_GET_VERSION_INFO,NULL,0,(u8*)&ver,sizeof(ver));
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	deb_info("Version information: 0x%02x 0x%02x 0x%02x 0x%02x\n",
667*4882a593Smuzhiyun 		ver.microcode_version, ver.script_version, ver.config_version, ver.demod_version);
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	if (ver.script_version == BCM3510_DEF_SCRIPT_VERSION &&
670*4882a593Smuzhiyun 		ver.config_version == BCM3510_DEF_CONFIG_VERSION &&
671*4882a593Smuzhiyun 		ver.demod_version  == BCM3510_DEF_DEMOD_VERSION)
672*4882a593Smuzhiyun 		return 0;
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	deb_info("version check failed\n");
675*4882a593Smuzhiyun 	return -ENODEV;
676*4882a593Smuzhiyun }
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun /* (un)resetting the AP */
bcm3510_reset(struct bcm3510_state * st)679*4882a593Smuzhiyun static int bcm3510_reset(struct bcm3510_state *st)
680*4882a593Smuzhiyun {
681*4882a593Smuzhiyun 	int ret;
682*4882a593Smuzhiyun 	unsigned long  t;
683*4882a593Smuzhiyun 	bcm3510_register_value v;
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 	bcm3510_readB(st,0xa0,&v); v.HCTL1_a0.RESET = 1;
686*4882a593Smuzhiyun 	if ((ret = bcm3510_writeB(st,0xa0,v)) < 0)
687*4882a593Smuzhiyun 		return ret;
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	t = jiffies + 3*HZ;
690*4882a593Smuzhiyun 	while (time_before(jiffies, t)) {
691*4882a593Smuzhiyun 		msleep(10);
692*4882a593Smuzhiyun 		if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
693*4882a593Smuzhiyun 			return ret;
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 		if (v.APSTAT1_a2.RESET)
696*4882a593Smuzhiyun 			return 0;
697*4882a593Smuzhiyun 	}
698*4882a593Smuzhiyun 	deb_info("reset timed out\n");
699*4882a593Smuzhiyun 	return -ETIMEDOUT;
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun 
bcm3510_clear_reset(struct bcm3510_state * st)702*4882a593Smuzhiyun static int bcm3510_clear_reset(struct bcm3510_state *st)
703*4882a593Smuzhiyun {
704*4882a593Smuzhiyun 	bcm3510_register_value v;
705*4882a593Smuzhiyun 	int ret;
706*4882a593Smuzhiyun 	unsigned long t;
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	v.raw = 0;
709*4882a593Smuzhiyun 	if ((ret = bcm3510_writeB(st,0xa0,v)) < 0)
710*4882a593Smuzhiyun 		return ret;
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	t = jiffies + 3*HZ;
713*4882a593Smuzhiyun 	while (time_before(jiffies, t)) {
714*4882a593Smuzhiyun 		msleep(10);
715*4882a593Smuzhiyun 		if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
716*4882a593Smuzhiyun 			return ret;
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 		/* verify that reset is cleared */
719*4882a593Smuzhiyun 		if (!v.APSTAT1_a2.RESET)
720*4882a593Smuzhiyun 			return 0;
721*4882a593Smuzhiyun 	}
722*4882a593Smuzhiyun 	deb_info("reset clear timed out\n");
723*4882a593Smuzhiyun 	return -ETIMEDOUT;
724*4882a593Smuzhiyun }
725*4882a593Smuzhiyun 
bcm3510_init_cold(struct bcm3510_state * st)726*4882a593Smuzhiyun static int bcm3510_init_cold(struct bcm3510_state *st)
727*4882a593Smuzhiyun {
728*4882a593Smuzhiyun 	int ret;
729*4882a593Smuzhiyun 	bcm3510_register_value v;
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	/* read Acquisation Processor status register and check it is not in RUN mode */
732*4882a593Smuzhiyun 	if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
733*4882a593Smuzhiyun 		return ret;
734*4882a593Smuzhiyun 	if (v.APSTAT1_a2.RUN) {
735*4882a593Smuzhiyun 		deb_info("AP is already running - firmware already loaded.\n");
736*4882a593Smuzhiyun 		return 0;
737*4882a593Smuzhiyun 	}
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 	deb_info("reset?\n");
740*4882a593Smuzhiyun 	if ((ret = bcm3510_reset(st)) < 0)
741*4882a593Smuzhiyun 		return ret;
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	deb_info("tristate?\n");
744*4882a593Smuzhiyun 	/* tri-state */
745*4882a593Smuzhiyun 	v.TSTCTL_2e.CTL = 0;
746*4882a593Smuzhiyun 	if ((ret = bcm3510_writeB(st,0x2e,v)) < 0)
747*4882a593Smuzhiyun 		return ret;
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	deb_info("firmware?\n");
750*4882a593Smuzhiyun 	if ((ret = bcm3510_download_firmware(&st->frontend)) < 0 ||
751*4882a593Smuzhiyun 		(ret = bcm3510_clear_reset(st)) < 0)
752*4882a593Smuzhiyun 		return ret;
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	/* anything left here to Let the acquisition processor begin execution at program counter 0000 ??? */
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 	return 0;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun 
bcm3510_init(struct dvb_frontend * fe)759*4882a593Smuzhiyun static int bcm3510_init(struct dvb_frontend* fe)
760*4882a593Smuzhiyun {
761*4882a593Smuzhiyun 	struct bcm3510_state* st = fe->demodulator_priv;
762*4882a593Smuzhiyun 	bcm3510_register_value j;
763*4882a593Smuzhiyun 	struct bcm3510_hab_cmd_set_agc c;
764*4882a593Smuzhiyun 	int ret;
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	if ((ret = bcm3510_readB(st,0xca,&j)) < 0)
767*4882a593Smuzhiyun 		return ret;
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 	deb_info("JDEC: %02x\n",j.raw);
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun 	switch (j.JDEC_ca.JDEC) {
772*4882a593Smuzhiyun 		case JDEC_WAIT_AT_RAM:
773*4882a593Smuzhiyun 			deb_info("attempting to download firmware\n");
774*4882a593Smuzhiyun 			if ((ret = bcm3510_init_cold(st)) < 0)
775*4882a593Smuzhiyun 				return ret;
776*4882a593Smuzhiyun 			fallthrough;
777*4882a593Smuzhiyun 		case JDEC_EEPROM_LOAD_WAIT:
778*4882a593Smuzhiyun 			deb_info("firmware is loaded\n");
779*4882a593Smuzhiyun 			bcm3510_check_firmware_version(st);
780*4882a593Smuzhiyun 			break;
781*4882a593Smuzhiyun 		default:
782*4882a593Smuzhiyun 			return -ENODEV;
783*4882a593Smuzhiyun 	}
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	memset(&c,0,1);
786*4882a593Smuzhiyun 	c.SEL = 1;
787*4882a593Smuzhiyun 	bcm3510_do_hab_cmd(st,CMD_AUTO_PARAM,MSGID_SET_RF_AGC_SEL,(u8 *)&c,sizeof(c),NULL,0);
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 	return 0;
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun static const struct dvb_frontend_ops bcm3510_ops;
794*4882a593Smuzhiyun 
bcm3510_attach(const struct bcm3510_config * config,struct i2c_adapter * i2c)795*4882a593Smuzhiyun struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config,
796*4882a593Smuzhiyun 				   struct i2c_adapter *i2c)
797*4882a593Smuzhiyun {
798*4882a593Smuzhiyun 	struct bcm3510_state* state = NULL;
799*4882a593Smuzhiyun 	int ret;
800*4882a593Smuzhiyun 	bcm3510_register_value v;
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 	/* allocate memory for the internal state */
803*4882a593Smuzhiyun 	state = kzalloc(sizeof(struct bcm3510_state), GFP_KERNEL);
804*4882a593Smuzhiyun 	if (state == NULL)
805*4882a593Smuzhiyun 		goto error;
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 	/* setup the state */
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	state->config = config;
810*4882a593Smuzhiyun 	state->i2c = i2c;
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun 	/* create dvb_frontend */
813*4882a593Smuzhiyun 	memcpy(&state->frontend.ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
814*4882a593Smuzhiyun 	state->frontend.demodulator_priv = state;
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun 	mutex_init(&state->hab_mutex);
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 	if ((ret = bcm3510_readB(state,0xe0,&v)) < 0)
819*4882a593Smuzhiyun 		goto error;
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun 	deb_info("Revision: 0x%1x, Layer: 0x%1x.\n",v.REVID_e0.REV,v.REVID_e0.LAYER);
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun 	if ((v.REVID_e0.REV != 0x1 && v.REVID_e0.LAYER != 0xb) && /* cold */
824*4882a593Smuzhiyun 		(v.REVID_e0.REV != 0x8 && v.REVID_e0.LAYER != 0x0))   /* warm */
825*4882a593Smuzhiyun 		goto error;
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun 	info("Revision: 0x%1x, Layer: 0x%1x.",v.REVID_e0.REV,v.REVID_e0.LAYER);
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun 	bcm3510_reset(state);
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 	return &state->frontend;
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun error:
834*4882a593Smuzhiyun 	kfree(state);
835*4882a593Smuzhiyun 	return NULL;
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun EXPORT_SYMBOL(bcm3510_attach);
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun static const struct dvb_frontend_ops bcm3510_ops = {
840*4882a593Smuzhiyun 	.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
841*4882a593Smuzhiyun 	.info = {
842*4882a593Smuzhiyun 		.name = "Broadcom BCM3510 VSB/QAM frontend",
843*4882a593Smuzhiyun 		.frequency_min_hz =  54 * MHz,
844*4882a593Smuzhiyun 		.frequency_max_hz = 803 * MHz,
845*4882a593Smuzhiyun 		.caps =
846*4882a593Smuzhiyun 			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
847*4882a593Smuzhiyun 			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
848*4882a593Smuzhiyun 			FE_CAN_8VSB | FE_CAN_16VSB |
849*4882a593Smuzhiyun 			FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256
850*4882a593Smuzhiyun 	},
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 	.release = bcm3510_release,
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun 	.init = bcm3510_init,
855*4882a593Smuzhiyun 	.sleep = bcm3510_sleep,
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	.set_frontend = bcm3510_set_frontend,
858*4882a593Smuzhiyun 	.get_tune_settings = bcm3510_get_tune_settings,
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun 	.read_status = bcm3510_read_status,
861*4882a593Smuzhiyun 	.read_ber = bcm3510_read_ber,
862*4882a593Smuzhiyun 	.read_signal_strength = bcm3510_read_signal_strength,
863*4882a593Smuzhiyun 	.read_snr = bcm3510_read_snr,
864*4882a593Smuzhiyun 	.read_ucblocks = bcm3510_read_unc,
865*4882a593Smuzhiyun };
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun MODULE_DESCRIPTION("Broadcom BCM3510 ATSC (8VSB/16VSB & ITU J83 AnnexB FEC QAM64/256) demodulator driver");
868*4882a593Smuzhiyun MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
869*4882a593Smuzhiyun MODULE_LICENSE("GPL");
870