xref: /OK3568_Linux_fs/kernel/drivers/media/dvb-frontends/si21xx.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /* DVB compliant Linux driver for the DVB-S si2109/2110 demodulator
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun #include <linux/init.h>
7*4882a593Smuzhiyun #include <linux/kernel.h>
8*4882a593Smuzhiyun #include <linux/module.h>
9*4882a593Smuzhiyun #include <linux/string.h>
10*4882a593Smuzhiyun #include <linux/slab.h>
11*4882a593Smuzhiyun #include <linux/jiffies.h>
12*4882a593Smuzhiyun #include <asm/div64.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include <media/dvb_frontend.h>
15*4882a593Smuzhiyun #include "si21xx.h"
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define	REVISION_REG			0x00
18*4882a593Smuzhiyun #define	SYSTEM_MODE_REG			0x01
19*4882a593Smuzhiyun #define	TS_CTRL_REG_1			0x02
20*4882a593Smuzhiyun #define	TS_CTRL_REG_2			0x03
21*4882a593Smuzhiyun #define	PIN_CTRL_REG_1			0x04
22*4882a593Smuzhiyun #define	PIN_CTRL_REG_2			0x05
23*4882a593Smuzhiyun #define	LOCK_STATUS_REG_1		0x0f
24*4882a593Smuzhiyun #define	LOCK_STATUS_REG_2		0x10
25*4882a593Smuzhiyun #define	ACQ_STATUS_REG			0x11
26*4882a593Smuzhiyun #define	ACQ_CTRL_REG_1			0x13
27*4882a593Smuzhiyun #define	ACQ_CTRL_REG_2			0x14
28*4882a593Smuzhiyun #define	PLL_DIVISOR_REG			0x15
29*4882a593Smuzhiyun #define	COARSE_TUNE_REG			0x16
30*4882a593Smuzhiyun #define	FINE_TUNE_REG_L			0x17
31*4882a593Smuzhiyun #define	FINE_TUNE_REG_H			0x18
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define	ANALOG_AGC_POWER_LEVEL_REG	0x28
34*4882a593Smuzhiyun #define	CFO_ESTIMATOR_CTRL_REG_1	0x29
35*4882a593Smuzhiyun #define	CFO_ESTIMATOR_CTRL_REG_2	0x2a
36*4882a593Smuzhiyun #define	CFO_ESTIMATOR_CTRL_REG_3	0x2b
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #define	SYM_RATE_ESTIMATE_REG_L		0x31
39*4882a593Smuzhiyun #define	SYM_RATE_ESTIMATE_REG_M		0x32
40*4882a593Smuzhiyun #define	SYM_RATE_ESTIMATE_REG_H		0x33
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #define	CFO_ESTIMATOR_OFFSET_REG_L	0x36
43*4882a593Smuzhiyun #define	CFO_ESTIMATOR_OFFSET_REG_H	0x37
44*4882a593Smuzhiyun #define	CFO_ERROR_REG_L			0x38
45*4882a593Smuzhiyun #define	CFO_ERROR_REG_H			0x39
46*4882a593Smuzhiyun #define	SYM_RATE_ESTIMATOR_CTRL_REG	0x3a
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun #define	SYM_RATE_REG_L			0x3f
49*4882a593Smuzhiyun #define	SYM_RATE_REG_M			0x40
50*4882a593Smuzhiyun #define	SYM_RATE_REG_H			0x41
51*4882a593Smuzhiyun #define	SYM_RATE_ESTIMATOR_MAXIMUM_REG	0x42
52*4882a593Smuzhiyun #define	SYM_RATE_ESTIMATOR_MINIMUM_REG	0x43
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #define	C_N_ESTIMATOR_CTRL_REG		0x7c
55*4882a593Smuzhiyun #define	C_N_ESTIMATOR_THRSHLD_REG	0x7d
56*4882a593Smuzhiyun #define	C_N_ESTIMATOR_LEVEL_REG_L	0x7e
57*4882a593Smuzhiyun #define	C_N_ESTIMATOR_LEVEL_REG_H	0x7f
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define	BLIND_SCAN_CTRL_REG		0x80
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun #define	LSA_CTRL_REG_1			0x8D
62*4882a593Smuzhiyun #define	SPCTRM_TILT_CORR_THRSHLD_REG	0x8f
63*4882a593Smuzhiyun #define	ONE_DB_BNDWDTH_THRSHLD_REG	0x90
64*4882a593Smuzhiyun #define	TWO_DB_BNDWDTH_THRSHLD_REG	0x91
65*4882a593Smuzhiyun #define	THREE_DB_BNDWDTH_THRSHLD_REG	0x92
66*4882a593Smuzhiyun #define	INBAND_POWER_THRSHLD_REG	0x93
67*4882a593Smuzhiyun #define	REF_NOISE_LVL_MRGN_THRSHLD_REG	0x94
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun #define	VIT_SRCH_CTRL_REG_1		0xa0
70*4882a593Smuzhiyun #define	VIT_SRCH_CTRL_REG_2		0xa1
71*4882a593Smuzhiyun #define	VIT_SRCH_CTRL_REG_3		0xa2
72*4882a593Smuzhiyun #define	VIT_SRCH_STATUS_REG		0xa3
73*4882a593Smuzhiyun #define	VITERBI_BER_COUNT_REG_L		0xab
74*4882a593Smuzhiyun #define	REED_SOLOMON_CTRL_REG		0xb0
75*4882a593Smuzhiyun #define	REED_SOLOMON_ERROR_COUNT_REG_L	0xb1
76*4882a593Smuzhiyun #define	PRBS_CTRL_REG			0xb5
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun #define	LNB_CTRL_REG_1			0xc0
79*4882a593Smuzhiyun #define	LNB_CTRL_REG_2			0xc1
80*4882a593Smuzhiyun #define	LNB_CTRL_REG_3			0xc2
81*4882a593Smuzhiyun #define	LNB_CTRL_REG_4			0xc3
82*4882a593Smuzhiyun #define	LNB_CTRL_STATUS_REG		0xc4
83*4882a593Smuzhiyun #define	LNB_FIFO_REGS_0			0xc5
84*4882a593Smuzhiyun #define	LNB_FIFO_REGS_1			0xc6
85*4882a593Smuzhiyun #define	LNB_FIFO_REGS_2			0xc7
86*4882a593Smuzhiyun #define	LNB_FIFO_REGS_3			0xc8
87*4882a593Smuzhiyun #define	LNB_FIFO_REGS_4			0xc9
88*4882a593Smuzhiyun #define	LNB_FIFO_REGS_5			0xca
89*4882a593Smuzhiyun #define	LNB_SUPPLY_CTRL_REG_1		0xcb
90*4882a593Smuzhiyun #define	LNB_SUPPLY_CTRL_REG_2		0xcc
91*4882a593Smuzhiyun #define	LNB_SUPPLY_CTRL_REG_3		0xcd
92*4882a593Smuzhiyun #define	LNB_SUPPLY_CTRL_REG_4		0xce
93*4882a593Smuzhiyun #define	LNB_SUPPLY_STATUS_REG		0xcf
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun #define FAIL	-1
96*4882a593Smuzhiyun #define PASS	0
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun #define ALLOWABLE_FS_COUNT	10
99*4882a593Smuzhiyun #define STATUS_BER		0
100*4882a593Smuzhiyun #define STATUS_UCBLOCKS		1
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun static int debug;
103*4882a593Smuzhiyun #define dprintk(args...) \
104*4882a593Smuzhiyun 	do { \
105*4882a593Smuzhiyun 		if (debug) \
106*4882a593Smuzhiyun 			printk(KERN_DEBUG "si21xx: " args); \
107*4882a593Smuzhiyun 	} while (0)
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun enum {
110*4882a593Smuzhiyun 	ACTIVE_HIGH,
111*4882a593Smuzhiyun 	ACTIVE_LOW
112*4882a593Smuzhiyun };
113*4882a593Smuzhiyun enum {
114*4882a593Smuzhiyun 	BYTE_WIDE,
115*4882a593Smuzhiyun 	BIT_WIDE
116*4882a593Smuzhiyun };
117*4882a593Smuzhiyun enum {
118*4882a593Smuzhiyun 	CLK_GAPPED_MODE,
119*4882a593Smuzhiyun 	CLK_CONTINUOUS_MODE
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun enum {
122*4882a593Smuzhiyun 	RISING_EDGE,
123*4882a593Smuzhiyun 	FALLING_EDGE
124*4882a593Smuzhiyun };
125*4882a593Smuzhiyun enum {
126*4882a593Smuzhiyun 	MSB_FIRST,
127*4882a593Smuzhiyun 	LSB_FIRST
128*4882a593Smuzhiyun };
129*4882a593Smuzhiyun enum {
130*4882a593Smuzhiyun 	SERIAL,
131*4882a593Smuzhiyun 	PARALLEL
132*4882a593Smuzhiyun };
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun struct si21xx_state {
135*4882a593Smuzhiyun 	struct i2c_adapter *i2c;
136*4882a593Smuzhiyun 	const struct si21xx_config *config;
137*4882a593Smuzhiyun 	struct dvb_frontend frontend;
138*4882a593Smuzhiyun 	u8 initialised:1;
139*4882a593Smuzhiyun 	int errmode;
140*4882a593Smuzhiyun 	int fs;			/*Sampling rate of the ADC in MHz*/
141*4882a593Smuzhiyun };
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun /*	register default initialization */
144*4882a593Smuzhiyun static u8 serit_sp1511lhb_inittab[] = {
145*4882a593Smuzhiyun 	0x01, 0x28,	/* set i2c_inc_disable */
146*4882a593Smuzhiyun 	0x20, 0x03,
147*4882a593Smuzhiyun 	0x27, 0x20,
148*4882a593Smuzhiyun 	0xe0, 0x45,
149*4882a593Smuzhiyun 	0xe1, 0x08,
150*4882a593Smuzhiyun 	0xfe, 0x01,
151*4882a593Smuzhiyun 	0x01, 0x28,
152*4882a593Smuzhiyun 	0x89, 0x09,
153*4882a593Smuzhiyun 	0x04, 0x80,
154*4882a593Smuzhiyun 	0x05, 0x01,
155*4882a593Smuzhiyun 	0x06, 0x00,
156*4882a593Smuzhiyun 	0x20, 0x03,
157*4882a593Smuzhiyun 	0x24, 0x88,
158*4882a593Smuzhiyun 	0x29, 0x09,
159*4882a593Smuzhiyun 	0x2a, 0x0f,
160*4882a593Smuzhiyun 	0x2c, 0x10,
161*4882a593Smuzhiyun 	0x2d, 0x19,
162*4882a593Smuzhiyun 	0x2e, 0x08,
163*4882a593Smuzhiyun 	0x2f, 0x10,
164*4882a593Smuzhiyun 	0x30, 0x19,
165*4882a593Smuzhiyun 	0x34, 0x20,
166*4882a593Smuzhiyun 	0x35, 0x03,
167*4882a593Smuzhiyun 	0x45, 0x02,
168*4882a593Smuzhiyun 	0x46, 0x45,
169*4882a593Smuzhiyun 	0x47, 0xd0,
170*4882a593Smuzhiyun 	0x48, 0x00,
171*4882a593Smuzhiyun 	0x49, 0x40,
172*4882a593Smuzhiyun 	0x4a, 0x03,
173*4882a593Smuzhiyun 	0x4c, 0xfd,
174*4882a593Smuzhiyun 	0x4f, 0x2e,
175*4882a593Smuzhiyun 	0x50, 0x2e,
176*4882a593Smuzhiyun 	0x51, 0x10,
177*4882a593Smuzhiyun 	0x52, 0x10,
178*4882a593Smuzhiyun 	0x56, 0x92,
179*4882a593Smuzhiyun 	0x59, 0x00,
180*4882a593Smuzhiyun 	0x5a, 0x2d,
181*4882a593Smuzhiyun 	0x5b, 0x33,
182*4882a593Smuzhiyun 	0x5c, 0x1f,
183*4882a593Smuzhiyun 	0x5f, 0x76,
184*4882a593Smuzhiyun 	0x62, 0xc0,
185*4882a593Smuzhiyun 	0x63, 0xc0,
186*4882a593Smuzhiyun 	0x64, 0xf3,
187*4882a593Smuzhiyun 	0x65, 0xf3,
188*4882a593Smuzhiyun 	0x79, 0x40,
189*4882a593Smuzhiyun 	0x6a, 0x40,
190*4882a593Smuzhiyun 	0x6b, 0x0a,
191*4882a593Smuzhiyun 	0x6c, 0x80,
192*4882a593Smuzhiyun 	0x6d, 0x27,
193*4882a593Smuzhiyun 	0x71, 0x06,
194*4882a593Smuzhiyun 	0x75, 0x60,
195*4882a593Smuzhiyun 	0x78, 0x00,
196*4882a593Smuzhiyun 	0x79, 0xb5,
197*4882a593Smuzhiyun 	0x7c, 0x05,
198*4882a593Smuzhiyun 	0x7d, 0x1a,
199*4882a593Smuzhiyun 	0x87, 0x55,
200*4882a593Smuzhiyun 	0x88, 0x72,
201*4882a593Smuzhiyun 	0x8f, 0x08,
202*4882a593Smuzhiyun 	0x90, 0xe0,
203*4882a593Smuzhiyun 	0x94, 0x40,
204*4882a593Smuzhiyun 	0xa0, 0x3f,
205*4882a593Smuzhiyun 	0xa1, 0xc0,
206*4882a593Smuzhiyun 	0xa4, 0xcc,
207*4882a593Smuzhiyun 	0xa5, 0x66,
208*4882a593Smuzhiyun 	0xa6, 0x66,
209*4882a593Smuzhiyun 	0xa7, 0x7b,
210*4882a593Smuzhiyun 	0xa8, 0x7b,
211*4882a593Smuzhiyun 	0xa9, 0x7b,
212*4882a593Smuzhiyun 	0xaa, 0x9a,
213*4882a593Smuzhiyun 	0xed, 0x04,
214*4882a593Smuzhiyun 	0xad, 0x00,
215*4882a593Smuzhiyun 	0xae, 0x03,
216*4882a593Smuzhiyun 	0xcc, 0xab,
217*4882a593Smuzhiyun 	0x01, 0x08,
218*4882a593Smuzhiyun 	0xff, 0xff
219*4882a593Smuzhiyun };
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun /*	low level read/writes */
si21_writeregs(struct si21xx_state * state,u8 reg1,u8 * data,int len)222*4882a593Smuzhiyun static int si21_writeregs(struct si21xx_state *state, u8 reg1,
223*4882a593Smuzhiyun 							u8 *data, int len)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun 	int ret;
226*4882a593Smuzhiyun 	u8 buf[60];/* = { reg1, data };*/
227*4882a593Smuzhiyun 	struct i2c_msg msg = {
228*4882a593Smuzhiyun 				.addr = state->config->demod_address,
229*4882a593Smuzhiyun 				.flags = 0,
230*4882a593Smuzhiyun 				.buf = buf,
231*4882a593Smuzhiyun 				.len = len + 1
232*4882a593Smuzhiyun 	};
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	if (len > sizeof(buf) - 1)
235*4882a593Smuzhiyun 		return -EINVAL;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	msg.buf[0] =  reg1;
238*4882a593Smuzhiyun 	memcpy(msg.buf + 1, data, len);
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	ret = i2c_transfer(state->i2c, &msg, 1);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	if (ret != 1)
243*4882a593Smuzhiyun 		dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, ret == %i)\n",
244*4882a593Smuzhiyun 			__func__, reg1, data[0], ret);
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	return (ret != 1) ? -EREMOTEIO : 0;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun 
si21_writereg(struct si21xx_state * state,u8 reg,u8 data)249*4882a593Smuzhiyun static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun 	int ret;
252*4882a593Smuzhiyun 	u8 buf[] = { reg, data };
253*4882a593Smuzhiyun 	struct i2c_msg msg = {
254*4882a593Smuzhiyun 				.addr = state->config->demod_address,
255*4882a593Smuzhiyun 				.flags = 0,
256*4882a593Smuzhiyun 				.buf = buf,
257*4882a593Smuzhiyun 				.len = 2
258*4882a593Smuzhiyun 	};
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	ret = i2c_transfer(state->i2c, &msg, 1);
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	if (ret != 1)
263*4882a593Smuzhiyun 		dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, ret == %i)\n",
264*4882a593Smuzhiyun 			__func__, reg, data, ret);
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	return (ret != 1) ? -EREMOTEIO : 0;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
si21_write(struct dvb_frontend * fe,const u8 buf[],int len)269*4882a593Smuzhiyun static int si21_write(struct dvb_frontend *fe, const u8 buf[], int len)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun 	struct si21xx_state *state = fe->demodulator_priv;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	if (len != 2)
274*4882a593Smuzhiyun 		return -EINVAL;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	return si21_writereg(state, buf[0], buf[1]);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun 
si21_readreg(struct si21xx_state * state,u8 reg)279*4882a593Smuzhiyun static u8 si21_readreg(struct si21xx_state *state, u8 reg)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun 	int ret;
282*4882a593Smuzhiyun 	u8 b0[] = { reg };
283*4882a593Smuzhiyun 	u8 b1[] = { 0 };
284*4882a593Smuzhiyun 	struct i2c_msg msg[] = {
285*4882a593Smuzhiyun 		{
286*4882a593Smuzhiyun 			.addr = state->config->demod_address,
287*4882a593Smuzhiyun 			.flags = 0,
288*4882a593Smuzhiyun 			.buf = b0,
289*4882a593Smuzhiyun 			.len = 1
290*4882a593Smuzhiyun 		}, {
291*4882a593Smuzhiyun 			.addr = state->config->demod_address,
292*4882a593Smuzhiyun 			.flags = I2C_M_RD,
293*4882a593Smuzhiyun 			.buf = b1,
294*4882a593Smuzhiyun 			.len = 1
295*4882a593Smuzhiyun 		}
296*4882a593Smuzhiyun 	};
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	ret = i2c_transfer(state->i2c, msg, 2);
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	if (ret != 2)
301*4882a593Smuzhiyun 		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
302*4882a593Smuzhiyun 			__func__, reg, ret);
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	return b1[0];
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
si21_readregs(struct si21xx_state * state,u8 reg1,u8 * b,u8 len)307*4882a593Smuzhiyun static int si21_readregs(struct si21xx_state *state, u8 reg1, u8 *b, u8 len)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun 	int ret;
310*4882a593Smuzhiyun 	struct i2c_msg msg[] = {
311*4882a593Smuzhiyun 		{
312*4882a593Smuzhiyun 			.addr = state->config->demod_address,
313*4882a593Smuzhiyun 			.flags = 0,
314*4882a593Smuzhiyun 			.buf = &reg1,
315*4882a593Smuzhiyun 			.len = 1
316*4882a593Smuzhiyun 		}, {
317*4882a593Smuzhiyun 			.addr = state->config->demod_address,
318*4882a593Smuzhiyun 			.flags = I2C_M_RD,
319*4882a593Smuzhiyun 			.buf = b,
320*4882a593Smuzhiyun 			.len = len
321*4882a593Smuzhiyun 		}
322*4882a593Smuzhiyun 	};
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	ret = i2c_transfer(state->i2c, msg, 2);
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	if (ret != 2)
327*4882a593Smuzhiyun 		dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	return ret == 2 ? 0 : -1;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun 
si21xx_wait_diseqc_idle(struct si21xx_state * state,int timeout)332*4882a593Smuzhiyun static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun 	unsigned long start = jiffies;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	dprintk("%s\n", __func__);
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	while ((si21_readreg(state, LNB_CTRL_REG_1) & 0x8) == 8) {
339*4882a593Smuzhiyun 		if (jiffies - start > timeout) {
340*4882a593Smuzhiyun 			dprintk("%s: timeout!!\n", __func__);
341*4882a593Smuzhiyun 			return -ETIMEDOUT;
342*4882a593Smuzhiyun 		}
343*4882a593Smuzhiyun 		msleep(10);
344*4882a593Smuzhiyun 	}
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	return 0;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun 
si21xx_set_symbolrate(struct dvb_frontend * fe,u32 srate)349*4882a593Smuzhiyun static int si21xx_set_symbolrate(struct dvb_frontend *fe, u32 srate)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun 	struct si21xx_state *state = fe->demodulator_priv;
352*4882a593Smuzhiyun 	u32 sym_rate, data_rate;
353*4882a593Smuzhiyun 	int i;
354*4882a593Smuzhiyun 	u8 sym_rate_bytes[3];
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	dprintk("%s : srate = %i\n", __func__ , srate);
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	if ((srate < 1000000) || (srate > 45000000))
359*4882a593Smuzhiyun 		return -EINVAL;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	data_rate = srate;
362*4882a593Smuzhiyun 	sym_rate = 0;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	for (i = 0; i < 4; ++i) {
365*4882a593Smuzhiyun 		sym_rate /= 100;
366*4882a593Smuzhiyun 		sym_rate = sym_rate + ((data_rate % 100) * 0x800000) /
367*4882a593Smuzhiyun 								state->fs;
368*4882a593Smuzhiyun 		data_rate /= 100;
369*4882a593Smuzhiyun 	}
370*4882a593Smuzhiyun 	for (i = 0; i < 3; ++i)
371*4882a593Smuzhiyun 		sym_rate_bytes[i] = (u8)((sym_rate >> (i * 8)) & 0xff);
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	si21_writeregs(state, SYM_RATE_REG_L, sym_rate_bytes, 0x03);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	return 0;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun 
si21xx_send_diseqc_msg(struct dvb_frontend * fe,struct dvb_diseqc_master_cmd * m)378*4882a593Smuzhiyun static int si21xx_send_diseqc_msg(struct dvb_frontend *fe,
379*4882a593Smuzhiyun 					struct dvb_diseqc_master_cmd *m)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun 	struct si21xx_state *state = fe->demodulator_priv;
382*4882a593Smuzhiyun 	u8 lnb_status;
383*4882a593Smuzhiyun 	u8 LNB_CTRL_1;
384*4882a593Smuzhiyun 	int status;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	dprintk("%s\n", __func__);
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	status = PASS;
389*4882a593Smuzhiyun 	LNB_CTRL_1 = 0;
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	status |= si21_readregs(state, LNB_CTRL_STATUS_REG, &lnb_status, 0x01);
392*4882a593Smuzhiyun 	status |= si21_readregs(state, LNB_CTRL_REG_1, &lnb_status, 0x01);
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	/*fill the FIFO*/
395*4882a593Smuzhiyun 	status |= si21_writeregs(state, LNB_FIFO_REGS_0, m->msg, m->msg_len);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	LNB_CTRL_1 = (lnb_status & 0x70);
398*4882a593Smuzhiyun 	LNB_CTRL_1 |= m->msg_len;
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	LNB_CTRL_1 |= 0x80;	/* begin LNB signaling */
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	status |= si21_writeregs(state, LNB_CTRL_REG_1, &LNB_CTRL_1, 0x01);
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	return status;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun 
si21xx_send_diseqc_burst(struct dvb_frontend * fe,enum fe_sec_mini_cmd burst)407*4882a593Smuzhiyun static int si21xx_send_diseqc_burst(struct dvb_frontend *fe,
408*4882a593Smuzhiyun 				    enum fe_sec_mini_cmd burst)
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun 	struct si21xx_state *state = fe->demodulator_priv;
411*4882a593Smuzhiyun 	u8 val;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	dprintk("%s\n", __func__);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	if (si21xx_wait_diseqc_idle(state, 100) < 0)
416*4882a593Smuzhiyun 		return -ETIMEDOUT;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	val = (0x80 | si21_readreg(state, 0xc1));
419*4882a593Smuzhiyun 	if (si21_writereg(state, LNB_CTRL_REG_1,
420*4882a593Smuzhiyun 			burst == SEC_MINI_A ? (val & ~0x10) : (val | 0x10)))
421*4882a593Smuzhiyun 		return -EREMOTEIO;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	if (si21xx_wait_diseqc_idle(state, 100) < 0)
424*4882a593Smuzhiyun 		return -ETIMEDOUT;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	if (si21_writereg(state, LNB_CTRL_REG_1, val))
427*4882a593Smuzhiyun 		return -EREMOTEIO;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	return 0;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun /*	30.06.2008 */
si21xx_set_tone(struct dvb_frontend * fe,enum fe_sec_tone_mode tone)432*4882a593Smuzhiyun static int si21xx_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun 	struct si21xx_state *state = fe->demodulator_priv;
435*4882a593Smuzhiyun 	u8 val;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	dprintk("%s\n", __func__);
438*4882a593Smuzhiyun 	val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1));
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	switch (tone) {
441*4882a593Smuzhiyun 	case SEC_TONE_ON:
442*4882a593Smuzhiyun 		return si21_writereg(state, LNB_CTRL_REG_1, val | 0x20);
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	case SEC_TONE_OFF:
445*4882a593Smuzhiyun 		return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x20));
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	default:
448*4882a593Smuzhiyun 		return -EINVAL;
449*4882a593Smuzhiyun 	}
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun 
si21xx_set_voltage(struct dvb_frontend * fe,enum fe_sec_voltage volt)452*4882a593Smuzhiyun static int si21xx_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage volt)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun 	struct si21xx_state *state = fe->demodulator_priv;
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	u8 val;
457*4882a593Smuzhiyun 	dprintk("%s: %s\n", __func__,
458*4882a593Smuzhiyun 		volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
459*4882a593Smuzhiyun 		volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1));
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	switch (volt) {
465*4882a593Smuzhiyun 	case SEC_VOLTAGE_18:
466*4882a593Smuzhiyun 		return si21_writereg(state, LNB_CTRL_REG_1, val | 0x40);
467*4882a593Smuzhiyun 		break;
468*4882a593Smuzhiyun 	case SEC_VOLTAGE_13:
469*4882a593Smuzhiyun 		return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x40));
470*4882a593Smuzhiyun 		break;
471*4882a593Smuzhiyun 	default:
472*4882a593Smuzhiyun 		return -EINVAL;
473*4882a593Smuzhiyun 	}
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun 
si21xx_init(struct dvb_frontend * fe)476*4882a593Smuzhiyun static int si21xx_init(struct dvb_frontend *fe)
477*4882a593Smuzhiyun {
478*4882a593Smuzhiyun 	struct si21xx_state *state = fe->demodulator_priv;
479*4882a593Smuzhiyun 	int i;
480*4882a593Smuzhiyun 	int status = 0;
481*4882a593Smuzhiyun 	u8 reg1;
482*4882a593Smuzhiyun 	u8 val;
483*4882a593Smuzhiyun 	u8 reg2[2];
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	dprintk("%s\n", __func__);
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	for (i = 0; ; i += 2) {
488*4882a593Smuzhiyun 		reg1 = serit_sp1511lhb_inittab[i];
489*4882a593Smuzhiyun 		val = serit_sp1511lhb_inittab[i+1];
490*4882a593Smuzhiyun 		if (reg1 == 0xff && val == 0xff)
491*4882a593Smuzhiyun 			break;
492*4882a593Smuzhiyun 		si21_writeregs(state, reg1, &val, 1);
493*4882a593Smuzhiyun 	}
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	/*DVB QPSK SYSTEM MODE REG*/
496*4882a593Smuzhiyun 	reg1 = 0x08;
497*4882a593Smuzhiyun 	si21_writeregs(state, SYSTEM_MODE_REG, &reg1, 0x01);
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	/*transport stream config*/
500*4882a593Smuzhiyun 	/*
501*4882a593Smuzhiyun 	mode = PARALLEL;
502*4882a593Smuzhiyun 	sdata_form = LSB_FIRST;
503*4882a593Smuzhiyun 	clk_edge = FALLING_EDGE;
504*4882a593Smuzhiyun 	clk_mode = CLK_GAPPED_MODE;
505*4882a593Smuzhiyun 	strt_len = BYTE_WIDE;
506*4882a593Smuzhiyun 	sync_pol = ACTIVE_HIGH;
507*4882a593Smuzhiyun 	val_pol = ACTIVE_HIGH;
508*4882a593Smuzhiyun 	err_pol = ACTIVE_HIGH;
509*4882a593Smuzhiyun 	sclk_rate = 0x00;
510*4882a593Smuzhiyun 	parity = 0x00 ;
511*4882a593Smuzhiyun 	data_delay = 0x00;
512*4882a593Smuzhiyun 	clk_delay = 0x00;
513*4882a593Smuzhiyun 	pclk_smooth = 0x00;
514*4882a593Smuzhiyun 	*/
515*4882a593Smuzhiyun 	reg2[0] =
516*4882a593Smuzhiyun 		PARALLEL + (LSB_FIRST << 1)
517*4882a593Smuzhiyun 		+ (FALLING_EDGE << 2) + (CLK_GAPPED_MODE << 3)
518*4882a593Smuzhiyun 		+ (BYTE_WIDE << 4) + (ACTIVE_HIGH << 5)
519*4882a593Smuzhiyun 		+ (ACTIVE_HIGH << 6) + (ACTIVE_HIGH << 7);
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	reg2[1] = 0;
522*4882a593Smuzhiyun 	/*	sclk_rate + (parity << 2)
523*4882a593Smuzhiyun 		+ (data_delay << 3) + (clk_delay << 4)
524*4882a593Smuzhiyun 		+ (pclk_smooth << 5);
525*4882a593Smuzhiyun 	*/
526*4882a593Smuzhiyun 	status |= si21_writeregs(state, TS_CTRL_REG_1, reg2, 0x02);
527*4882a593Smuzhiyun 	if (status != 0)
528*4882a593Smuzhiyun 		dprintk(" %s : TS Set Error\n", __func__);
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	return 0;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun 
si21_read_status(struct dvb_frontend * fe,enum fe_status * status)534*4882a593Smuzhiyun static int si21_read_status(struct dvb_frontend *fe, enum fe_status *status)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun 	struct si21xx_state *state = fe->demodulator_priv;
537*4882a593Smuzhiyun 	u8 regs_read[2];
538*4882a593Smuzhiyun 	u8 reg_read;
539*4882a593Smuzhiyun 	u8 i;
540*4882a593Smuzhiyun 	u8 lock;
541*4882a593Smuzhiyun 	u8 signal = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG);
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	si21_readregs(state, LOCK_STATUS_REG_1, regs_read, 0x02);
544*4882a593Smuzhiyun 	reg_read = 0;
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	for (i = 0; i < 7; ++i)
547*4882a593Smuzhiyun 		reg_read |= ((regs_read[0] >> i) & 0x01) << (6 - i);
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	lock = ((reg_read & 0x7f) | (regs_read[1] & 0x80));
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, lock);
552*4882a593Smuzhiyun 	*status = 0;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	if (signal > 10)
555*4882a593Smuzhiyun 		*status |= FE_HAS_SIGNAL;
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	if (lock & 0x2)
558*4882a593Smuzhiyun 		*status |= FE_HAS_CARRIER;
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	if (lock & 0x20)
561*4882a593Smuzhiyun 		*status |= FE_HAS_VITERBI;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	if (lock & 0x40)
564*4882a593Smuzhiyun 		*status |= FE_HAS_SYNC;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	if ((lock & 0x7b) == 0x7b)
567*4882a593Smuzhiyun 		*status |= FE_HAS_LOCK;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	return 0;
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun 
si21_read_signal_strength(struct dvb_frontend * fe,u16 * strength)572*4882a593Smuzhiyun static int si21_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun 	struct si21xx_state *state = fe->demodulator_priv;
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	/*status = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG,
577*4882a593Smuzhiyun 						(u8*)agclevel, 0x01);*/
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	u16 signal = (3 * si21_readreg(state, 0x27) *
580*4882a593Smuzhiyun 					si21_readreg(state, 0x28));
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	dprintk("%s : AGCPWR: 0x%02x%02x, signal=0x%04x\n", __func__,
583*4882a593Smuzhiyun 		si21_readreg(state, 0x27),
584*4882a593Smuzhiyun 		si21_readreg(state, 0x28), (int) signal);
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	signal  <<= 4;
587*4882a593Smuzhiyun 	*strength = signal;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	return 0;
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun 
si21_read_ber(struct dvb_frontend * fe,u32 * ber)592*4882a593Smuzhiyun static int si21_read_ber(struct dvb_frontend *fe, u32 *ber)
593*4882a593Smuzhiyun {
594*4882a593Smuzhiyun 	struct si21xx_state *state = fe->demodulator_priv;
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	dprintk("%s\n", __func__);
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	if (state->errmode != STATUS_BER)
599*4882a593Smuzhiyun 		return 0;
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	*ber = (si21_readreg(state, 0x1d) << 8) |
602*4882a593Smuzhiyun 				si21_readreg(state, 0x1e);
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	return 0;
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun 
si21_read_snr(struct dvb_frontend * fe,u16 * snr)607*4882a593Smuzhiyun static int si21_read_snr(struct dvb_frontend *fe, u16 *snr)
608*4882a593Smuzhiyun {
609*4882a593Smuzhiyun 	struct si21xx_state *state = fe->demodulator_priv;
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	s32 xsnr = 0xffff - ((si21_readreg(state, 0x24) << 8) |
612*4882a593Smuzhiyun 					si21_readreg(state, 0x25));
613*4882a593Smuzhiyun 	xsnr = 3 * (xsnr - 0xa100);
614*4882a593Smuzhiyun 	*snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	dprintk("%s\n", __func__);
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	return 0;
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun 
si21_read_ucblocks(struct dvb_frontend * fe,u32 * ucblocks)621*4882a593Smuzhiyun static int si21_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun 	struct si21xx_state *state = fe->demodulator_priv;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	dprintk("%s\n", __func__);
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 	if (state->errmode != STATUS_UCBLOCKS)
628*4882a593Smuzhiyun 		*ucblocks = 0;
629*4882a593Smuzhiyun 	else
630*4882a593Smuzhiyun 		*ucblocks = (si21_readreg(state, 0x1d) << 8) |
631*4882a593Smuzhiyun 					si21_readreg(state, 0x1e);
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	return 0;
634*4882a593Smuzhiyun }
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun /*	initiates a channel acquisition sequence
637*4882a593Smuzhiyun 	using the specified symbol rate and code rate */
si21xx_setacquire(struct dvb_frontend * fe,int symbrate,enum fe_code_rate crate)638*4882a593Smuzhiyun static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate,
639*4882a593Smuzhiyun 			     enum fe_code_rate crate)
640*4882a593Smuzhiyun {
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	struct si21xx_state *state = fe->demodulator_priv;
643*4882a593Smuzhiyun 	u8 coderates[] = {
644*4882a593Smuzhiyun 				0x0, 0x01, 0x02, 0x04, 0x00,
645*4882a593Smuzhiyun 				0x8, 0x10, 0x20, 0x00, 0x3f
646*4882a593Smuzhiyun 	};
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	u8 coderate_ptr;
649*4882a593Smuzhiyun 	int status;
650*4882a593Smuzhiyun 	u8 start_acq = 0x80;
651*4882a593Smuzhiyun 	u8 reg, regs[3];
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	dprintk("%s\n", __func__);
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	status = PASS;
656*4882a593Smuzhiyun 	coderate_ptr = coderates[crate];
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	si21xx_set_symbolrate(fe, symbrate);
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	/* write code rates to use in the Viterbi search */
661*4882a593Smuzhiyun 	status |= si21_writeregs(state,
662*4882a593Smuzhiyun 				VIT_SRCH_CTRL_REG_1,
663*4882a593Smuzhiyun 				&coderate_ptr, 0x01);
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 	/* clear acq_start bit */
666*4882a593Smuzhiyun 	status |= si21_readregs(state, ACQ_CTRL_REG_2, &reg, 0x01);
667*4882a593Smuzhiyun 	reg &= ~start_acq;
668*4882a593Smuzhiyun 	status |= si21_writeregs(state, ACQ_CTRL_REG_2, &reg, 0x01);
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 	/* use new Carrier Frequency Offset Estimator (QuickLock) */
671*4882a593Smuzhiyun 	regs[0] = 0xCB;
672*4882a593Smuzhiyun 	regs[1] = 0x40;
673*4882a593Smuzhiyun 	regs[2] = 0xCB;
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 	status |= si21_writeregs(state,
676*4882a593Smuzhiyun 				TWO_DB_BNDWDTH_THRSHLD_REG,
677*4882a593Smuzhiyun 				&regs[0], 0x03);
678*4882a593Smuzhiyun 	reg = 0x56;
679*4882a593Smuzhiyun 	status |= si21_writeregs(state,
680*4882a593Smuzhiyun 				LSA_CTRL_REG_1, &reg, 1);
681*4882a593Smuzhiyun 	reg = 0x05;
682*4882a593Smuzhiyun 	status |= si21_writeregs(state,
683*4882a593Smuzhiyun 				BLIND_SCAN_CTRL_REG, &reg, 1);
684*4882a593Smuzhiyun 	/* start automatic acq */
685*4882a593Smuzhiyun 	status |= si21_writeregs(state,
686*4882a593Smuzhiyun 				ACQ_CTRL_REG_2, &start_acq, 0x01);
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	return status;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun 
si21xx_set_frontend(struct dvb_frontend * fe)691*4882a593Smuzhiyun static int si21xx_set_frontend(struct dvb_frontend *fe)
692*4882a593Smuzhiyun {
693*4882a593Smuzhiyun 	struct si21xx_state *state = fe->demodulator_priv;
694*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	/* freq		Channel carrier frequency in KHz (i.e. 1550000 KHz)
697*4882a593Smuzhiyun 	 datarate	Channel symbol rate in Sps (i.e. 22500000 Sps)*/
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	/* in MHz */
700*4882a593Smuzhiyun 	unsigned char coarse_tune_freq;
701*4882a593Smuzhiyun 	int fine_tune_freq;
702*4882a593Smuzhiyun 	unsigned char sample_rate = 0;
703*4882a593Smuzhiyun 	/* boolean */
704*4882a593Smuzhiyun 	bool inband_interferer_ind;
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun 	/* INTERMEDIATE VALUES */
707*4882a593Smuzhiyun 	int icoarse_tune_freq; /* MHz */
708*4882a593Smuzhiyun 	int ifine_tune_freq; /* MHz */
709*4882a593Smuzhiyun 	unsigned int band_high;
710*4882a593Smuzhiyun 	unsigned int band_low;
711*4882a593Smuzhiyun 	unsigned int x1;
712*4882a593Smuzhiyun 	unsigned int x2;
713*4882a593Smuzhiyun 	int i;
714*4882a593Smuzhiyun 	bool inband_interferer_div2[ALLOWABLE_FS_COUNT];
715*4882a593Smuzhiyun 	bool inband_interferer_div4[ALLOWABLE_FS_COUNT];
716*4882a593Smuzhiyun 	int status;
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	/* allowable sample rates for ADC in MHz */
719*4882a593Smuzhiyun 	int afs[ALLOWABLE_FS_COUNT] = { 200, 192, 193, 194, 195,
720*4882a593Smuzhiyun 					196, 204, 205, 206, 207
721*4882a593Smuzhiyun 	};
722*4882a593Smuzhiyun 	/* in MHz */
723*4882a593Smuzhiyun 	int if_limit_high;
724*4882a593Smuzhiyun 	int if_limit_low;
725*4882a593Smuzhiyun 	int lnb_lo;
726*4882a593Smuzhiyun 	int lnb_uncertanity;
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	int rf_freq;
729*4882a593Smuzhiyun 	int data_rate;
730*4882a593Smuzhiyun 	unsigned char regs[4];
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun 	dprintk("%s : FE_SET_FRONTEND\n", __func__);
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	if (c->delivery_system != SYS_DVBS) {
735*4882a593Smuzhiyun 			dprintk("%s: unsupported delivery system selected (%d)\n",
736*4882a593Smuzhiyun 				__func__, c->delivery_system);
737*4882a593Smuzhiyun 			return -EOPNOTSUPP;
738*4882a593Smuzhiyun 	}
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
741*4882a593Smuzhiyun 		inband_interferer_div2[i] = inband_interferer_div4[i] = false;
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	if_limit_high = -700000;
744*4882a593Smuzhiyun 	if_limit_low = -100000;
745*4882a593Smuzhiyun 	/* in MHz */
746*4882a593Smuzhiyun 	lnb_lo = 0;
747*4882a593Smuzhiyun 	lnb_uncertanity = 0;
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	rf_freq = 10 * c->frequency ;
750*4882a593Smuzhiyun 	data_rate = c->symbol_rate / 100;
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	status = PASS;
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	band_low = (rf_freq - lnb_lo) - ((lnb_uncertanity * 200)
755*4882a593Smuzhiyun 					+ (data_rate * 135)) / 200;
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	band_high = (rf_freq - lnb_lo) + ((lnb_uncertanity * 200)
758*4882a593Smuzhiyun 					+ (data_rate * 135)) / 200;
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 	icoarse_tune_freq = 100000 *
762*4882a593Smuzhiyun 				(((rf_freq - lnb_lo) -
763*4882a593Smuzhiyun 					(if_limit_low + if_limit_high) / 2)
764*4882a593Smuzhiyun 								/ 100000);
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	ifine_tune_freq = (rf_freq - lnb_lo) - icoarse_tune_freq ;
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
769*4882a593Smuzhiyun 		x1 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) *
770*4882a593Smuzhiyun 					(afs[i] * 2500) + afs[i] * 2500;
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 		x2 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) *
773*4882a593Smuzhiyun 							(afs[i] * 2500);
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 		if (((band_low < x1) && (x1 < band_high)) ||
776*4882a593Smuzhiyun 					((band_low < x2) && (x2 < band_high)))
777*4882a593Smuzhiyun 					inband_interferer_div4[i] = true;
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	}
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
782*4882a593Smuzhiyun 		x1 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) *
783*4882a593Smuzhiyun 					(afs[i] * 5000) + afs[i] * 5000;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 		x2 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) *
786*4882a593Smuzhiyun 					(afs[i] * 5000);
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 		if (((band_low < x1) && (x1 < band_high)) ||
789*4882a593Smuzhiyun 					((band_low < x2) && (x2 < band_high)))
790*4882a593Smuzhiyun 					inband_interferer_div2[i] = true;
791*4882a593Smuzhiyun 	}
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 	inband_interferer_ind = true;
794*4882a593Smuzhiyun 	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
795*4882a593Smuzhiyun 		if (inband_interferer_div2[i] || inband_interferer_div4[i]) {
796*4882a593Smuzhiyun 			inband_interferer_ind = false;
797*4882a593Smuzhiyun 			break;
798*4882a593Smuzhiyun 		}
799*4882a593Smuzhiyun 	}
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 	if (inband_interferer_ind) {
802*4882a593Smuzhiyun 		for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
803*4882a593Smuzhiyun 			if (!inband_interferer_div2[i]) {
804*4882a593Smuzhiyun 				sample_rate = (u8) afs[i];
805*4882a593Smuzhiyun 				break;
806*4882a593Smuzhiyun 			}
807*4882a593Smuzhiyun 		}
808*4882a593Smuzhiyun 	} else {
809*4882a593Smuzhiyun 		for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
810*4882a593Smuzhiyun 			if ((inband_interferer_div2[i] ||
811*4882a593Smuzhiyun 			     !inband_interferer_div4[i])) {
812*4882a593Smuzhiyun 				sample_rate = (u8) afs[i];
813*4882a593Smuzhiyun 				break;
814*4882a593Smuzhiyun 			}
815*4882a593Smuzhiyun 		}
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 	}
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	if (sample_rate > 207 || sample_rate < 192)
820*4882a593Smuzhiyun 		sample_rate = 200;
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun 	fine_tune_freq = ((0x4000 * (ifine_tune_freq / 10)) /
823*4882a593Smuzhiyun 					((sample_rate) * 1000));
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun 	coarse_tune_freq = (u8)(icoarse_tune_freq / 100000);
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun 	regs[0] = sample_rate;
828*4882a593Smuzhiyun 	regs[1] = coarse_tune_freq;
829*4882a593Smuzhiyun 	regs[2] = fine_tune_freq & 0xFF;
830*4882a593Smuzhiyun 	regs[3] = fine_tune_freq >> 8 & 0xFF;
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun 	status |= si21_writeregs(state, PLL_DIVISOR_REG, &regs[0], 0x04);
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 	state->fs = sample_rate;/*ADC MHz*/
835*4882a593Smuzhiyun 	si21xx_setacquire(fe, c->symbol_rate, c->fec_inner);
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	return 0;
838*4882a593Smuzhiyun }
839*4882a593Smuzhiyun 
si21xx_sleep(struct dvb_frontend * fe)840*4882a593Smuzhiyun static int si21xx_sleep(struct dvb_frontend *fe)
841*4882a593Smuzhiyun {
842*4882a593Smuzhiyun 	struct si21xx_state *state = fe->demodulator_priv;
843*4882a593Smuzhiyun 	u8 regdata;
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 	dprintk("%s\n", __func__);
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 	si21_readregs(state, SYSTEM_MODE_REG, &regdata, 0x01);
848*4882a593Smuzhiyun 	regdata |= 1 << 6;
849*4882a593Smuzhiyun 	si21_writeregs(state, SYSTEM_MODE_REG, &regdata, 0x01);
850*4882a593Smuzhiyun 	state->initialised = 0;
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 	return 0;
853*4882a593Smuzhiyun }
854*4882a593Smuzhiyun 
si21xx_release(struct dvb_frontend * fe)855*4882a593Smuzhiyun static void si21xx_release(struct dvb_frontend *fe)
856*4882a593Smuzhiyun {
857*4882a593Smuzhiyun 	struct si21xx_state *state = fe->demodulator_priv;
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun 	dprintk("%s\n", __func__);
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 	kfree(state);
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun static const struct dvb_frontend_ops si21xx_ops = {
865*4882a593Smuzhiyun 	.delsys = { SYS_DVBS },
866*4882a593Smuzhiyun 	.info = {
867*4882a593Smuzhiyun 		.name			= "SL SI21XX DVB-S",
868*4882a593Smuzhiyun 		.frequency_min_hz	=  950 * MHz,
869*4882a593Smuzhiyun 		.frequency_max_hz	= 2150 * MHz,
870*4882a593Smuzhiyun 		.frequency_stepsize_hz	=  125 * kHz,
871*4882a593Smuzhiyun 		.symbol_rate_min	= 1000000,
872*4882a593Smuzhiyun 		.symbol_rate_max	= 45000000,
873*4882a593Smuzhiyun 		.symbol_rate_tolerance	= 500,	/* ppm */
874*4882a593Smuzhiyun 		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
875*4882a593Smuzhiyun 		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
876*4882a593Smuzhiyun 		FE_CAN_QPSK |
877*4882a593Smuzhiyun 		FE_CAN_FEC_AUTO
878*4882a593Smuzhiyun 	},
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun 	.release = si21xx_release,
881*4882a593Smuzhiyun 	.init = si21xx_init,
882*4882a593Smuzhiyun 	.sleep = si21xx_sleep,
883*4882a593Smuzhiyun 	.write = si21_write,
884*4882a593Smuzhiyun 	.read_status = si21_read_status,
885*4882a593Smuzhiyun 	.read_ber = si21_read_ber,
886*4882a593Smuzhiyun 	.read_signal_strength = si21_read_signal_strength,
887*4882a593Smuzhiyun 	.read_snr = si21_read_snr,
888*4882a593Smuzhiyun 	.read_ucblocks = si21_read_ucblocks,
889*4882a593Smuzhiyun 	.diseqc_send_master_cmd = si21xx_send_diseqc_msg,
890*4882a593Smuzhiyun 	.diseqc_send_burst = si21xx_send_diseqc_burst,
891*4882a593Smuzhiyun 	.set_tone = si21xx_set_tone,
892*4882a593Smuzhiyun 	.set_voltage = si21xx_set_voltage,
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun 	.set_frontend = si21xx_set_frontend,
895*4882a593Smuzhiyun };
896*4882a593Smuzhiyun 
si21xx_attach(const struct si21xx_config * config,struct i2c_adapter * i2c)897*4882a593Smuzhiyun struct dvb_frontend *si21xx_attach(const struct si21xx_config *config,
898*4882a593Smuzhiyun 						struct i2c_adapter *i2c)
899*4882a593Smuzhiyun {
900*4882a593Smuzhiyun 	struct si21xx_state *state = NULL;
901*4882a593Smuzhiyun 	int id;
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun 	dprintk("%s\n", __func__);
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun 	/* allocate memory for the internal state */
906*4882a593Smuzhiyun 	state = kzalloc(sizeof(struct si21xx_state), GFP_KERNEL);
907*4882a593Smuzhiyun 	if (state == NULL)
908*4882a593Smuzhiyun 		goto error;
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 	/* setup the state */
911*4882a593Smuzhiyun 	state->config = config;
912*4882a593Smuzhiyun 	state->i2c = i2c;
913*4882a593Smuzhiyun 	state->initialised = 0;
914*4882a593Smuzhiyun 	state->errmode = STATUS_BER;
915*4882a593Smuzhiyun 
916*4882a593Smuzhiyun 	/* check if the demod is there */
917*4882a593Smuzhiyun 	id = si21_readreg(state, SYSTEM_MODE_REG);
918*4882a593Smuzhiyun 	si21_writereg(state, SYSTEM_MODE_REG, id | 0x40); /* standby off */
919*4882a593Smuzhiyun 	msleep(200);
920*4882a593Smuzhiyun 	id = si21_readreg(state, 0x00);
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 	/* register 0x00 contains:
923*4882a593Smuzhiyun 		0x34 for SI2107
924*4882a593Smuzhiyun 		0x24 for SI2108
925*4882a593Smuzhiyun 		0x14 for SI2109
926*4882a593Smuzhiyun 		0x04 for SI2110
927*4882a593Smuzhiyun 	*/
928*4882a593Smuzhiyun 	if (id != 0x04 && id != 0x14)
929*4882a593Smuzhiyun 		goto error;
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 	/* create dvb_frontend */
932*4882a593Smuzhiyun 	memcpy(&state->frontend.ops, &si21xx_ops,
933*4882a593Smuzhiyun 					sizeof(struct dvb_frontend_ops));
934*4882a593Smuzhiyun 	state->frontend.demodulator_priv = state;
935*4882a593Smuzhiyun 	return &state->frontend;
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun error:
938*4882a593Smuzhiyun 	kfree(state);
939*4882a593Smuzhiyun 	return NULL;
940*4882a593Smuzhiyun }
941*4882a593Smuzhiyun EXPORT_SYMBOL(si21xx_attach);
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun module_param(debug, int, 0644);
944*4882a593Smuzhiyun MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun MODULE_DESCRIPTION("SL SI21XX DVB Demodulator driver");
947*4882a593Smuzhiyun MODULE_AUTHOR("Igor M. Liplianin");
948*4882a593Smuzhiyun MODULE_LICENSE("GPL");
949