xref: /OK3568_Linux_fs/kernel/drivers/media/dvb-frontends/dib8000.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Linux-DVB Driver for DiBcom's DiB8000 chip (ISDB-T).
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2009 DiBcom (http://www.dibcom.fr/)
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/i2c.h>
13*4882a593Smuzhiyun #include <linux/mutex.h>
14*4882a593Smuzhiyun #include <asm/div64.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <media/dvb_math.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <media/dvb_frontend.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include "dib8000.h"
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define LAYER_ALL -1
23*4882a593Smuzhiyun #define LAYER_A   1
24*4882a593Smuzhiyun #define LAYER_B   2
25*4882a593Smuzhiyun #define LAYER_C   3
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #define MAX_NUMBER_OF_FRONTENDS 6
28*4882a593Smuzhiyun /* #define DIB8000_AGC_FREEZE */
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun static int debug;
31*4882a593Smuzhiyun module_param(debug, int, 0644);
32*4882a593Smuzhiyun MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #define dprintk(fmt, arg...) do {					\
35*4882a593Smuzhiyun 	if (debug)							\
36*4882a593Smuzhiyun 		printk(KERN_DEBUG pr_fmt("%s: " fmt),			\
37*4882a593Smuzhiyun 		       __func__, ##arg);				\
38*4882a593Smuzhiyun } while (0)
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun struct i2c_device {
41*4882a593Smuzhiyun 	struct i2c_adapter *adap;
42*4882a593Smuzhiyun 	u8 addr;
43*4882a593Smuzhiyun 	u8 *i2c_write_buffer;
44*4882a593Smuzhiyun 	u8 *i2c_read_buffer;
45*4882a593Smuzhiyun 	struct mutex *i2c_buffer_lock;
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun enum param_loop_step {
49*4882a593Smuzhiyun 	LOOP_TUNE_1,
50*4882a593Smuzhiyun 	LOOP_TUNE_2
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun enum dib8000_autosearch_step {
54*4882a593Smuzhiyun 	AS_START = 0,
55*4882a593Smuzhiyun 	AS_SEARCHING_FFT,
56*4882a593Smuzhiyun 	AS_SEARCHING_GUARD,
57*4882a593Smuzhiyun 	AS_DONE = 100,
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun enum timeout_mode {
61*4882a593Smuzhiyun 	SYMBOL_DEPENDENT_OFF = 0,
62*4882a593Smuzhiyun 	SYMBOL_DEPENDENT_ON,
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun struct dib8000_state {
66*4882a593Smuzhiyun 	struct dib8000_config cfg;
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	struct i2c_device i2c;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	struct dibx000_i2c_master i2c_master;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	u16 wbd_ref;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	u8 current_band;
75*4882a593Smuzhiyun 	u32 current_bandwidth;
76*4882a593Smuzhiyun 	struct dibx000_agc_config *current_agc;
77*4882a593Smuzhiyun 	u32 timf;
78*4882a593Smuzhiyun 	u32 timf_default;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	u8 div_force_off:1;
81*4882a593Smuzhiyun 	u8 div_state:1;
82*4882a593Smuzhiyun 	u16 div_sync_wait;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	u8 agc_state;
85*4882a593Smuzhiyun 	u8 differential_constellation;
86*4882a593Smuzhiyun 	u8 diversity_onoff;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	s16 ber_monitored_layer;
89*4882a593Smuzhiyun 	u16 gpio_dir;
90*4882a593Smuzhiyun 	u16 gpio_val;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	u16 revision;
93*4882a593Smuzhiyun 	u8 isdbt_cfg_loaded;
94*4882a593Smuzhiyun 	enum frontend_tune_state tune_state;
95*4882a593Smuzhiyun 	s32 status;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	/* for the I2C transfer */
100*4882a593Smuzhiyun 	struct i2c_msg msg[2];
101*4882a593Smuzhiyun 	u8 i2c_write_buffer[4];
102*4882a593Smuzhiyun 	u8 i2c_read_buffer[2];
103*4882a593Smuzhiyun 	struct mutex i2c_buffer_lock;
104*4882a593Smuzhiyun 	u8 input_mode_mpeg;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	u16 tuner_enable;
107*4882a593Smuzhiyun 	struct i2c_adapter dib8096p_tuner_adap;
108*4882a593Smuzhiyun 	u16 current_demod_bw;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	u16 seg_mask;
111*4882a593Smuzhiyun 	u16 seg_diff_mask;
112*4882a593Smuzhiyun 	u16 mode;
113*4882a593Smuzhiyun 	u8 layer_b_nb_seg;
114*4882a593Smuzhiyun 	u8 layer_c_nb_seg;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	u8 channel_parameters_set;
117*4882a593Smuzhiyun 	u16 autosearch_state;
118*4882a593Smuzhiyun 	u16 found_nfft;
119*4882a593Smuzhiyun 	u16 found_guard;
120*4882a593Smuzhiyun 	u8 subchannel;
121*4882a593Smuzhiyun 	u8 symbol_duration;
122*4882a593Smuzhiyun 	unsigned long timeout;
123*4882a593Smuzhiyun 	u8 longest_intlv_layer;
124*4882a593Smuzhiyun 	u16 output_mode;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	/* for DVBv5 stats */
127*4882a593Smuzhiyun 	s64 init_ucb;
128*4882a593Smuzhiyun 	unsigned long per_jiffies_stats;
129*4882a593Smuzhiyun 	unsigned long ber_jiffies_stats;
130*4882a593Smuzhiyun 	unsigned long ber_jiffies_stats_layer[3];
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun #ifdef DIB8000_AGC_FREEZE
133*4882a593Smuzhiyun 	u16 agc1_max;
134*4882a593Smuzhiyun 	u16 agc1_min;
135*4882a593Smuzhiyun 	u16 agc2_max;
136*4882a593Smuzhiyun 	u16 agc2_min;
137*4882a593Smuzhiyun #endif
138*4882a593Smuzhiyun };
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun enum dib8000_power_mode {
141*4882a593Smuzhiyun 	DIB8000_POWER_ALL = 0,
142*4882a593Smuzhiyun 	DIB8000_POWER_INTERFACE_ONLY,
143*4882a593Smuzhiyun };
144*4882a593Smuzhiyun 
dib8000_i2c_read16(struct i2c_device * i2c,u16 reg)145*4882a593Smuzhiyun static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	u16 ret;
148*4882a593Smuzhiyun 	struct i2c_msg msg[2] = {
149*4882a593Smuzhiyun 		{.addr = i2c->addr >> 1, .flags = 0, .len = 2},
150*4882a593Smuzhiyun 		{.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
151*4882a593Smuzhiyun 	};
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
154*4882a593Smuzhiyun 		dprintk("could not acquire lock\n");
155*4882a593Smuzhiyun 		return 0;
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	msg[0].buf    = i2c->i2c_write_buffer;
159*4882a593Smuzhiyun 	msg[0].buf[0] = reg >> 8;
160*4882a593Smuzhiyun 	msg[0].buf[1] = reg & 0xff;
161*4882a593Smuzhiyun 	msg[1].buf    = i2c->i2c_read_buffer;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	if (i2c_transfer(i2c->adap, msg, 2) != 2)
164*4882a593Smuzhiyun 		dprintk("i2c read error on %d\n", reg);
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
167*4882a593Smuzhiyun 	mutex_unlock(i2c->i2c_buffer_lock);
168*4882a593Smuzhiyun 	return ret;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun 
__dib8000_read_word(struct dib8000_state * state,u16 reg)171*4882a593Smuzhiyun static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun 	u16 ret;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	state->i2c_write_buffer[0] = reg >> 8;
176*4882a593Smuzhiyun 	state->i2c_write_buffer[1] = reg & 0xff;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
179*4882a593Smuzhiyun 	state->msg[0].addr = state->i2c.addr >> 1;
180*4882a593Smuzhiyun 	state->msg[0].flags = 0;
181*4882a593Smuzhiyun 	state->msg[0].buf = state->i2c_write_buffer;
182*4882a593Smuzhiyun 	state->msg[0].len = 2;
183*4882a593Smuzhiyun 	state->msg[1].addr = state->i2c.addr >> 1;
184*4882a593Smuzhiyun 	state->msg[1].flags = I2C_M_RD;
185*4882a593Smuzhiyun 	state->msg[1].buf = state->i2c_read_buffer;
186*4882a593Smuzhiyun 	state->msg[1].len = 2;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
189*4882a593Smuzhiyun 		dprintk("i2c read error on %d\n", reg);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	return ret;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun 
dib8000_read_word(struct dib8000_state * state,u16 reg)196*4882a593Smuzhiyun static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun 	u16 ret;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
201*4882a593Smuzhiyun 		dprintk("could not acquire lock\n");
202*4882a593Smuzhiyun 		return 0;
203*4882a593Smuzhiyun 	}
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	ret = __dib8000_read_word(state, reg);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	mutex_unlock(&state->i2c_buffer_lock);
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	return ret;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun 
dib8000_read32(struct dib8000_state * state,u16 reg)212*4882a593Smuzhiyun static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun 	u16 rw[2];
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
217*4882a593Smuzhiyun 		dprintk("could not acquire lock\n");
218*4882a593Smuzhiyun 		return 0;
219*4882a593Smuzhiyun 	}
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	rw[0] = __dib8000_read_word(state, reg + 0);
222*4882a593Smuzhiyun 	rw[1] = __dib8000_read_word(state, reg + 1);
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	mutex_unlock(&state->i2c_buffer_lock);
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	return ((rw[0] << 16) | (rw[1]));
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun 
dib8000_i2c_write16(struct i2c_device * i2c,u16 reg,u16 val)229*4882a593Smuzhiyun static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun 	struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
232*4882a593Smuzhiyun 	int ret = 0;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
235*4882a593Smuzhiyun 		dprintk("could not acquire lock\n");
236*4882a593Smuzhiyun 		return -EINVAL;
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	msg.buf    = i2c->i2c_write_buffer;
240*4882a593Smuzhiyun 	msg.buf[0] = (reg >> 8) & 0xff;
241*4882a593Smuzhiyun 	msg.buf[1] = reg & 0xff;
242*4882a593Smuzhiyun 	msg.buf[2] = (val >> 8) & 0xff;
243*4882a593Smuzhiyun 	msg.buf[3] = val & 0xff;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
246*4882a593Smuzhiyun 	mutex_unlock(i2c->i2c_buffer_lock);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	return ret;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun 
dib8000_write_word(struct dib8000_state * state,u16 reg,u16 val)251*4882a593Smuzhiyun static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun 	int ret;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
256*4882a593Smuzhiyun 		dprintk("could not acquire lock\n");
257*4882a593Smuzhiyun 		return -EINVAL;
258*4882a593Smuzhiyun 	}
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
261*4882a593Smuzhiyun 	state->i2c_write_buffer[1] = reg & 0xff;
262*4882a593Smuzhiyun 	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
263*4882a593Smuzhiyun 	state->i2c_write_buffer[3] = val & 0xff;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
266*4882a593Smuzhiyun 	state->msg[0].addr = state->i2c.addr >> 1;
267*4882a593Smuzhiyun 	state->msg[0].flags = 0;
268*4882a593Smuzhiyun 	state->msg[0].buf = state->i2c_write_buffer;
269*4882a593Smuzhiyun 	state->msg[0].len = 4;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
272*4882a593Smuzhiyun 			-EREMOTEIO : 0);
273*4882a593Smuzhiyun 	mutex_unlock(&state->i2c_buffer_lock);
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	return ret;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
279*4882a593Smuzhiyun 	(769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c,
280*4882a593Smuzhiyun 		(920 << 5) | 0x09
281*4882a593Smuzhiyun };
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun static const s16 coeff_2k_sb_1seg[8] = {
284*4882a593Smuzhiyun 	(692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
285*4882a593Smuzhiyun };
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
288*4882a593Smuzhiyun 	(832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11,
289*4882a593Smuzhiyun 		(-931 << 5) | 0x0f
290*4882a593Smuzhiyun };
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
293*4882a593Smuzhiyun 	(622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e,
294*4882a593Smuzhiyun 		(982 << 5) | 0x0c
295*4882a593Smuzhiyun };
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
298*4882a593Smuzhiyun 	(699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12,
299*4882a593Smuzhiyun 		(-720 << 5) | 0x0d
300*4882a593Smuzhiyun };
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun static const s16 coeff_2k_sb_3seg[8] = {
303*4882a593Smuzhiyun 	(664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e,
304*4882a593Smuzhiyun 		(-610 << 5) | 0x0a
305*4882a593Smuzhiyun };
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
308*4882a593Smuzhiyun 	(-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f,
309*4882a593Smuzhiyun 		(-922 << 5) | 0x0d
310*4882a593Smuzhiyun };
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun static const s16 coeff_4k_sb_1seg[8] = {
313*4882a593Smuzhiyun 	(638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d,
314*4882a593Smuzhiyun 		(-655 << 5) | 0x0a
315*4882a593Smuzhiyun };
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
318*4882a593Smuzhiyun 	(-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14,
319*4882a593Smuzhiyun 		(-958 << 5) | 0x13
320*4882a593Smuzhiyun };
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
323*4882a593Smuzhiyun 	(-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12,
324*4882a593Smuzhiyun 		(-568 << 5) | 0x0f
325*4882a593Smuzhiyun };
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
328*4882a593Smuzhiyun 	(-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14,
329*4882a593Smuzhiyun 		(-848 << 5) | 0x13
330*4882a593Smuzhiyun };
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun static const s16 coeff_4k_sb_3seg[8] = {
333*4882a593Smuzhiyun 	(612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12,
334*4882a593Smuzhiyun 		(-869 << 5) | 0x13
335*4882a593Smuzhiyun };
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
338*4882a593Smuzhiyun 	(-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13,
339*4882a593Smuzhiyun 		(-598 << 5) | 0x10
340*4882a593Smuzhiyun };
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun static const s16 coeff_8k_sb_1seg[8] = {
343*4882a593Smuzhiyun 	(673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f,
344*4882a593Smuzhiyun 		(585 << 5) | 0x0f
345*4882a593Smuzhiyun };
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
348*4882a593Smuzhiyun 	(863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18,
349*4882a593Smuzhiyun 		(0 << 5) | 0x14
350*4882a593Smuzhiyun };
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
353*4882a593Smuzhiyun 	(-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15,
354*4882a593Smuzhiyun 		(-877 << 5) | 0x15
355*4882a593Smuzhiyun };
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
358*4882a593Smuzhiyun 	(-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18,
359*4882a593Smuzhiyun 		(-921 << 5) | 0x14
360*4882a593Smuzhiyun };
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun static const s16 coeff_8k_sb_3seg[8] = {
363*4882a593Smuzhiyun 	(514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15,
364*4882a593Smuzhiyun 		(690 << 5) | 0x14
365*4882a593Smuzhiyun };
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun static const s16 ana_fe_coeff_3seg[24] = {
368*4882a593Smuzhiyun 	81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017
369*4882a593Smuzhiyun };
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun static const s16 ana_fe_coeff_1seg[24] = {
372*4882a593Smuzhiyun 	249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003
373*4882a593Smuzhiyun };
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun static const s16 ana_fe_coeff_13seg[24] = {
376*4882a593Smuzhiyun 	396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1
377*4882a593Smuzhiyun };
378*4882a593Smuzhiyun 
fft_to_mode(struct dib8000_state * state)379*4882a593Smuzhiyun static u16 fft_to_mode(struct dib8000_state *state)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun 	u16 mode;
382*4882a593Smuzhiyun 	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
383*4882a593Smuzhiyun 	case TRANSMISSION_MODE_2K:
384*4882a593Smuzhiyun 		mode = 1;
385*4882a593Smuzhiyun 		break;
386*4882a593Smuzhiyun 	case TRANSMISSION_MODE_4K:
387*4882a593Smuzhiyun 		mode = 2;
388*4882a593Smuzhiyun 		break;
389*4882a593Smuzhiyun 	default:
390*4882a593Smuzhiyun 	case TRANSMISSION_MODE_AUTO:
391*4882a593Smuzhiyun 	case TRANSMISSION_MODE_8K:
392*4882a593Smuzhiyun 		mode = 3;
393*4882a593Smuzhiyun 		break;
394*4882a593Smuzhiyun 	}
395*4882a593Smuzhiyun 	return mode;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun 
dib8000_set_acquisition_mode(struct dib8000_state * state)398*4882a593Smuzhiyun static void dib8000_set_acquisition_mode(struct dib8000_state *state)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun 	u16 nud = dib8000_read_word(state, 298);
401*4882a593Smuzhiyun 	nud |= (1 << 3) | (1 << 0);
402*4882a593Smuzhiyun 	dprintk("acquisition mode activated\n");
403*4882a593Smuzhiyun 	dib8000_write_word(state, 298, nud);
404*4882a593Smuzhiyun }
dib8000_set_output_mode(struct dvb_frontend * fe,int mode)405*4882a593Smuzhiyun static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
408*4882a593Smuzhiyun 	u16 outreg, fifo_threshold, smo_mode, sram = 0x0205;	/* by default SDRAM deintlv is enabled */
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	state->output_mode = mode;
411*4882a593Smuzhiyun 	outreg = 0;
412*4882a593Smuzhiyun 	fifo_threshold = 1792;
413*4882a593Smuzhiyun 	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	dprintk("-I-	Setting output mode for demod %p to %d\n",
416*4882a593Smuzhiyun 			&state->fe[0], mode);
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	switch (mode) {
419*4882a593Smuzhiyun 	case OUTMODE_MPEG2_PAR_GATED_CLK:	// STBs with parallel gated clock
420*4882a593Smuzhiyun 		outreg = (1 << 10);	/* 0x0400 */
421*4882a593Smuzhiyun 		break;
422*4882a593Smuzhiyun 	case OUTMODE_MPEG2_PAR_CONT_CLK:	// STBs with parallel continues clock
423*4882a593Smuzhiyun 		outreg = (1 << 10) | (1 << 6);	/* 0x0440 */
424*4882a593Smuzhiyun 		break;
425*4882a593Smuzhiyun 	case OUTMODE_MPEG2_SERIAL:	// STBs with serial input
426*4882a593Smuzhiyun 		outreg = (1 << 10) | (2 << 6) | (0 << 1);	/* 0x0482 */
427*4882a593Smuzhiyun 		break;
428*4882a593Smuzhiyun 	case OUTMODE_DIVERSITY:
429*4882a593Smuzhiyun 		if (state->cfg.hostbus_diversity) {
430*4882a593Smuzhiyun 			outreg = (1 << 10) | (4 << 6);	/* 0x0500 */
431*4882a593Smuzhiyun 			sram &= 0xfdff;
432*4882a593Smuzhiyun 		} else
433*4882a593Smuzhiyun 			sram |= 0x0c00;
434*4882a593Smuzhiyun 		break;
435*4882a593Smuzhiyun 	case OUTMODE_MPEG2_FIFO:	// e.g. USB feeding
436*4882a593Smuzhiyun 		smo_mode |= (3 << 1);
437*4882a593Smuzhiyun 		fifo_threshold = 512;
438*4882a593Smuzhiyun 		outreg = (1 << 10) | (5 << 6);
439*4882a593Smuzhiyun 		break;
440*4882a593Smuzhiyun 	case OUTMODE_HIGH_Z:	// disable
441*4882a593Smuzhiyun 		outreg = 0;
442*4882a593Smuzhiyun 		break;
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	case OUTMODE_ANALOG_ADC:
445*4882a593Smuzhiyun 		outreg = (1 << 10) | (3 << 6);
446*4882a593Smuzhiyun 		dib8000_set_acquisition_mode(state);
447*4882a593Smuzhiyun 		break;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	default:
450*4882a593Smuzhiyun 		dprintk("Unhandled output_mode passed to be set for demod %p\n",
451*4882a593Smuzhiyun 				&state->fe[0]);
452*4882a593Smuzhiyun 		return -EINVAL;
453*4882a593Smuzhiyun 	}
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	if (state->cfg.output_mpeg2_in_188_bytes)
456*4882a593Smuzhiyun 		smo_mode |= (1 << 5);
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	dib8000_write_word(state, 299, smo_mode);
459*4882a593Smuzhiyun 	dib8000_write_word(state, 300, fifo_threshold);	/* synchronous fread */
460*4882a593Smuzhiyun 	dib8000_write_word(state, 1286, outreg);
461*4882a593Smuzhiyun 	dib8000_write_word(state, 1291, sram);
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	return 0;
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun 
dib8000_set_diversity_in(struct dvb_frontend * fe,int onoff)466*4882a593Smuzhiyun static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
469*4882a593Smuzhiyun 	u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0;
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	dprintk("set diversity input to %i\n", onoff);
472*4882a593Smuzhiyun 	if (!state->differential_constellation) {
473*4882a593Smuzhiyun 		dib8000_write_word(state, 272, 1 << 9);	//dvsy_off_lmod4 = 1
474*4882a593Smuzhiyun 		dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2);	// sync_enable = 1; comb_mode = 2
475*4882a593Smuzhiyun 	} else {
476*4882a593Smuzhiyun 		dib8000_write_word(state, 272, 0);	//dvsy_off_lmod4 = 0
477*4882a593Smuzhiyun 		dib8000_write_word(state, 273, sync_wait);	// sync_enable = 0; comb_mode = 0
478*4882a593Smuzhiyun 	}
479*4882a593Smuzhiyun 	state->diversity_onoff = onoff;
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	switch (onoff) {
482*4882a593Smuzhiyun 	case 0:		/* only use the internal way - not the diversity input */
483*4882a593Smuzhiyun 		dib8000_write_word(state, 270, 1);
484*4882a593Smuzhiyun 		dib8000_write_word(state, 271, 0);
485*4882a593Smuzhiyun 		break;
486*4882a593Smuzhiyun 	case 1:		/* both ways */
487*4882a593Smuzhiyun 		dib8000_write_word(state, 270, 6);
488*4882a593Smuzhiyun 		dib8000_write_word(state, 271, 6);
489*4882a593Smuzhiyun 		break;
490*4882a593Smuzhiyun 	case 2:		/* only the diversity input */
491*4882a593Smuzhiyun 		dib8000_write_word(state, 270, 0);
492*4882a593Smuzhiyun 		dib8000_write_word(state, 271, 1);
493*4882a593Smuzhiyun 		break;
494*4882a593Smuzhiyun 	}
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	if (state->revision == 0x8002) {
497*4882a593Smuzhiyun 		tmp = dib8000_read_word(state, 903);
498*4882a593Smuzhiyun 		dib8000_write_word(state, 903, tmp & ~(1 << 3));
499*4882a593Smuzhiyun 		msleep(30);
500*4882a593Smuzhiyun 		dib8000_write_word(state, 903, tmp | (1 << 3));
501*4882a593Smuzhiyun 	}
502*4882a593Smuzhiyun 	return 0;
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun 
dib8000_set_power_mode(struct dib8000_state * state,enum dib8000_power_mode mode)505*4882a593Smuzhiyun static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun 	/* by default everything is going to be powered off */
508*4882a593Smuzhiyun 	u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
509*4882a593Smuzhiyun 		reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
510*4882a593Smuzhiyun 		reg_1280;
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	if (state->revision != 0x8090)
513*4882a593Smuzhiyun 		reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
514*4882a593Smuzhiyun 	else
515*4882a593Smuzhiyun 		reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	/* now, depending on the requested mode, we power on */
518*4882a593Smuzhiyun 	switch (mode) {
519*4882a593Smuzhiyun 		/* power up everything in the demod */
520*4882a593Smuzhiyun 	case DIB8000_POWER_ALL:
521*4882a593Smuzhiyun 		reg_774 = 0x0000;
522*4882a593Smuzhiyun 		reg_775 = 0x0000;
523*4882a593Smuzhiyun 		reg_776 = 0x0000;
524*4882a593Smuzhiyun 		reg_900 &= 0xfffc;
525*4882a593Smuzhiyun 		if (state->revision != 0x8090)
526*4882a593Smuzhiyun 			reg_1280 &= 0x00ff;
527*4882a593Smuzhiyun 		else
528*4882a593Smuzhiyun 			reg_1280 &= 0x707f;
529*4882a593Smuzhiyun 		break;
530*4882a593Smuzhiyun 	case DIB8000_POWER_INTERFACE_ONLY:
531*4882a593Smuzhiyun 		if (state->revision != 0x8090)
532*4882a593Smuzhiyun 			reg_1280 &= 0x00ff;
533*4882a593Smuzhiyun 		else
534*4882a593Smuzhiyun 			reg_1280 &= 0xfa7b;
535*4882a593Smuzhiyun 		break;
536*4882a593Smuzhiyun 	}
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x\n", reg_774, reg_775, reg_776, reg_900, reg_1280);
539*4882a593Smuzhiyun 	dib8000_write_word(state, 774, reg_774);
540*4882a593Smuzhiyun 	dib8000_write_word(state, 775, reg_775);
541*4882a593Smuzhiyun 	dib8000_write_word(state, 776, reg_776);
542*4882a593Smuzhiyun 	dib8000_write_word(state, 900, reg_900);
543*4882a593Smuzhiyun 	dib8000_write_word(state, 1280, reg_1280);
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun 
dib8000_set_adc_state(struct dib8000_state * state,enum dibx000_adc_states no)546*4882a593Smuzhiyun static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun 	int ret = 0;
549*4882a593Smuzhiyun 	u16 reg, reg_907 = dib8000_read_word(state, 907);
550*4882a593Smuzhiyun 	u16 reg_908 = dib8000_read_word(state, 908);
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	switch (no) {
553*4882a593Smuzhiyun 	case DIBX000_SLOW_ADC_ON:
554*4882a593Smuzhiyun 		if (state->revision != 0x8090) {
555*4882a593Smuzhiyun 			reg_908 |= (1 << 1) | (1 << 0);
556*4882a593Smuzhiyun 			ret |= dib8000_write_word(state, 908, reg_908);
557*4882a593Smuzhiyun 			reg_908 &= ~(1 << 1);
558*4882a593Smuzhiyun 		} else {
559*4882a593Smuzhiyun 			reg = dib8000_read_word(state, 1925);
560*4882a593Smuzhiyun 			/* en_slowAdc = 1 & reset_sladc = 1 */
561*4882a593Smuzhiyun 			dib8000_write_word(state, 1925, reg |
562*4882a593Smuzhiyun 					(1<<4) | (1<<2));
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 			/* read access to make it works... strange ... */
565*4882a593Smuzhiyun 			reg = dib8000_read_word(state, 1925);
566*4882a593Smuzhiyun 			msleep(20);
567*4882a593Smuzhiyun 			/* en_slowAdc = 1 & reset_sladc = 0 */
568*4882a593Smuzhiyun 			dib8000_write_word(state, 1925, reg & ~(1<<4));
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 			reg = dib8000_read_word(state, 921) & ~((0x3 << 14)
571*4882a593Smuzhiyun 					| (0x3 << 12));
572*4882a593Smuzhiyun 			/* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ;
573*4882a593Smuzhiyun 			   (Vin2 = Vcm) */
574*4882a593Smuzhiyun 			dib8000_write_word(state, 921, reg | (1 << 14)
575*4882a593Smuzhiyun 					| (3 << 12));
576*4882a593Smuzhiyun 		}
577*4882a593Smuzhiyun 		break;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	case DIBX000_SLOW_ADC_OFF:
580*4882a593Smuzhiyun 		if (state->revision == 0x8090) {
581*4882a593Smuzhiyun 			reg = dib8000_read_word(state, 1925);
582*4882a593Smuzhiyun 			/* reset_sladc = 1 en_slowAdc = 0 */
583*4882a593Smuzhiyun 			dib8000_write_word(state, 1925,
584*4882a593Smuzhiyun 					(reg & ~(1<<2)) | (1<<4));
585*4882a593Smuzhiyun 		}
586*4882a593Smuzhiyun 		reg_908 |= (1 << 1) | (1 << 0);
587*4882a593Smuzhiyun 		break;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	case DIBX000_ADC_ON:
590*4882a593Smuzhiyun 		reg_907 &= 0x0fff;
591*4882a593Smuzhiyun 		reg_908 &= 0x0003;
592*4882a593Smuzhiyun 		break;
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	case DIBX000_ADC_OFF:	// leave the VBG voltage on
595*4882a593Smuzhiyun 		reg_907 = (1 << 13) | (1 << 12);
596*4882a593Smuzhiyun 		reg_908 = (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 1);
597*4882a593Smuzhiyun 		break;
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	case DIBX000_VBG_ENABLE:
600*4882a593Smuzhiyun 		reg_907 &= ~(1 << 15);
601*4882a593Smuzhiyun 		break;
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	case DIBX000_VBG_DISABLE:
604*4882a593Smuzhiyun 		reg_907 |= (1 << 15);
605*4882a593Smuzhiyun 		break;
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	default:
608*4882a593Smuzhiyun 		break;
609*4882a593Smuzhiyun 	}
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	ret |= dib8000_write_word(state, 907, reg_907);
612*4882a593Smuzhiyun 	ret |= dib8000_write_word(state, 908, reg_908);
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	return ret;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun 
dib8000_set_bandwidth(struct dvb_frontend * fe,u32 bw)617*4882a593Smuzhiyun static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
620*4882a593Smuzhiyun 	u32 timf;
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	if (bw == 0)
623*4882a593Smuzhiyun 		bw = 6000;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	if (state->timf == 0) {
626*4882a593Smuzhiyun 		dprintk("using default timf\n");
627*4882a593Smuzhiyun 		timf = state->timf_default;
628*4882a593Smuzhiyun 	} else {
629*4882a593Smuzhiyun 		dprintk("using updated timf\n");
630*4882a593Smuzhiyun 		timf = state->timf;
631*4882a593Smuzhiyun 	}
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
634*4882a593Smuzhiyun 	dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	return 0;
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun 
dib8000_sad_calib(struct dib8000_state * state)639*4882a593Smuzhiyun static int dib8000_sad_calib(struct dib8000_state *state)
640*4882a593Smuzhiyun {
641*4882a593Smuzhiyun 	u8 sad_sel = 3;
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	if (state->revision == 0x8090) {
644*4882a593Smuzhiyun 		dib8000_write_word(state, 922, (sad_sel << 2));
645*4882a593Smuzhiyun 		dib8000_write_word(state, 923, 2048);
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 		dib8000_write_word(state, 922, (sad_sel << 2) | 0x1);
648*4882a593Smuzhiyun 		dib8000_write_word(state, 922, (sad_sel << 2));
649*4882a593Smuzhiyun 	} else {
650*4882a593Smuzhiyun 		/* internal */
651*4882a593Smuzhiyun 		dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
652*4882a593Smuzhiyun 		dib8000_write_word(state, 924, 776);
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 		/* do the calibration */
655*4882a593Smuzhiyun 		dib8000_write_word(state, 923, (1 << 0));
656*4882a593Smuzhiyun 		dib8000_write_word(state, 923, (0 << 0));
657*4882a593Smuzhiyun 	}
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	msleep(1);
660*4882a593Smuzhiyun 	return 0;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun 
dib8000_set_wbd_ref(struct dvb_frontend * fe,u16 value)663*4882a593Smuzhiyun static int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
666*4882a593Smuzhiyun 	if (value > 4095)
667*4882a593Smuzhiyun 		value = 4095;
668*4882a593Smuzhiyun 	state->wbd_ref = value;
669*4882a593Smuzhiyun 	return dib8000_write_word(state, 106, value);
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun 
dib8000_reset_pll_common(struct dib8000_state * state,const struct dibx000_bandwidth_config * bw)672*4882a593Smuzhiyun static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
673*4882a593Smuzhiyun {
674*4882a593Smuzhiyun 	dprintk("ifreq: %d %x, inversion: %d\n", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
675*4882a593Smuzhiyun 	if (state->revision != 0x8090) {
676*4882a593Smuzhiyun 		dib8000_write_word(state, 23,
677*4882a593Smuzhiyun 				(u16) (((bw->internal * 1000) >> 16) & 0xffff));
678*4882a593Smuzhiyun 		dib8000_write_word(state, 24,
679*4882a593Smuzhiyun 				(u16) ((bw->internal * 1000) & 0xffff));
680*4882a593Smuzhiyun 	} else {
681*4882a593Smuzhiyun 		dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff));
682*4882a593Smuzhiyun 		dib8000_write_word(state, 24,
683*4882a593Smuzhiyun 				(u16) ((bw->internal  / 2 * 1000) & 0xffff));
684*4882a593Smuzhiyun 	}
685*4882a593Smuzhiyun 	dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
686*4882a593Smuzhiyun 	dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
687*4882a593Smuzhiyun 	dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	if (state->revision != 0x8090)
690*4882a593Smuzhiyun 		dib8000_write_word(state, 922, bw->sad_cfg);
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun 
dib8000_reset_pll(struct dib8000_state * state)693*4882a593Smuzhiyun static void dib8000_reset_pll(struct dib8000_state *state)
694*4882a593Smuzhiyun {
695*4882a593Smuzhiyun 	const struct dibx000_bandwidth_config *pll = state->cfg.pll;
696*4882a593Smuzhiyun 	u16 clk_cfg1, reg;
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 	if (state->revision != 0x8090) {
699*4882a593Smuzhiyun 		dib8000_write_word(state, 901,
700*4882a593Smuzhiyun 				(pll->pll_prediv << 8) | (pll->pll_ratio << 0));
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 		clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
703*4882a593Smuzhiyun 			(pll->bypclk_div << 5) | (pll->enable_refdiv << 4) |
704*4882a593Smuzhiyun 			(1 << 3) | (pll->pll_range << 1) |
705*4882a593Smuzhiyun 			(pll->pll_reset << 0);
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 		dib8000_write_word(state, 902, clk_cfg1);
708*4882a593Smuzhiyun 		clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
709*4882a593Smuzhiyun 		dib8000_write_word(state, 902, clk_cfg1);
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 		dprintk("clk_cfg1: 0x%04x\n", clk_cfg1);
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 		/* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
714*4882a593Smuzhiyun 		if (state->cfg.pll->ADClkSrc == 0)
715*4882a593Smuzhiyun 			dib8000_write_word(state, 904,
716*4882a593Smuzhiyun 					(0 << 15) | (0 << 12) | (0 << 10) |
717*4882a593Smuzhiyun 					(pll->modulo << 8) |
718*4882a593Smuzhiyun 					(pll->ADClkSrc << 7) | (0 << 1));
719*4882a593Smuzhiyun 		else if (state->cfg.refclksel != 0)
720*4882a593Smuzhiyun 			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
721*4882a593Smuzhiyun 					((state->cfg.refclksel & 0x3) << 10) |
722*4882a593Smuzhiyun 					(pll->modulo << 8) |
723*4882a593Smuzhiyun 					(pll->ADClkSrc << 7) | (0 << 1));
724*4882a593Smuzhiyun 		else
725*4882a593Smuzhiyun 			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
726*4882a593Smuzhiyun 					(3 << 10) | (pll->modulo << 8) |
727*4882a593Smuzhiyun 					(pll->ADClkSrc << 7) | (0 << 1));
728*4882a593Smuzhiyun 	} else {
729*4882a593Smuzhiyun 		dib8000_write_word(state, 1856, (!pll->pll_reset<<13) |
730*4882a593Smuzhiyun 				(pll->pll_range<<12) | (pll->pll_ratio<<6) |
731*4882a593Smuzhiyun 				(pll->pll_prediv));
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 		reg = dib8000_read_word(state, 1857);
734*4882a593Smuzhiyun 		dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15));
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 		reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */
737*4882a593Smuzhiyun 		dib8000_write_word(state, 1858, reg | 1);
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 		dib8000_write_word(state, 904, (pll->modulo << 8));
740*4882a593Smuzhiyun 	}
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	dib8000_reset_pll_common(state, pll);
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun 
dib8000_update_pll(struct dvb_frontend * fe,struct dibx000_bandwidth_config * pll,u32 bw,u8 ratio)745*4882a593Smuzhiyun static int dib8000_update_pll(struct dvb_frontend *fe,
746*4882a593Smuzhiyun 		struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
747*4882a593Smuzhiyun {
748*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
749*4882a593Smuzhiyun 	u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
750*4882a593Smuzhiyun 	u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ;
751*4882a593Smuzhiyun 	u32 internal, xtal;
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	/* get back old values */
754*4882a593Smuzhiyun 	prediv = reg_1856 & 0x3f;
755*4882a593Smuzhiyun 	loopdiv = (reg_1856 >> 6) & 0x3f;
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	if ((pll == NULL) || (pll->pll_prediv == prediv &&
758*4882a593Smuzhiyun 				pll->pll_ratio == loopdiv))
759*4882a593Smuzhiyun 		return -EINVAL;
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 	dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)\n", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
762*4882a593Smuzhiyun 	if (state->revision == 0x8090) {
763*4882a593Smuzhiyun 		reg_1856 &= 0xf000;
764*4882a593Smuzhiyun 		reg_1857 = dib8000_read_word(state, 1857);
765*4882a593Smuzhiyun 		/* disable PLL */
766*4882a593Smuzhiyun 		dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15));
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 		dib8000_write_word(state, 1856, reg_1856 |
769*4882a593Smuzhiyun 				((pll->pll_ratio & 0x3f) << 6) |
770*4882a593Smuzhiyun 				(pll->pll_prediv & 0x3f));
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 		/* write new system clk into P_sec_len */
773*4882a593Smuzhiyun 		internal = dib8000_read32(state, 23) / 1000;
774*4882a593Smuzhiyun 		dprintk("Old Internal = %d\n", internal);
775*4882a593Smuzhiyun 		xtal = 2 * (internal / loopdiv) * prediv;
776*4882a593Smuzhiyun 		internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio;
777*4882a593Smuzhiyun 		dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d\n", xtal, internal/1000, internal/2000, internal/8000);
778*4882a593Smuzhiyun 		dprintk("New Internal = %d\n", internal);
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 		dib8000_write_word(state, 23,
781*4882a593Smuzhiyun 				(u16) (((internal / 2) >> 16) & 0xffff));
782*4882a593Smuzhiyun 		dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff));
783*4882a593Smuzhiyun 		/* enable PLL */
784*4882a593Smuzhiyun 		dib8000_write_word(state, 1857, reg_1857 | (1 << 15));
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 		while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1)
787*4882a593Smuzhiyun 			dprintk("Waiting for PLL to lock\n");
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 		/* verify */
790*4882a593Smuzhiyun 		reg_1856 = dib8000_read_word(state, 1856);
791*4882a593Smuzhiyun 		dprintk("PLL Updated with prediv = %d and loopdiv = %d\n",
792*4882a593Smuzhiyun 				reg_1856&0x3f, (reg_1856>>6)&0x3f);
793*4882a593Smuzhiyun 	} else {
794*4882a593Smuzhiyun 		if (bw != state->current_demod_bw) {
795*4882a593Smuzhiyun 			/** Bandwidth change => force PLL update **/
796*4882a593Smuzhiyun 			dprintk("PLL: Bandwidth Change %d MHz -> %d MHz (prediv: %d->%d)\n", state->current_demod_bw / 1000, bw / 1000, oldprediv, state->cfg.pll->pll_prediv);
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 			if (state->cfg.pll->pll_prediv != oldprediv) {
799*4882a593Smuzhiyun 				/** Full PLL change only if prediv is changed **/
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 				/** full update => bypass and reconfigure **/
802*4882a593Smuzhiyun 				dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)\n", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio);
803*4882a593Smuzhiyun 				dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */
804*4882a593Smuzhiyun 				dib8000_reset_pll(state);
805*4882a593Smuzhiyun 				dib8000_write_word(state, 898, 0x0004); /* sad */
806*4882a593Smuzhiyun 			} else
807*4882a593Smuzhiyun 				ratio = state->cfg.pll->pll_ratio;
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 			state->current_demod_bw = bw;
810*4882a593Smuzhiyun 		}
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun 		if (ratio != 0) {
813*4882a593Smuzhiyun 			/** ratio update => only change ratio **/
814*4882a593Smuzhiyun 			dprintk("PLL: Update ratio (prediv: %d, ratio: %d)\n", state->cfg.pll->pll_prediv, ratio);
815*4882a593Smuzhiyun 			dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
816*4882a593Smuzhiyun 		}
817*4882a593Smuzhiyun 	}
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	return 0;
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun 
dib8000_reset_gpio(struct dib8000_state * st)822*4882a593Smuzhiyun static int dib8000_reset_gpio(struct dib8000_state *st)
823*4882a593Smuzhiyun {
824*4882a593Smuzhiyun 	/* reset the GPIOs */
825*4882a593Smuzhiyun 	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
826*4882a593Smuzhiyun 	dib8000_write_word(st, 1030, st->cfg.gpio_val);
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	/* TODO 782 is P_gpio_od */
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 	dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun 	dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
833*4882a593Smuzhiyun 	return 0;
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun 
dib8000_cfg_gpio(struct dib8000_state * st,u8 num,u8 dir,u8 val)836*4882a593Smuzhiyun static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
837*4882a593Smuzhiyun {
838*4882a593Smuzhiyun 	st->cfg.gpio_dir = dib8000_read_word(st, 1029);
839*4882a593Smuzhiyun 	st->cfg.gpio_dir &= ~(1 << num);	/* reset the direction bit */
840*4882a593Smuzhiyun 	st->cfg.gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
841*4882a593Smuzhiyun 	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	st->cfg.gpio_val = dib8000_read_word(st, 1030);
844*4882a593Smuzhiyun 	st->cfg.gpio_val &= ~(1 << num);	/* reset the direction bit */
845*4882a593Smuzhiyun 	st->cfg.gpio_val |= (val & 0x01) << num;	/* set the new value */
846*4882a593Smuzhiyun 	dib8000_write_word(st, 1030, st->cfg.gpio_val);
847*4882a593Smuzhiyun 
848*4882a593Smuzhiyun 	dprintk("gpio dir: %x: gpio val: %x\n", st->cfg.gpio_dir, st->cfg.gpio_val);
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun 	return 0;
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun 
dib8000_set_gpio(struct dvb_frontend * fe,u8 num,u8 dir,u8 val)853*4882a593Smuzhiyun static int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
854*4882a593Smuzhiyun {
855*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
856*4882a593Smuzhiyun 	return dib8000_cfg_gpio(state, num, dir, val);
857*4882a593Smuzhiyun }
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun static const u16 dib8000_defaults[] = {
860*4882a593Smuzhiyun 	/* auto search configuration - lock0 by default waiting
861*4882a593Smuzhiyun 	 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
862*4882a593Smuzhiyun 	3, 7,
863*4882a593Smuzhiyun 	0x0004,
864*4882a593Smuzhiyun 	0x0400,
865*4882a593Smuzhiyun 	0x0814,
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	12, 11,
868*4882a593Smuzhiyun 	0x001b,
869*4882a593Smuzhiyun 	0x7740,
870*4882a593Smuzhiyun 	0x005b,
871*4882a593Smuzhiyun 	0x8d80,
872*4882a593Smuzhiyun 	0x01c9,
873*4882a593Smuzhiyun 	0xc380,
874*4882a593Smuzhiyun 	0x0000,
875*4882a593Smuzhiyun 	0x0080,
876*4882a593Smuzhiyun 	0x0000,
877*4882a593Smuzhiyun 	0x0090,
878*4882a593Smuzhiyun 	0x0001,
879*4882a593Smuzhiyun 	0xd4c0,
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 	/*1, 32,
882*4882a593Smuzhiyun 		0x6680 // P_corm_thres Lock algorithms configuration */
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 	11, 80,			/* set ADC level to -16 */
885*4882a593Smuzhiyun 	(1 << 13) - 825 - 117,
886*4882a593Smuzhiyun 	(1 << 13) - 837 - 117,
887*4882a593Smuzhiyun 	(1 << 13) - 811 - 117,
888*4882a593Smuzhiyun 	(1 << 13) - 766 - 117,
889*4882a593Smuzhiyun 	(1 << 13) - 737 - 117,
890*4882a593Smuzhiyun 	(1 << 13) - 693 - 117,
891*4882a593Smuzhiyun 	(1 << 13) - 648 - 117,
892*4882a593Smuzhiyun 	(1 << 13) - 619 - 117,
893*4882a593Smuzhiyun 	(1 << 13) - 575 - 117,
894*4882a593Smuzhiyun 	(1 << 13) - 531 - 117,
895*4882a593Smuzhiyun 	(1 << 13) - 501 - 117,
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 	4, 108,
898*4882a593Smuzhiyun 	0,
899*4882a593Smuzhiyun 	0,
900*4882a593Smuzhiyun 	0,
901*4882a593Smuzhiyun 	0,
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun 	1, 175,
904*4882a593Smuzhiyun 	0x0410,
905*4882a593Smuzhiyun 	1, 179,
906*4882a593Smuzhiyun 	8192,			// P_fft_nb_to_cut
907*4882a593Smuzhiyun 
908*4882a593Smuzhiyun 	6, 181,
909*4882a593Smuzhiyun 	0x2800,			// P_coff_corthres_ ( 2k 4k 8k ) 0x2800
910*4882a593Smuzhiyun 	0x2800,
911*4882a593Smuzhiyun 	0x2800,
912*4882a593Smuzhiyun 	0x2800,			// P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
913*4882a593Smuzhiyun 	0x2800,
914*4882a593Smuzhiyun 	0x2800,
915*4882a593Smuzhiyun 
916*4882a593Smuzhiyun 	2, 193,
917*4882a593Smuzhiyun 	0x0666,			// P_pha3_thres
918*4882a593Smuzhiyun 	0x0000,			// P_cti_use_cpe, P_cti_use_prog
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun 	2, 205,
921*4882a593Smuzhiyun 	0x200f,			// P_cspu_regul, P_cspu_win_cut
922*4882a593Smuzhiyun 	0x000f,			// P_des_shift_work
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	5, 215,
925*4882a593Smuzhiyun 	0x023d,			// P_adp_regul_cnt
926*4882a593Smuzhiyun 	0x00a4,			// P_adp_noise_cnt
927*4882a593Smuzhiyun 	0x00a4,			// P_adp_regul_ext
928*4882a593Smuzhiyun 	0x7ff0,			// P_adp_noise_ext
929*4882a593Smuzhiyun 	0x3ccc,			// P_adp_fil
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 	1, 230,
932*4882a593Smuzhiyun 	0x0000,			// P_2d_byp_ti_num
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 	1, 263,
935*4882a593Smuzhiyun 	0x800,			//P_equal_thres_wgn
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	1, 268,
938*4882a593Smuzhiyun 	(2 << 9) | 39,		// P_equal_ctrl_synchro, P_equal_speedmode
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun 	1, 270,
941*4882a593Smuzhiyun 	0x0001,			// P_div_lock0_wait
942*4882a593Smuzhiyun 	1, 285,
943*4882a593Smuzhiyun 	0x0020,			//p_fec_
944*4882a593Smuzhiyun 	1, 299,
945*4882a593Smuzhiyun 	0x0062,			/* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun 	1, 338,
948*4882a593Smuzhiyun 	(1 << 12) |		// P_ctrl_corm_thres4pre_freq_inh=1
949*4882a593Smuzhiyun 		(1 << 10) |
950*4882a593Smuzhiyun 		(0 << 9) |		/* P_ctrl_pre_freq_inh=0 */
951*4882a593Smuzhiyun 		(3 << 5) |		/* P_ctrl_pre_freq_step=3 */
952*4882a593Smuzhiyun 		(1 << 0),		/* P_pre_freq_win_len=1 */
953*4882a593Smuzhiyun 
954*4882a593Smuzhiyun 	0,
955*4882a593Smuzhiyun };
956*4882a593Smuzhiyun 
dib8000_identify(struct i2c_device * client)957*4882a593Smuzhiyun static u16 dib8000_identify(struct i2c_device *client)
958*4882a593Smuzhiyun {
959*4882a593Smuzhiyun 	u16 value;
960*4882a593Smuzhiyun 
961*4882a593Smuzhiyun 	//because of glitches sometimes
962*4882a593Smuzhiyun 	value = dib8000_i2c_read16(client, 896);
963*4882a593Smuzhiyun 
964*4882a593Smuzhiyun 	if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
965*4882a593Smuzhiyun 		dprintk("wrong Vendor ID (read=0x%x)\n", value);
966*4882a593Smuzhiyun 		return 0;
967*4882a593Smuzhiyun 	}
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	value = dib8000_i2c_read16(client, 897);
970*4882a593Smuzhiyun 	if (value != 0x8000 && value != 0x8001 &&
971*4882a593Smuzhiyun 			value != 0x8002 && value != 0x8090) {
972*4882a593Smuzhiyun 		dprintk("wrong Device ID (%x)\n", value);
973*4882a593Smuzhiyun 		return 0;
974*4882a593Smuzhiyun 	}
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	switch (value) {
977*4882a593Smuzhiyun 	case 0x8000:
978*4882a593Smuzhiyun 		dprintk("found DiB8000A\n");
979*4882a593Smuzhiyun 		break;
980*4882a593Smuzhiyun 	case 0x8001:
981*4882a593Smuzhiyun 		dprintk("found DiB8000B\n");
982*4882a593Smuzhiyun 		break;
983*4882a593Smuzhiyun 	case 0x8002:
984*4882a593Smuzhiyun 		dprintk("found DiB8000C\n");
985*4882a593Smuzhiyun 		break;
986*4882a593Smuzhiyun 	case 0x8090:
987*4882a593Smuzhiyun 		dprintk("found DiB8096P\n");
988*4882a593Smuzhiyun 		break;
989*4882a593Smuzhiyun 	}
990*4882a593Smuzhiyun 	return value;
991*4882a593Smuzhiyun }
992*4882a593Smuzhiyun 
993*4882a593Smuzhiyun static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 *unc);
994*4882a593Smuzhiyun 
dib8000_reset_stats(struct dvb_frontend * fe)995*4882a593Smuzhiyun static void dib8000_reset_stats(struct dvb_frontend *fe)
996*4882a593Smuzhiyun {
997*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
998*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
999*4882a593Smuzhiyun 	u32 ucb;
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 	memset(&c->strength, 0, sizeof(c->strength));
1002*4882a593Smuzhiyun 	memset(&c->cnr, 0, sizeof(c->cnr));
1003*4882a593Smuzhiyun 	memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
1004*4882a593Smuzhiyun 	memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
1005*4882a593Smuzhiyun 	memset(&c->block_error, 0, sizeof(c->block_error));
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	c->strength.len = 1;
1008*4882a593Smuzhiyun 	c->cnr.len = 1;
1009*4882a593Smuzhiyun 	c->block_error.len = 1;
1010*4882a593Smuzhiyun 	c->block_count.len = 1;
1011*4882a593Smuzhiyun 	c->post_bit_error.len = 1;
1012*4882a593Smuzhiyun 	c->post_bit_count.len = 1;
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 	c->strength.stat[0].scale = FE_SCALE_DECIBEL;
1015*4882a593Smuzhiyun 	c->strength.stat[0].uvalue = 0;
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun 	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1018*4882a593Smuzhiyun 	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1019*4882a593Smuzhiyun 	c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1020*4882a593Smuzhiyun 	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1021*4882a593Smuzhiyun 	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun 	dib8000_read_unc_blocks(fe, &ucb);
1024*4882a593Smuzhiyun 
1025*4882a593Smuzhiyun 	state->init_ucb = -ucb;
1026*4882a593Smuzhiyun 	state->ber_jiffies_stats = 0;
1027*4882a593Smuzhiyun 	state->per_jiffies_stats = 0;
1028*4882a593Smuzhiyun 	memset(&state->ber_jiffies_stats_layer, 0,
1029*4882a593Smuzhiyun 	       sizeof(state->ber_jiffies_stats_layer));
1030*4882a593Smuzhiyun }
1031*4882a593Smuzhiyun 
dib8000_reset(struct dvb_frontend * fe)1032*4882a593Smuzhiyun static int dib8000_reset(struct dvb_frontend *fe)
1033*4882a593Smuzhiyun {
1034*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun 	if ((state->revision = dib8000_identify(&state->i2c)) == 0)
1037*4882a593Smuzhiyun 		return -EINVAL;
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 	/* sram lead in, rdy */
1040*4882a593Smuzhiyun 	if (state->revision != 0x8090)
1041*4882a593Smuzhiyun 		dib8000_write_word(state, 1287, 0x0003);
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun 	if (state->revision == 0x8000)
1044*4882a593Smuzhiyun 		dprintk("error : dib8000 MA not supported\n");
1045*4882a593Smuzhiyun 
1046*4882a593Smuzhiyun 	dibx000_reset_i2c_master(&state->i2c_master);
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
1049*4882a593Smuzhiyun 
1050*4882a593Smuzhiyun 	/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
1051*4882a593Smuzhiyun 	dib8000_set_adc_state(state, DIBX000_ADC_OFF);
1052*4882a593Smuzhiyun 
1053*4882a593Smuzhiyun 	/* restart all parts */
1054*4882a593Smuzhiyun 	dib8000_write_word(state, 770, 0xffff);
1055*4882a593Smuzhiyun 	dib8000_write_word(state, 771, 0xffff);
1056*4882a593Smuzhiyun 	dib8000_write_word(state, 772, 0xfffc);
1057*4882a593Smuzhiyun 	dib8000_write_word(state, 898, 0x000c);	/* restart sad */
1058*4882a593Smuzhiyun 	if (state->revision == 0x8090)
1059*4882a593Smuzhiyun 		dib8000_write_word(state, 1280, 0x0045);
1060*4882a593Smuzhiyun 	else
1061*4882a593Smuzhiyun 		dib8000_write_word(state, 1280, 0x004d);
1062*4882a593Smuzhiyun 	dib8000_write_word(state, 1281, 0x000c);
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun 	dib8000_write_word(state, 770, 0x0000);
1065*4882a593Smuzhiyun 	dib8000_write_word(state, 771, 0x0000);
1066*4882a593Smuzhiyun 	dib8000_write_word(state, 772, 0x0000);
1067*4882a593Smuzhiyun 	dib8000_write_word(state, 898, 0x0004);	// sad
1068*4882a593Smuzhiyun 	dib8000_write_word(state, 1280, 0x0000);
1069*4882a593Smuzhiyun 	dib8000_write_word(state, 1281, 0x0000);
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun 	/* drives */
1072*4882a593Smuzhiyun 	if (state->revision != 0x8090) {
1073*4882a593Smuzhiyun 		if (state->cfg.drives)
1074*4882a593Smuzhiyun 			dib8000_write_word(state, 906, state->cfg.drives);
1075*4882a593Smuzhiyun 		else {
1076*4882a593Smuzhiyun 			dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.\n");
1077*4882a593Smuzhiyun 			/* min drive SDRAM - not optimal - adjust */
1078*4882a593Smuzhiyun 			dib8000_write_word(state, 906, 0x2d98);
1079*4882a593Smuzhiyun 		}
1080*4882a593Smuzhiyun 	}
1081*4882a593Smuzhiyun 
1082*4882a593Smuzhiyun 	dib8000_reset_pll(state);
1083*4882a593Smuzhiyun 	if (state->revision != 0x8090)
1084*4882a593Smuzhiyun 		dib8000_write_word(state, 898, 0x0004);
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun 	if (dib8000_reset_gpio(state) != 0)
1087*4882a593Smuzhiyun 		dprintk("GPIO reset was not successful.\n");
1088*4882a593Smuzhiyun 
1089*4882a593Smuzhiyun 	if ((state->revision != 0x8090) &&
1090*4882a593Smuzhiyun 			(dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
1091*4882a593Smuzhiyun 		dprintk("OUTPUT_MODE could not be reset.\n");
1092*4882a593Smuzhiyun 
1093*4882a593Smuzhiyun 	state->current_agc = NULL;
1094*4882a593Smuzhiyun 
1095*4882a593Smuzhiyun 	// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
1096*4882a593Smuzhiyun 	/* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
1097*4882a593Smuzhiyun 	if (state->cfg.pll->ifreq == 0)
1098*4882a593Smuzhiyun 		dib8000_write_word(state, 40, 0x0755);	/* P_iqc_corr_inh = 0 enable IQcorr block */
1099*4882a593Smuzhiyun 	else
1100*4882a593Smuzhiyun 		dib8000_write_word(state, 40, 0x1f55);	/* P_iqc_corr_inh = 1 disable IQcorr block */
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun 	{
1103*4882a593Smuzhiyun 		u16 l = 0, r;
1104*4882a593Smuzhiyun 		const u16 *n;
1105*4882a593Smuzhiyun 		n = dib8000_defaults;
1106*4882a593Smuzhiyun 		l = *n++;
1107*4882a593Smuzhiyun 		while (l) {
1108*4882a593Smuzhiyun 			r = *n++;
1109*4882a593Smuzhiyun 			do {
1110*4882a593Smuzhiyun 				dib8000_write_word(state, r, *n++);
1111*4882a593Smuzhiyun 				r++;
1112*4882a593Smuzhiyun 			} while (--l);
1113*4882a593Smuzhiyun 			l = *n++;
1114*4882a593Smuzhiyun 		}
1115*4882a593Smuzhiyun 	}
1116*4882a593Smuzhiyun 
1117*4882a593Smuzhiyun 	state->isdbt_cfg_loaded = 0;
1118*4882a593Smuzhiyun 
1119*4882a593Smuzhiyun 	//div_cfg override for special configs
1120*4882a593Smuzhiyun 	if ((state->revision != 8090) && (state->cfg.div_cfg != 0))
1121*4882a593Smuzhiyun 		dib8000_write_word(state, 903, state->cfg.div_cfg);
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun 	/* unforce divstr regardless whether i2c enumeration was done or not */
1124*4882a593Smuzhiyun 	dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
1125*4882a593Smuzhiyun 
1126*4882a593Smuzhiyun 	dib8000_set_bandwidth(fe, 6000);
1127*4882a593Smuzhiyun 
1128*4882a593Smuzhiyun 	dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
1129*4882a593Smuzhiyun 	dib8000_sad_calib(state);
1130*4882a593Smuzhiyun 	if (state->revision != 0x8090)
1131*4882a593Smuzhiyun 		dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
1132*4882a593Smuzhiyun 
1133*4882a593Smuzhiyun 	/* ber_rs_len = 3 */
1134*4882a593Smuzhiyun 	dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));
1135*4882a593Smuzhiyun 
1136*4882a593Smuzhiyun 	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
1137*4882a593Smuzhiyun 
1138*4882a593Smuzhiyun 	dib8000_reset_stats(fe);
1139*4882a593Smuzhiyun 
1140*4882a593Smuzhiyun 	return 0;
1141*4882a593Smuzhiyun }
1142*4882a593Smuzhiyun 
dib8000_restart_agc(struct dib8000_state * state)1143*4882a593Smuzhiyun static void dib8000_restart_agc(struct dib8000_state *state)
1144*4882a593Smuzhiyun {
1145*4882a593Smuzhiyun 	// P_restart_iqc & P_restart_agc
1146*4882a593Smuzhiyun 	dib8000_write_word(state, 770, 0x0a00);
1147*4882a593Smuzhiyun 	dib8000_write_word(state, 770, 0x0000);
1148*4882a593Smuzhiyun }
1149*4882a593Smuzhiyun 
dib8000_update_lna(struct dib8000_state * state)1150*4882a593Smuzhiyun static int dib8000_update_lna(struct dib8000_state *state)
1151*4882a593Smuzhiyun {
1152*4882a593Smuzhiyun 	u16 dyn_gain;
1153*4882a593Smuzhiyun 
1154*4882a593Smuzhiyun 	if (state->cfg.update_lna) {
1155*4882a593Smuzhiyun 		// read dyn_gain here (because it is demod-dependent and not tuner)
1156*4882a593Smuzhiyun 		dyn_gain = dib8000_read_word(state, 390);
1157*4882a593Smuzhiyun 
1158*4882a593Smuzhiyun 		if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
1159*4882a593Smuzhiyun 			dib8000_restart_agc(state);
1160*4882a593Smuzhiyun 			return 1;
1161*4882a593Smuzhiyun 		}
1162*4882a593Smuzhiyun 	}
1163*4882a593Smuzhiyun 	return 0;
1164*4882a593Smuzhiyun }
1165*4882a593Smuzhiyun 
dib8000_set_agc_config(struct dib8000_state * state,u8 band)1166*4882a593Smuzhiyun static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
1167*4882a593Smuzhiyun {
1168*4882a593Smuzhiyun 	struct dibx000_agc_config *agc = NULL;
1169*4882a593Smuzhiyun 	int i;
1170*4882a593Smuzhiyun 	u16 reg;
1171*4882a593Smuzhiyun 
1172*4882a593Smuzhiyun 	if (state->current_band == band && state->current_agc != NULL)
1173*4882a593Smuzhiyun 		return 0;
1174*4882a593Smuzhiyun 	state->current_band = band;
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun 	for (i = 0; i < state->cfg.agc_config_count; i++)
1177*4882a593Smuzhiyun 		if (state->cfg.agc[i].band_caps & band) {
1178*4882a593Smuzhiyun 			agc = &state->cfg.agc[i];
1179*4882a593Smuzhiyun 			break;
1180*4882a593Smuzhiyun 		}
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 	if (agc == NULL) {
1183*4882a593Smuzhiyun 		dprintk("no valid AGC configuration found for band 0x%02x\n", band);
1184*4882a593Smuzhiyun 		return -EINVAL;
1185*4882a593Smuzhiyun 	}
1186*4882a593Smuzhiyun 
1187*4882a593Smuzhiyun 	state->current_agc = agc;
1188*4882a593Smuzhiyun 
1189*4882a593Smuzhiyun 	/* AGC */
1190*4882a593Smuzhiyun 	dib8000_write_word(state, 76, agc->setup);
1191*4882a593Smuzhiyun 	dib8000_write_word(state, 77, agc->inv_gain);
1192*4882a593Smuzhiyun 	dib8000_write_word(state, 78, agc->time_stabiliz);
1193*4882a593Smuzhiyun 	dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
1194*4882a593Smuzhiyun 
1195*4882a593Smuzhiyun 	// Demod AGC loop configuration
1196*4882a593Smuzhiyun 	dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
1197*4882a593Smuzhiyun 	dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
1198*4882a593Smuzhiyun 
1199*4882a593Smuzhiyun 	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
1200*4882a593Smuzhiyun 		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 	/* AGC continued */
1203*4882a593Smuzhiyun 	if (state->wbd_ref != 0)
1204*4882a593Smuzhiyun 		dib8000_write_word(state, 106, state->wbd_ref);
1205*4882a593Smuzhiyun 	else			// use default
1206*4882a593Smuzhiyun 		dib8000_write_word(state, 106, agc->wbd_ref);
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	if (state->revision == 0x8090) {
1209*4882a593Smuzhiyun 		reg = dib8000_read_word(state, 922) & (0x3 << 2);
1210*4882a593Smuzhiyun 		dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
1211*4882a593Smuzhiyun 	}
1212*4882a593Smuzhiyun 
1213*4882a593Smuzhiyun 	dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
1214*4882a593Smuzhiyun 	dib8000_write_word(state, 108, agc->agc1_max);
1215*4882a593Smuzhiyun 	dib8000_write_word(state, 109, agc->agc1_min);
1216*4882a593Smuzhiyun 	dib8000_write_word(state, 110, agc->agc2_max);
1217*4882a593Smuzhiyun 	dib8000_write_word(state, 111, agc->agc2_min);
1218*4882a593Smuzhiyun 	dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
1219*4882a593Smuzhiyun 	dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
1220*4882a593Smuzhiyun 	dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
1221*4882a593Smuzhiyun 	dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
1222*4882a593Smuzhiyun 
1223*4882a593Smuzhiyun 	dib8000_write_word(state, 75, agc->agc1_pt3);
1224*4882a593Smuzhiyun 	if (state->revision != 0x8090)
1225*4882a593Smuzhiyun 		dib8000_write_word(state, 923,
1226*4882a593Smuzhiyun 				(dib8000_read_word(state, 923) & 0xffe3) |
1227*4882a593Smuzhiyun 				(agc->wbd_inv << 4) | (agc->wbd_sel << 2));
1228*4882a593Smuzhiyun 
1229*4882a593Smuzhiyun 	return 0;
1230*4882a593Smuzhiyun }
1231*4882a593Smuzhiyun 
dib8000_pwm_agc_reset(struct dvb_frontend * fe)1232*4882a593Smuzhiyun static void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
1233*4882a593Smuzhiyun {
1234*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
1235*4882a593Smuzhiyun 	dib8000_set_adc_state(state, DIBX000_ADC_ON);
1236*4882a593Smuzhiyun 	dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
1237*4882a593Smuzhiyun }
1238*4882a593Smuzhiyun 
dib8000_agc_soft_split(struct dib8000_state * state)1239*4882a593Smuzhiyun static int dib8000_agc_soft_split(struct dib8000_state *state)
1240*4882a593Smuzhiyun {
1241*4882a593Smuzhiyun 	u16 agc, split_offset;
1242*4882a593Smuzhiyun 
1243*4882a593Smuzhiyun 	if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
1244*4882a593Smuzhiyun 		return 0;
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun 	// n_agc_global
1247*4882a593Smuzhiyun 	agc = dib8000_read_word(state, 390);
1248*4882a593Smuzhiyun 
1249*4882a593Smuzhiyun 	if (agc > state->current_agc->split.min_thres)
1250*4882a593Smuzhiyun 		split_offset = state->current_agc->split.min;
1251*4882a593Smuzhiyun 	else if (agc < state->current_agc->split.max_thres)
1252*4882a593Smuzhiyun 		split_offset = state->current_agc->split.max;
1253*4882a593Smuzhiyun 	else
1254*4882a593Smuzhiyun 		split_offset = state->current_agc->split.max *
1255*4882a593Smuzhiyun 			(agc - state->current_agc->split.min_thres) /
1256*4882a593Smuzhiyun 			(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
1257*4882a593Smuzhiyun 
1258*4882a593Smuzhiyun 	dprintk("AGC split_offset: %d\n", split_offset);
1259*4882a593Smuzhiyun 
1260*4882a593Smuzhiyun 	// P_agc_force_split and P_agc_split_offset
1261*4882a593Smuzhiyun 	dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
1262*4882a593Smuzhiyun 	return 5000;
1263*4882a593Smuzhiyun }
1264*4882a593Smuzhiyun 
dib8000_agc_startup(struct dvb_frontend * fe)1265*4882a593Smuzhiyun static int dib8000_agc_startup(struct dvb_frontend *fe)
1266*4882a593Smuzhiyun {
1267*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
1268*4882a593Smuzhiyun 	enum frontend_tune_state *tune_state = &state->tune_state;
1269*4882a593Smuzhiyun 	int ret = 0;
1270*4882a593Smuzhiyun 	u16 reg;
1271*4882a593Smuzhiyun 	u32 upd_demod_gain_period = 0x8000;
1272*4882a593Smuzhiyun 
1273*4882a593Smuzhiyun 	switch (*tune_state) {
1274*4882a593Smuzhiyun 	case CT_AGC_START:
1275*4882a593Smuzhiyun 		// set power-up level: interf+analog+AGC
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun 		if (state->revision != 0x8090)
1278*4882a593Smuzhiyun 			dib8000_set_adc_state(state, DIBX000_ADC_ON);
1279*4882a593Smuzhiyun 		else {
1280*4882a593Smuzhiyun 			dib8000_set_power_mode(state, DIB8000_POWER_ALL);
1281*4882a593Smuzhiyun 
1282*4882a593Smuzhiyun 			reg = dib8000_read_word(state, 1947)&0xff00;
1283*4882a593Smuzhiyun 			dib8000_write_word(state, 1946,
1284*4882a593Smuzhiyun 					upd_demod_gain_period & 0xFFFF);
1285*4882a593Smuzhiyun 			/* bit 14 = enDemodGain */
1286*4882a593Smuzhiyun 			dib8000_write_word(state, 1947, reg | (1<<14) |
1287*4882a593Smuzhiyun 					((upd_demod_gain_period >> 16) & 0xFF));
1288*4882a593Smuzhiyun 
1289*4882a593Smuzhiyun 			/* enable adc i & q */
1290*4882a593Smuzhiyun 			reg = dib8000_read_word(state, 1920);
1291*4882a593Smuzhiyun 			dib8000_write_word(state, 1920, (reg | 0x3) &
1292*4882a593Smuzhiyun 					(~(1 << 7)));
1293*4882a593Smuzhiyun 		}
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun 		if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
1296*4882a593Smuzhiyun 			*tune_state = CT_AGC_STOP;
1297*4882a593Smuzhiyun 			state->status = FE_STATUS_TUNE_FAILED;
1298*4882a593Smuzhiyun 			break;
1299*4882a593Smuzhiyun 		}
1300*4882a593Smuzhiyun 
1301*4882a593Smuzhiyun 		ret = 70;
1302*4882a593Smuzhiyun 		*tune_state = CT_AGC_STEP_0;
1303*4882a593Smuzhiyun 		break;
1304*4882a593Smuzhiyun 
1305*4882a593Smuzhiyun 	case CT_AGC_STEP_0:
1306*4882a593Smuzhiyun 		//AGC initialization
1307*4882a593Smuzhiyun 		if (state->cfg.agc_control)
1308*4882a593Smuzhiyun 			state->cfg.agc_control(fe, 1);
1309*4882a593Smuzhiyun 
1310*4882a593Smuzhiyun 		dib8000_restart_agc(state);
1311*4882a593Smuzhiyun 
1312*4882a593Smuzhiyun 		// wait AGC rough lock time
1313*4882a593Smuzhiyun 		ret = 50;
1314*4882a593Smuzhiyun 		*tune_state = CT_AGC_STEP_1;
1315*4882a593Smuzhiyun 		break;
1316*4882a593Smuzhiyun 
1317*4882a593Smuzhiyun 	case CT_AGC_STEP_1:
1318*4882a593Smuzhiyun 		// wait AGC accurate lock time
1319*4882a593Smuzhiyun 		ret = 70;
1320*4882a593Smuzhiyun 
1321*4882a593Smuzhiyun 		if (dib8000_update_lna(state))
1322*4882a593Smuzhiyun 			// wait only AGC rough lock time
1323*4882a593Smuzhiyun 			ret = 50;
1324*4882a593Smuzhiyun 		else
1325*4882a593Smuzhiyun 			*tune_state = CT_AGC_STEP_2;
1326*4882a593Smuzhiyun 		break;
1327*4882a593Smuzhiyun 
1328*4882a593Smuzhiyun 	case CT_AGC_STEP_2:
1329*4882a593Smuzhiyun 		dib8000_agc_soft_split(state);
1330*4882a593Smuzhiyun 
1331*4882a593Smuzhiyun 		if (state->cfg.agc_control)
1332*4882a593Smuzhiyun 			state->cfg.agc_control(fe, 0);
1333*4882a593Smuzhiyun 
1334*4882a593Smuzhiyun 		*tune_state = CT_AGC_STOP;
1335*4882a593Smuzhiyun 		break;
1336*4882a593Smuzhiyun 	default:
1337*4882a593Smuzhiyun 		ret = dib8000_agc_soft_split(state);
1338*4882a593Smuzhiyun 		break;
1339*4882a593Smuzhiyun 	}
1340*4882a593Smuzhiyun 	return ret;
1341*4882a593Smuzhiyun 
1342*4882a593Smuzhiyun }
1343*4882a593Smuzhiyun 
dib8096p_host_bus_drive(struct dib8000_state * state,u8 drive)1344*4882a593Smuzhiyun static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
1345*4882a593Smuzhiyun {
1346*4882a593Smuzhiyun 	u16 reg;
1347*4882a593Smuzhiyun 
1348*4882a593Smuzhiyun 	drive &= 0x7;
1349*4882a593Smuzhiyun 
1350*4882a593Smuzhiyun 	/* drive host bus 2, 3, 4 */
1351*4882a593Smuzhiyun 	reg = dib8000_read_word(state, 1798) &
1352*4882a593Smuzhiyun 		~(0x7 | (0x7 << 6) | (0x7 << 12));
1353*4882a593Smuzhiyun 	reg |= (drive<<12) | (drive<<6) | drive;
1354*4882a593Smuzhiyun 	dib8000_write_word(state, 1798, reg);
1355*4882a593Smuzhiyun 
1356*4882a593Smuzhiyun 	/* drive host bus 5,6 */
1357*4882a593Smuzhiyun 	reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
1358*4882a593Smuzhiyun 	reg |= (drive<<8) | (drive<<2);
1359*4882a593Smuzhiyun 	dib8000_write_word(state, 1799, reg);
1360*4882a593Smuzhiyun 
1361*4882a593Smuzhiyun 	/* drive host bus 7, 8, 9 */
1362*4882a593Smuzhiyun 	reg = dib8000_read_word(state, 1800) &
1363*4882a593Smuzhiyun 		~(0x7 | (0x7 << 6) | (0x7 << 12));
1364*4882a593Smuzhiyun 	reg |= (drive<<12) | (drive<<6) | drive;
1365*4882a593Smuzhiyun 	dib8000_write_word(state, 1800, reg);
1366*4882a593Smuzhiyun 
1367*4882a593Smuzhiyun 	/* drive host bus 10, 11 */
1368*4882a593Smuzhiyun 	reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
1369*4882a593Smuzhiyun 	reg |= (drive<<8) | (drive<<2);
1370*4882a593Smuzhiyun 	dib8000_write_word(state, 1801, reg);
1371*4882a593Smuzhiyun 
1372*4882a593Smuzhiyun 	/* drive host bus 12, 13, 14 */
1373*4882a593Smuzhiyun 	reg = dib8000_read_word(state, 1802) &
1374*4882a593Smuzhiyun 		~(0x7 | (0x7 << 6) | (0x7 << 12));
1375*4882a593Smuzhiyun 	reg |= (drive<<12) | (drive<<6) | drive;
1376*4882a593Smuzhiyun 	dib8000_write_word(state, 1802, reg);
1377*4882a593Smuzhiyun }
1378*4882a593Smuzhiyun 
dib8096p_calcSyncFreq(u32 P_Kin,u32 P_Kout,u32 insertExtSynchro,u32 syncSize)1379*4882a593Smuzhiyun static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
1380*4882a593Smuzhiyun 		u32 insertExtSynchro, u32 syncSize)
1381*4882a593Smuzhiyun {
1382*4882a593Smuzhiyun 	u32 quantif = 3;
1383*4882a593Smuzhiyun 	u32 nom = (insertExtSynchro * P_Kin+syncSize);
1384*4882a593Smuzhiyun 	u32 denom = P_Kout;
1385*4882a593Smuzhiyun 	u32 syncFreq = ((nom << quantif) / denom);
1386*4882a593Smuzhiyun 
1387*4882a593Smuzhiyun 	if ((syncFreq & ((1 << quantif) - 1)) != 0)
1388*4882a593Smuzhiyun 		syncFreq = (syncFreq >> quantif) + 1;
1389*4882a593Smuzhiyun 	else
1390*4882a593Smuzhiyun 		syncFreq = (syncFreq >> quantif);
1391*4882a593Smuzhiyun 
1392*4882a593Smuzhiyun 	if (syncFreq != 0)
1393*4882a593Smuzhiyun 		syncFreq = syncFreq - 1;
1394*4882a593Smuzhiyun 
1395*4882a593Smuzhiyun 	return syncFreq;
1396*4882a593Smuzhiyun }
1397*4882a593Smuzhiyun 
dib8096p_cfg_DibTx(struct dib8000_state * state,u32 P_Kin,u32 P_Kout,u32 insertExtSynchro,u32 synchroMode,u32 syncWord,u32 syncSize)1398*4882a593Smuzhiyun static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
1399*4882a593Smuzhiyun 		u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
1400*4882a593Smuzhiyun 		u32 syncWord, u32 syncSize)
1401*4882a593Smuzhiyun {
1402*4882a593Smuzhiyun 	dprintk("Configure DibStream Tx\n");
1403*4882a593Smuzhiyun 
1404*4882a593Smuzhiyun 	dib8000_write_word(state, 1615, 1);
1405*4882a593Smuzhiyun 	dib8000_write_word(state, 1603, P_Kin);
1406*4882a593Smuzhiyun 	dib8000_write_word(state, 1605, P_Kout);
1407*4882a593Smuzhiyun 	dib8000_write_word(state, 1606, insertExtSynchro);
1408*4882a593Smuzhiyun 	dib8000_write_word(state, 1608, synchroMode);
1409*4882a593Smuzhiyun 	dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
1410*4882a593Smuzhiyun 	dib8000_write_word(state, 1610, syncWord & 0xffff);
1411*4882a593Smuzhiyun 	dib8000_write_word(state, 1612, syncSize);
1412*4882a593Smuzhiyun 	dib8000_write_word(state, 1615, 0);
1413*4882a593Smuzhiyun }
1414*4882a593Smuzhiyun 
dib8096p_cfg_DibRx(struct dib8000_state * state,u32 P_Kin,u32 P_Kout,u32 synchroMode,u32 insertExtSynchro,u32 syncWord,u32 syncSize,u32 dataOutRate)1415*4882a593Smuzhiyun static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
1416*4882a593Smuzhiyun 		u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
1417*4882a593Smuzhiyun 		u32 syncWord, u32 syncSize, u32 dataOutRate)
1418*4882a593Smuzhiyun {
1419*4882a593Smuzhiyun 	u32 syncFreq;
1420*4882a593Smuzhiyun 
1421*4882a593Smuzhiyun 	dprintk("Configure DibStream Rx synchroMode = %d\n", synchroMode);
1422*4882a593Smuzhiyun 
1423*4882a593Smuzhiyun 	if ((P_Kin != 0) && (P_Kout != 0)) {
1424*4882a593Smuzhiyun 		syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
1425*4882a593Smuzhiyun 				insertExtSynchro, syncSize);
1426*4882a593Smuzhiyun 		dib8000_write_word(state, 1542, syncFreq);
1427*4882a593Smuzhiyun 	}
1428*4882a593Smuzhiyun 
1429*4882a593Smuzhiyun 	dib8000_write_word(state, 1554, 1);
1430*4882a593Smuzhiyun 	dib8000_write_word(state, 1536, P_Kin);
1431*4882a593Smuzhiyun 	dib8000_write_word(state, 1537, P_Kout);
1432*4882a593Smuzhiyun 	dib8000_write_word(state, 1539, synchroMode);
1433*4882a593Smuzhiyun 	dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
1434*4882a593Smuzhiyun 	dib8000_write_word(state, 1541, syncWord & 0xffff);
1435*4882a593Smuzhiyun 	dib8000_write_word(state, 1543, syncSize);
1436*4882a593Smuzhiyun 	dib8000_write_word(state, 1544, dataOutRate);
1437*4882a593Smuzhiyun 	dib8000_write_word(state, 1554, 0);
1438*4882a593Smuzhiyun }
1439*4882a593Smuzhiyun 
dib8096p_enMpegMux(struct dib8000_state * state,int onoff)1440*4882a593Smuzhiyun static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
1441*4882a593Smuzhiyun {
1442*4882a593Smuzhiyun 	u16 reg_1287;
1443*4882a593Smuzhiyun 
1444*4882a593Smuzhiyun 	reg_1287 = dib8000_read_word(state, 1287);
1445*4882a593Smuzhiyun 
1446*4882a593Smuzhiyun 	switch (onoff) {
1447*4882a593Smuzhiyun 	case 1:
1448*4882a593Smuzhiyun 			reg_1287 &= ~(1 << 8);
1449*4882a593Smuzhiyun 			break;
1450*4882a593Smuzhiyun 	case 0:
1451*4882a593Smuzhiyun 			reg_1287 |= (1 << 8);
1452*4882a593Smuzhiyun 			break;
1453*4882a593Smuzhiyun 	}
1454*4882a593Smuzhiyun 
1455*4882a593Smuzhiyun 	dib8000_write_word(state, 1287, reg_1287);
1456*4882a593Smuzhiyun }
1457*4882a593Smuzhiyun 
dib8096p_configMpegMux(struct dib8000_state * state,u16 pulseWidth,u16 enSerialMode,u16 enSerialClkDiv2)1458*4882a593Smuzhiyun static void dib8096p_configMpegMux(struct dib8000_state *state,
1459*4882a593Smuzhiyun 		u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
1460*4882a593Smuzhiyun {
1461*4882a593Smuzhiyun 	u16 reg_1287;
1462*4882a593Smuzhiyun 
1463*4882a593Smuzhiyun 	dprintk("Enable Mpeg mux\n");
1464*4882a593Smuzhiyun 
1465*4882a593Smuzhiyun 	dib8096p_enMpegMux(state, 0);
1466*4882a593Smuzhiyun 
1467*4882a593Smuzhiyun 	/* If the input mode is MPEG do not divide the serial clock */
1468*4882a593Smuzhiyun 	if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
1469*4882a593Smuzhiyun 		enSerialClkDiv2 = 0;
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun 	reg_1287 = ((pulseWidth & 0x1f) << 3) |
1472*4882a593Smuzhiyun 		((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
1473*4882a593Smuzhiyun 	dib8000_write_word(state, 1287, reg_1287);
1474*4882a593Smuzhiyun 
1475*4882a593Smuzhiyun 	dib8096p_enMpegMux(state, 1);
1476*4882a593Smuzhiyun }
1477*4882a593Smuzhiyun 
dib8096p_setDibTxMux(struct dib8000_state * state,int mode)1478*4882a593Smuzhiyun static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
1479*4882a593Smuzhiyun {
1480*4882a593Smuzhiyun 	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
1481*4882a593Smuzhiyun 
1482*4882a593Smuzhiyun 	switch (mode) {
1483*4882a593Smuzhiyun 	case MPEG_ON_DIBTX:
1484*4882a593Smuzhiyun 			dprintk("SET MPEG ON DIBSTREAM TX\n");
1485*4882a593Smuzhiyun 			dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
1486*4882a593Smuzhiyun 			reg_1288 |= (1 << 9); break;
1487*4882a593Smuzhiyun 	case DIV_ON_DIBTX:
1488*4882a593Smuzhiyun 			dprintk("SET DIV_OUT ON DIBSTREAM TX\n");
1489*4882a593Smuzhiyun 			dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
1490*4882a593Smuzhiyun 			reg_1288 |= (1 << 8); break;
1491*4882a593Smuzhiyun 	case ADC_ON_DIBTX:
1492*4882a593Smuzhiyun 			dprintk("SET ADC_OUT ON DIBSTREAM TX\n");
1493*4882a593Smuzhiyun 			dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
1494*4882a593Smuzhiyun 			reg_1288 |= (1 << 7); break;
1495*4882a593Smuzhiyun 	default:
1496*4882a593Smuzhiyun 			break;
1497*4882a593Smuzhiyun 	}
1498*4882a593Smuzhiyun 	dib8000_write_word(state, 1288, reg_1288);
1499*4882a593Smuzhiyun }
1500*4882a593Smuzhiyun 
dib8096p_setHostBusMux(struct dib8000_state * state,int mode)1501*4882a593Smuzhiyun static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
1502*4882a593Smuzhiyun {
1503*4882a593Smuzhiyun 	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
1504*4882a593Smuzhiyun 
1505*4882a593Smuzhiyun 	switch (mode) {
1506*4882a593Smuzhiyun 	case DEMOUT_ON_HOSTBUS:
1507*4882a593Smuzhiyun 			dprintk("SET DEM OUT OLD INTERF ON HOST BUS\n");
1508*4882a593Smuzhiyun 			dib8096p_enMpegMux(state, 0);
1509*4882a593Smuzhiyun 			reg_1288 |= (1 << 6);
1510*4882a593Smuzhiyun 			break;
1511*4882a593Smuzhiyun 	case DIBTX_ON_HOSTBUS:
1512*4882a593Smuzhiyun 			dprintk("SET DIBSTREAM TX ON HOST BUS\n");
1513*4882a593Smuzhiyun 			dib8096p_enMpegMux(state, 0);
1514*4882a593Smuzhiyun 			reg_1288 |= (1 << 5);
1515*4882a593Smuzhiyun 			break;
1516*4882a593Smuzhiyun 	case MPEG_ON_HOSTBUS:
1517*4882a593Smuzhiyun 			dprintk("SET MPEG MUX ON HOST BUS\n");
1518*4882a593Smuzhiyun 			reg_1288 |= (1 << 4);
1519*4882a593Smuzhiyun 			break;
1520*4882a593Smuzhiyun 	default:
1521*4882a593Smuzhiyun 			break;
1522*4882a593Smuzhiyun 	}
1523*4882a593Smuzhiyun 	dib8000_write_word(state, 1288, reg_1288);
1524*4882a593Smuzhiyun }
1525*4882a593Smuzhiyun 
dib8096p_set_diversity_in(struct dvb_frontend * fe,int onoff)1526*4882a593Smuzhiyun static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
1527*4882a593Smuzhiyun {
1528*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
1529*4882a593Smuzhiyun 	u16 reg_1287;
1530*4882a593Smuzhiyun 
1531*4882a593Smuzhiyun 	switch (onoff) {
1532*4882a593Smuzhiyun 	case 0: /* only use the internal way - not the diversity input */
1533*4882a593Smuzhiyun 			dprintk("%s mode OFF : by default Enable Mpeg INPUT\n",
1534*4882a593Smuzhiyun 					__func__);
1535*4882a593Smuzhiyun 			/* outputRate = 8 */
1536*4882a593Smuzhiyun 			dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
1537*4882a593Smuzhiyun 
1538*4882a593Smuzhiyun 			/* Do not divide the serial clock of MPEG MUX in
1539*4882a593Smuzhiyun 			   SERIAL MODE in case input mode MPEG is used */
1540*4882a593Smuzhiyun 			reg_1287 = dib8000_read_word(state, 1287);
1541*4882a593Smuzhiyun 			/* enSerialClkDiv2 == 1 ? */
1542*4882a593Smuzhiyun 			if ((reg_1287 & 0x1) == 1) {
1543*4882a593Smuzhiyun 				/* force enSerialClkDiv2 = 0 */
1544*4882a593Smuzhiyun 				reg_1287 &= ~0x1;
1545*4882a593Smuzhiyun 				dib8000_write_word(state, 1287, reg_1287);
1546*4882a593Smuzhiyun 			}
1547*4882a593Smuzhiyun 			state->input_mode_mpeg = 1;
1548*4882a593Smuzhiyun 			break;
1549*4882a593Smuzhiyun 	case 1: /* both ways */
1550*4882a593Smuzhiyun 	case 2: /* only the diversity input */
1551*4882a593Smuzhiyun 			dprintk("%s ON : Enable diversity INPUT\n", __func__);
1552*4882a593Smuzhiyun 			dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
1553*4882a593Smuzhiyun 			state->input_mode_mpeg = 0;
1554*4882a593Smuzhiyun 			break;
1555*4882a593Smuzhiyun 	}
1556*4882a593Smuzhiyun 
1557*4882a593Smuzhiyun 	dib8000_set_diversity_in(state->fe[0], onoff);
1558*4882a593Smuzhiyun 	return 0;
1559*4882a593Smuzhiyun }
1560*4882a593Smuzhiyun 
dib8096p_set_output_mode(struct dvb_frontend * fe,int mode)1561*4882a593Smuzhiyun static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
1562*4882a593Smuzhiyun {
1563*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
1564*4882a593Smuzhiyun 	u16 outreg, smo_mode, fifo_threshold;
1565*4882a593Smuzhiyun 	u8 prefer_mpeg_mux_use = 1;
1566*4882a593Smuzhiyun 	int ret = 0;
1567*4882a593Smuzhiyun 
1568*4882a593Smuzhiyun 	state->output_mode = mode;
1569*4882a593Smuzhiyun 	dib8096p_host_bus_drive(state, 1);
1570*4882a593Smuzhiyun 
1571*4882a593Smuzhiyun 	fifo_threshold = 1792;
1572*4882a593Smuzhiyun 	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
1573*4882a593Smuzhiyun 	outreg   = dib8000_read_word(state, 1286) &
1574*4882a593Smuzhiyun 		~((1 << 10) | (0x7 << 6) | (1 << 1));
1575*4882a593Smuzhiyun 
1576*4882a593Smuzhiyun 	switch (mode) {
1577*4882a593Smuzhiyun 	case OUTMODE_HIGH_Z:
1578*4882a593Smuzhiyun 			outreg = 0;
1579*4882a593Smuzhiyun 			break;
1580*4882a593Smuzhiyun 
1581*4882a593Smuzhiyun 	case OUTMODE_MPEG2_SERIAL:
1582*4882a593Smuzhiyun 			if (prefer_mpeg_mux_use) {
1583*4882a593Smuzhiyun 				dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux\n");
1584*4882a593Smuzhiyun 				dib8096p_configMpegMux(state, 3, 1, 1);
1585*4882a593Smuzhiyun 				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
1586*4882a593Smuzhiyun 			} else {/* Use Smooth block */
1587*4882a593Smuzhiyun 				dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc\n");
1588*4882a593Smuzhiyun 				dib8096p_setHostBusMux(state,
1589*4882a593Smuzhiyun 						DEMOUT_ON_HOSTBUS);
1590*4882a593Smuzhiyun 				outreg |= (2 << 6) | (0 << 1);
1591*4882a593Smuzhiyun 			}
1592*4882a593Smuzhiyun 			break;
1593*4882a593Smuzhiyun 
1594*4882a593Smuzhiyun 	case OUTMODE_MPEG2_PAR_GATED_CLK:
1595*4882a593Smuzhiyun 			if (prefer_mpeg_mux_use) {
1596*4882a593Smuzhiyun 				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux\n");
1597*4882a593Smuzhiyun 				dib8096p_configMpegMux(state, 2, 0, 0);
1598*4882a593Smuzhiyun 				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
1599*4882a593Smuzhiyun 			} else { /* Use Smooth block */
1600*4882a593Smuzhiyun 				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block\n");
1601*4882a593Smuzhiyun 				dib8096p_setHostBusMux(state,
1602*4882a593Smuzhiyun 						DEMOUT_ON_HOSTBUS);
1603*4882a593Smuzhiyun 				outreg |= (0 << 6);
1604*4882a593Smuzhiyun 			}
1605*4882a593Smuzhiyun 			break;
1606*4882a593Smuzhiyun 
1607*4882a593Smuzhiyun 	case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
1608*4882a593Smuzhiyun 			dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block\n");
1609*4882a593Smuzhiyun 			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
1610*4882a593Smuzhiyun 			outreg |= (1 << 6);
1611*4882a593Smuzhiyun 			break;
1612*4882a593Smuzhiyun 
1613*4882a593Smuzhiyun 	case OUTMODE_MPEG2_FIFO:
1614*4882a593Smuzhiyun 			/* Using Smooth block because not supported
1615*4882a593Smuzhiyun 			   by new Mpeg Mux bloc */
1616*4882a593Smuzhiyun 			dprintk("dib8096P setting output mode TS_FIFO using Smooth block\n");
1617*4882a593Smuzhiyun 			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
1618*4882a593Smuzhiyun 			outreg |= (5 << 6);
1619*4882a593Smuzhiyun 			smo_mode |= (3 << 1);
1620*4882a593Smuzhiyun 			fifo_threshold = 512;
1621*4882a593Smuzhiyun 			break;
1622*4882a593Smuzhiyun 
1623*4882a593Smuzhiyun 	case OUTMODE_DIVERSITY:
1624*4882a593Smuzhiyun 			dprintk("dib8096P setting output mode MODE_DIVERSITY\n");
1625*4882a593Smuzhiyun 			dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
1626*4882a593Smuzhiyun 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1627*4882a593Smuzhiyun 			break;
1628*4882a593Smuzhiyun 
1629*4882a593Smuzhiyun 	case OUTMODE_ANALOG_ADC:
1630*4882a593Smuzhiyun 			dprintk("dib8096P setting output mode MODE_ANALOG_ADC\n");
1631*4882a593Smuzhiyun 			dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
1632*4882a593Smuzhiyun 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1633*4882a593Smuzhiyun 			break;
1634*4882a593Smuzhiyun 	}
1635*4882a593Smuzhiyun 
1636*4882a593Smuzhiyun 	if (mode != OUTMODE_HIGH_Z)
1637*4882a593Smuzhiyun 		outreg |= (1<<10);
1638*4882a593Smuzhiyun 
1639*4882a593Smuzhiyun 	dprintk("output_mpeg2_in_188_bytes = %d\n",
1640*4882a593Smuzhiyun 			state->cfg.output_mpeg2_in_188_bytes);
1641*4882a593Smuzhiyun 	if (state->cfg.output_mpeg2_in_188_bytes)
1642*4882a593Smuzhiyun 		smo_mode |= (1 << 5);
1643*4882a593Smuzhiyun 
1644*4882a593Smuzhiyun 	ret |= dib8000_write_word(state, 299, smo_mode);
1645*4882a593Smuzhiyun 	/* synchronous fread */
1646*4882a593Smuzhiyun 	ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
1647*4882a593Smuzhiyun 	ret |= dib8000_write_word(state, 1286, outreg);
1648*4882a593Smuzhiyun 
1649*4882a593Smuzhiyun 	return ret;
1650*4882a593Smuzhiyun }
1651*4882a593Smuzhiyun 
map_addr_to_serpar_number(struct i2c_msg * msg)1652*4882a593Smuzhiyun static int map_addr_to_serpar_number(struct i2c_msg *msg)
1653*4882a593Smuzhiyun {
1654*4882a593Smuzhiyun 	if (msg->buf[0] <= 15)
1655*4882a593Smuzhiyun 		msg->buf[0] -= 1;
1656*4882a593Smuzhiyun 	else if (msg->buf[0] == 17)
1657*4882a593Smuzhiyun 		msg->buf[0] = 15;
1658*4882a593Smuzhiyun 	else if (msg->buf[0] == 16)
1659*4882a593Smuzhiyun 		msg->buf[0] = 17;
1660*4882a593Smuzhiyun 	else if (msg->buf[0] == 19)
1661*4882a593Smuzhiyun 		msg->buf[0] = 16;
1662*4882a593Smuzhiyun 	else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
1663*4882a593Smuzhiyun 		msg->buf[0] -= 3;
1664*4882a593Smuzhiyun 	else if (msg->buf[0] == 28)
1665*4882a593Smuzhiyun 		msg->buf[0] = 23;
1666*4882a593Smuzhiyun 	else if (msg->buf[0] == 99)
1667*4882a593Smuzhiyun 		msg->buf[0] = 99;
1668*4882a593Smuzhiyun 	else
1669*4882a593Smuzhiyun 		return -EINVAL;
1670*4882a593Smuzhiyun 	return 0;
1671*4882a593Smuzhiyun }
1672*4882a593Smuzhiyun 
dib8096p_tuner_write_serpar(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num)1673*4882a593Smuzhiyun static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
1674*4882a593Smuzhiyun 		struct i2c_msg msg[], int num)
1675*4882a593Smuzhiyun {
1676*4882a593Smuzhiyun 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1677*4882a593Smuzhiyun 	u8 n_overflow = 1;
1678*4882a593Smuzhiyun 	u16 i = 1000;
1679*4882a593Smuzhiyun 	u16 serpar_num = msg[0].buf[0];
1680*4882a593Smuzhiyun 
1681*4882a593Smuzhiyun 	while (n_overflow == 1 && i) {
1682*4882a593Smuzhiyun 		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
1683*4882a593Smuzhiyun 		i--;
1684*4882a593Smuzhiyun 		if (i == 0)
1685*4882a593Smuzhiyun 			dprintk("Tuner ITF: write busy (overflow)\n");
1686*4882a593Smuzhiyun 	}
1687*4882a593Smuzhiyun 	dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
1688*4882a593Smuzhiyun 	dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
1689*4882a593Smuzhiyun 
1690*4882a593Smuzhiyun 	return num;
1691*4882a593Smuzhiyun }
1692*4882a593Smuzhiyun 
dib8096p_tuner_read_serpar(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num)1693*4882a593Smuzhiyun static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
1694*4882a593Smuzhiyun 		struct i2c_msg msg[], int num)
1695*4882a593Smuzhiyun {
1696*4882a593Smuzhiyun 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1697*4882a593Smuzhiyun 	u8 n_overflow = 1, n_empty = 1;
1698*4882a593Smuzhiyun 	u16 i = 1000;
1699*4882a593Smuzhiyun 	u16 serpar_num = msg[0].buf[0];
1700*4882a593Smuzhiyun 	u16 read_word;
1701*4882a593Smuzhiyun 
1702*4882a593Smuzhiyun 	while (n_overflow == 1 && i) {
1703*4882a593Smuzhiyun 		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
1704*4882a593Smuzhiyun 		i--;
1705*4882a593Smuzhiyun 		if (i == 0)
1706*4882a593Smuzhiyun 			dprintk("TunerITF: read busy (overflow)\n");
1707*4882a593Smuzhiyun 	}
1708*4882a593Smuzhiyun 	dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
1709*4882a593Smuzhiyun 
1710*4882a593Smuzhiyun 	i = 1000;
1711*4882a593Smuzhiyun 	while (n_empty == 1 && i) {
1712*4882a593Smuzhiyun 		n_empty = dib8000_read_word(state, 1984)&0x1;
1713*4882a593Smuzhiyun 		i--;
1714*4882a593Smuzhiyun 		if (i == 0)
1715*4882a593Smuzhiyun 			dprintk("TunerITF: read busy (empty)\n");
1716*4882a593Smuzhiyun 	}
1717*4882a593Smuzhiyun 
1718*4882a593Smuzhiyun 	read_word = dib8000_read_word(state, 1987);
1719*4882a593Smuzhiyun 	msg[1].buf[0] = (read_word >> 8) & 0xff;
1720*4882a593Smuzhiyun 	msg[1].buf[1] = (read_word) & 0xff;
1721*4882a593Smuzhiyun 
1722*4882a593Smuzhiyun 	return num;
1723*4882a593Smuzhiyun }
1724*4882a593Smuzhiyun 
dib8096p_tuner_rw_serpar(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num)1725*4882a593Smuzhiyun static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
1726*4882a593Smuzhiyun 		struct i2c_msg msg[], int num)
1727*4882a593Smuzhiyun {
1728*4882a593Smuzhiyun 	if (map_addr_to_serpar_number(&msg[0]) == 0) {
1729*4882a593Smuzhiyun 		if (num == 1) /* write */
1730*4882a593Smuzhiyun 			return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
1731*4882a593Smuzhiyun 		else /* read */
1732*4882a593Smuzhiyun 			return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
1733*4882a593Smuzhiyun 	}
1734*4882a593Smuzhiyun 	return num;
1735*4882a593Smuzhiyun }
1736*4882a593Smuzhiyun 
dib8096p_rw_on_apb(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num,u16 apb_address)1737*4882a593Smuzhiyun static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
1738*4882a593Smuzhiyun 		struct i2c_msg msg[], int num, u16 apb_address)
1739*4882a593Smuzhiyun {
1740*4882a593Smuzhiyun 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1741*4882a593Smuzhiyun 	u16 word;
1742*4882a593Smuzhiyun 
1743*4882a593Smuzhiyun 	if (num == 1) {		/* write */
1744*4882a593Smuzhiyun 		dib8000_write_word(state, apb_address,
1745*4882a593Smuzhiyun 				((msg[0].buf[1] << 8) | (msg[0].buf[2])));
1746*4882a593Smuzhiyun 	} else {
1747*4882a593Smuzhiyun 		word = dib8000_read_word(state, apb_address);
1748*4882a593Smuzhiyun 		msg[1].buf[0] = (word >> 8) & 0xff;
1749*4882a593Smuzhiyun 		msg[1].buf[1] = (word) & 0xff;
1750*4882a593Smuzhiyun 	}
1751*4882a593Smuzhiyun 	return num;
1752*4882a593Smuzhiyun }
1753*4882a593Smuzhiyun 
dib8096p_tuner_xfer(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num)1754*4882a593Smuzhiyun static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
1755*4882a593Smuzhiyun 		struct i2c_msg msg[], int num)
1756*4882a593Smuzhiyun {
1757*4882a593Smuzhiyun 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1758*4882a593Smuzhiyun 	u16 apb_address = 0, word;
1759*4882a593Smuzhiyun 	int i = 0;
1760*4882a593Smuzhiyun 
1761*4882a593Smuzhiyun 	switch (msg[0].buf[0]) {
1762*4882a593Smuzhiyun 	case 0x12:
1763*4882a593Smuzhiyun 			apb_address = 1920;
1764*4882a593Smuzhiyun 			break;
1765*4882a593Smuzhiyun 	case 0x14:
1766*4882a593Smuzhiyun 			apb_address = 1921;
1767*4882a593Smuzhiyun 			break;
1768*4882a593Smuzhiyun 	case 0x24:
1769*4882a593Smuzhiyun 			apb_address = 1922;
1770*4882a593Smuzhiyun 			break;
1771*4882a593Smuzhiyun 	case 0x1a:
1772*4882a593Smuzhiyun 			apb_address = 1923;
1773*4882a593Smuzhiyun 			break;
1774*4882a593Smuzhiyun 	case 0x22:
1775*4882a593Smuzhiyun 			apb_address = 1924;
1776*4882a593Smuzhiyun 			break;
1777*4882a593Smuzhiyun 	case 0x33:
1778*4882a593Smuzhiyun 			apb_address = 1926;
1779*4882a593Smuzhiyun 			break;
1780*4882a593Smuzhiyun 	case 0x34:
1781*4882a593Smuzhiyun 			apb_address = 1927;
1782*4882a593Smuzhiyun 			break;
1783*4882a593Smuzhiyun 	case 0x35:
1784*4882a593Smuzhiyun 			apb_address = 1928;
1785*4882a593Smuzhiyun 			break;
1786*4882a593Smuzhiyun 	case 0x36:
1787*4882a593Smuzhiyun 			apb_address = 1929;
1788*4882a593Smuzhiyun 			break;
1789*4882a593Smuzhiyun 	case 0x37:
1790*4882a593Smuzhiyun 			apb_address = 1930;
1791*4882a593Smuzhiyun 			break;
1792*4882a593Smuzhiyun 	case 0x38:
1793*4882a593Smuzhiyun 			apb_address = 1931;
1794*4882a593Smuzhiyun 			break;
1795*4882a593Smuzhiyun 	case 0x39:
1796*4882a593Smuzhiyun 			apb_address = 1932;
1797*4882a593Smuzhiyun 			break;
1798*4882a593Smuzhiyun 	case 0x2a:
1799*4882a593Smuzhiyun 			apb_address = 1935;
1800*4882a593Smuzhiyun 			break;
1801*4882a593Smuzhiyun 	case 0x2b:
1802*4882a593Smuzhiyun 			apb_address = 1936;
1803*4882a593Smuzhiyun 			break;
1804*4882a593Smuzhiyun 	case 0x2c:
1805*4882a593Smuzhiyun 			apb_address = 1937;
1806*4882a593Smuzhiyun 			break;
1807*4882a593Smuzhiyun 	case 0x2d:
1808*4882a593Smuzhiyun 			apb_address = 1938;
1809*4882a593Smuzhiyun 			break;
1810*4882a593Smuzhiyun 	case 0x2e:
1811*4882a593Smuzhiyun 			apb_address = 1939;
1812*4882a593Smuzhiyun 			break;
1813*4882a593Smuzhiyun 	case 0x2f:
1814*4882a593Smuzhiyun 			apb_address = 1940;
1815*4882a593Smuzhiyun 			break;
1816*4882a593Smuzhiyun 	case 0x30:
1817*4882a593Smuzhiyun 			apb_address = 1941;
1818*4882a593Smuzhiyun 			break;
1819*4882a593Smuzhiyun 	case 0x31:
1820*4882a593Smuzhiyun 			apb_address = 1942;
1821*4882a593Smuzhiyun 			break;
1822*4882a593Smuzhiyun 	case 0x32:
1823*4882a593Smuzhiyun 			apb_address = 1943;
1824*4882a593Smuzhiyun 			break;
1825*4882a593Smuzhiyun 	case 0x3e:
1826*4882a593Smuzhiyun 			apb_address = 1944;
1827*4882a593Smuzhiyun 			break;
1828*4882a593Smuzhiyun 	case 0x3f:
1829*4882a593Smuzhiyun 			apb_address = 1945;
1830*4882a593Smuzhiyun 			break;
1831*4882a593Smuzhiyun 	case 0x40:
1832*4882a593Smuzhiyun 			apb_address = 1948;
1833*4882a593Smuzhiyun 			break;
1834*4882a593Smuzhiyun 	case 0x25:
1835*4882a593Smuzhiyun 			apb_address = 936;
1836*4882a593Smuzhiyun 			break;
1837*4882a593Smuzhiyun 	case 0x26:
1838*4882a593Smuzhiyun 			apb_address = 937;
1839*4882a593Smuzhiyun 			break;
1840*4882a593Smuzhiyun 	case 0x27:
1841*4882a593Smuzhiyun 			apb_address = 938;
1842*4882a593Smuzhiyun 			break;
1843*4882a593Smuzhiyun 	case 0x28:
1844*4882a593Smuzhiyun 			apb_address = 939;
1845*4882a593Smuzhiyun 			break;
1846*4882a593Smuzhiyun 	case 0x1d:
1847*4882a593Smuzhiyun 			/* get sad sel request */
1848*4882a593Smuzhiyun 			i = ((dib8000_read_word(state, 921) >> 12)&0x3);
1849*4882a593Smuzhiyun 			word = dib8000_read_word(state, 924+i);
1850*4882a593Smuzhiyun 			msg[1].buf[0] = (word >> 8) & 0xff;
1851*4882a593Smuzhiyun 			msg[1].buf[1] = (word) & 0xff;
1852*4882a593Smuzhiyun 			return num;
1853*4882a593Smuzhiyun 	case 0x1f:
1854*4882a593Smuzhiyun 			if (num == 1) {	/* write */
1855*4882a593Smuzhiyun 				word = (u16) ((msg[0].buf[1] << 8) |
1856*4882a593Smuzhiyun 						msg[0].buf[2]);
1857*4882a593Smuzhiyun 				/* in the VGAMODE Sel are located on bit 0/1 */
1858*4882a593Smuzhiyun 				word &= 0x3;
1859*4882a593Smuzhiyun 				word = (dib8000_read_word(state, 921) &
1860*4882a593Smuzhiyun 						~(3<<12)) | (word<<12);
1861*4882a593Smuzhiyun 				/* Set the proper input */
1862*4882a593Smuzhiyun 				dib8000_write_word(state, 921, word);
1863*4882a593Smuzhiyun 				return num;
1864*4882a593Smuzhiyun 			}
1865*4882a593Smuzhiyun 	}
1866*4882a593Smuzhiyun 
1867*4882a593Smuzhiyun 	if (apb_address != 0) /* R/W access via APB */
1868*4882a593Smuzhiyun 		return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
1869*4882a593Smuzhiyun 	else  /* R/W access via SERPAR  */
1870*4882a593Smuzhiyun 		return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
1871*4882a593Smuzhiyun 
1872*4882a593Smuzhiyun 	return 0;
1873*4882a593Smuzhiyun }
1874*4882a593Smuzhiyun 
dib8096p_i2c_func(struct i2c_adapter * adapter)1875*4882a593Smuzhiyun static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
1876*4882a593Smuzhiyun {
1877*4882a593Smuzhiyun 	return I2C_FUNC_I2C;
1878*4882a593Smuzhiyun }
1879*4882a593Smuzhiyun 
1880*4882a593Smuzhiyun static const struct i2c_algorithm dib8096p_tuner_xfer_algo = {
1881*4882a593Smuzhiyun 	.master_xfer = dib8096p_tuner_xfer,
1882*4882a593Smuzhiyun 	.functionality = dib8096p_i2c_func,
1883*4882a593Smuzhiyun };
1884*4882a593Smuzhiyun 
dib8096p_get_i2c_tuner(struct dvb_frontend * fe)1885*4882a593Smuzhiyun static struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
1886*4882a593Smuzhiyun {
1887*4882a593Smuzhiyun 	struct dib8000_state *st = fe->demodulator_priv;
1888*4882a593Smuzhiyun 	return &st->dib8096p_tuner_adap;
1889*4882a593Smuzhiyun }
1890*4882a593Smuzhiyun 
dib8096p_tuner_sleep(struct dvb_frontend * fe,int onoff)1891*4882a593Smuzhiyun static int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
1892*4882a593Smuzhiyun {
1893*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
1894*4882a593Smuzhiyun 	u16 en_cur_state;
1895*4882a593Smuzhiyun 
1896*4882a593Smuzhiyun 	dprintk("sleep dib8096p: %d\n", onoff);
1897*4882a593Smuzhiyun 
1898*4882a593Smuzhiyun 	en_cur_state = dib8000_read_word(state, 1922);
1899*4882a593Smuzhiyun 
1900*4882a593Smuzhiyun 	/* LNAs and MIX are ON and therefore it is a valid configuration */
1901*4882a593Smuzhiyun 	if (en_cur_state > 0xff)
1902*4882a593Smuzhiyun 		state->tuner_enable = en_cur_state ;
1903*4882a593Smuzhiyun 
1904*4882a593Smuzhiyun 	if (onoff)
1905*4882a593Smuzhiyun 		en_cur_state &= 0x00ff;
1906*4882a593Smuzhiyun 	else {
1907*4882a593Smuzhiyun 		if (state->tuner_enable != 0)
1908*4882a593Smuzhiyun 			en_cur_state = state->tuner_enable;
1909*4882a593Smuzhiyun 	}
1910*4882a593Smuzhiyun 
1911*4882a593Smuzhiyun 	dib8000_write_word(state, 1922, en_cur_state);
1912*4882a593Smuzhiyun 
1913*4882a593Smuzhiyun 	return 0;
1914*4882a593Smuzhiyun }
1915*4882a593Smuzhiyun 
1916*4882a593Smuzhiyun static const s32 lut_1000ln_mant[] =
1917*4882a593Smuzhiyun {
1918*4882a593Smuzhiyun 	908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
1919*4882a593Smuzhiyun };
1920*4882a593Smuzhiyun 
dib8000_get_adc_power(struct dvb_frontend * fe,u8 mode)1921*4882a593Smuzhiyun static s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
1922*4882a593Smuzhiyun {
1923*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
1924*4882a593Smuzhiyun 	u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
1925*4882a593Smuzhiyun 	s32 val;
1926*4882a593Smuzhiyun 
1927*4882a593Smuzhiyun 	val = dib8000_read32(state, 384);
1928*4882a593Smuzhiyun 	if (mode) {
1929*4882a593Smuzhiyun 		tmp_val = val;
1930*4882a593Smuzhiyun 		while (tmp_val >>= 1)
1931*4882a593Smuzhiyun 			exp++;
1932*4882a593Smuzhiyun 		mant = (val * 1000 / (1<<exp));
1933*4882a593Smuzhiyun 		ix = (u8)((mant-1000)/100); /* index of the LUT */
1934*4882a593Smuzhiyun 		val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
1935*4882a593Smuzhiyun 		val = (val*256)/1000;
1936*4882a593Smuzhiyun 	}
1937*4882a593Smuzhiyun 	return val;
1938*4882a593Smuzhiyun }
1939*4882a593Smuzhiyun 
dib8090p_get_dc_power(struct dvb_frontend * fe,u8 IQ)1940*4882a593Smuzhiyun static int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
1941*4882a593Smuzhiyun {
1942*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
1943*4882a593Smuzhiyun 	int val = 0;
1944*4882a593Smuzhiyun 
1945*4882a593Smuzhiyun 	switch (IQ) {
1946*4882a593Smuzhiyun 	case 1:
1947*4882a593Smuzhiyun 			val = dib8000_read_word(state, 403);
1948*4882a593Smuzhiyun 			break;
1949*4882a593Smuzhiyun 	case 0:
1950*4882a593Smuzhiyun 			val = dib8000_read_word(state, 404);
1951*4882a593Smuzhiyun 			break;
1952*4882a593Smuzhiyun 	}
1953*4882a593Smuzhiyun 	if (val  & 0x200)
1954*4882a593Smuzhiyun 		val -= 1024;
1955*4882a593Smuzhiyun 
1956*4882a593Smuzhiyun 	return val;
1957*4882a593Smuzhiyun }
1958*4882a593Smuzhiyun 
dib8000_update_timf(struct dib8000_state * state)1959*4882a593Smuzhiyun static void dib8000_update_timf(struct dib8000_state *state)
1960*4882a593Smuzhiyun {
1961*4882a593Smuzhiyun 	u32 timf = state->timf = dib8000_read32(state, 435);
1962*4882a593Smuzhiyun 
1963*4882a593Smuzhiyun 	dib8000_write_word(state, 29, (u16) (timf >> 16));
1964*4882a593Smuzhiyun 	dib8000_write_word(state, 30, (u16) (timf & 0xffff));
1965*4882a593Smuzhiyun 	dprintk("Updated timing frequency: %d (default: %d)\n", state->timf, state->timf_default);
1966*4882a593Smuzhiyun }
1967*4882a593Smuzhiyun 
dib8000_ctrl_timf(struct dvb_frontend * fe,uint8_t op,uint32_t timf)1968*4882a593Smuzhiyun static u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
1969*4882a593Smuzhiyun {
1970*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
1971*4882a593Smuzhiyun 
1972*4882a593Smuzhiyun 	switch (op) {
1973*4882a593Smuzhiyun 	case DEMOD_TIMF_SET:
1974*4882a593Smuzhiyun 			state->timf = timf;
1975*4882a593Smuzhiyun 			break;
1976*4882a593Smuzhiyun 	case DEMOD_TIMF_UPDATE:
1977*4882a593Smuzhiyun 			dib8000_update_timf(state);
1978*4882a593Smuzhiyun 			break;
1979*4882a593Smuzhiyun 	case DEMOD_TIMF_GET:
1980*4882a593Smuzhiyun 			break;
1981*4882a593Smuzhiyun 	}
1982*4882a593Smuzhiyun 	dib8000_set_bandwidth(state->fe[0], 6000);
1983*4882a593Smuzhiyun 
1984*4882a593Smuzhiyun 	return state->timf;
1985*4882a593Smuzhiyun }
1986*4882a593Smuzhiyun 
1987*4882a593Smuzhiyun static const u16 adc_target_16dB[11] = {
1988*4882a593Smuzhiyun 	7250, 7238, 7264, 7309, 7338, 7382, 7427, 7456, 7500, 7544, 7574
1989*4882a593Smuzhiyun };
1990*4882a593Smuzhiyun 
1991*4882a593Smuzhiyun static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
1992*4882a593Smuzhiyun 
dib8000_set_layer(struct dib8000_state * state,u8 layer_index,u16 max_constellation)1993*4882a593Smuzhiyun static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
1994*4882a593Smuzhiyun {
1995*4882a593Smuzhiyun 	u8  cr, constellation, time_intlv;
1996*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
1997*4882a593Smuzhiyun 
1998*4882a593Smuzhiyun 	switch (c->layer[layer_index].modulation) {
1999*4882a593Smuzhiyun 	case DQPSK:
2000*4882a593Smuzhiyun 			constellation = 0;
2001*4882a593Smuzhiyun 			break;
2002*4882a593Smuzhiyun 	case  QPSK:
2003*4882a593Smuzhiyun 			constellation = 1;
2004*4882a593Smuzhiyun 			break;
2005*4882a593Smuzhiyun 	case QAM_16:
2006*4882a593Smuzhiyun 			constellation = 2;
2007*4882a593Smuzhiyun 			break;
2008*4882a593Smuzhiyun 	case QAM_64:
2009*4882a593Smuzhiyun 	default:
2010*4882a593Smuzhiyun 			constellation = 3;
2011*4882a593Smuzhiyun 			break;
2012*4882a593Smuzhiyun 	}
2013*4882a593Smuzhiyun 
2014*4882a593Smuzhiyun 	switch (c->layer[layer_index].fec) {
2015*4882a593Smuzhiyun 	case FEC_1_2:
2016*4882a593Smuzhiyun 			cr = 1;
2017*4882a593Smuzhiyun 			break;
2018*4882a593Smuzhiyun 	case FEC_2_3:
2019*4882a593Smuzhiyun 			cr = 2;
2020*4882a593Smuzhiyun 			break;
2021*4882a593Smuzhiyun 	case FEC_3_4:
2022*4882a593Smuzhiyun 			cr = 3;
2023*4882a593Smuzhiyun 			break;
2024*4882a593Smuzhiyun 	case FEC_5_6:
2025*4882a593Smuzhiyun 			cr = 5;
2026*4882a593Smuzhiyun 			break;
2027*4882a593Smuzhiyun 	case FEC_7_8:
2028*4882a593Smuzhiyun 	default:
2029*4882a593Smuzhiyun 			cr = 7;
2030*4882a593Smuzhiyun 			break;
2031*4882a593Smuzhiyun 	}
2032*4882a593Smuzhiyun 
2033*4882a593Smuzhiyun 	time_intlv = fls(c->layer[layer_index].interleaving);
2034*4882a593Smuzhiyun 	if (time_intlv > 3 && !(time_intlv == 4 && c->isdbt_sb_mode == 1))
2035*4882a593Smuzhiyun 		time_intlv = 0;
2036*4882a593Smuzhiyun 
2037*4882a593Smuzhiyun 	dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
2038*4882a593Smuzhiyun 	if (c->layer[layer_index].segment_count > 0) {
2039*4882a593Smuzhiyun 		switch (max_constellation) {
2040*4882a593Smuzhiyun 		case DQPSK:
2041*4882a593Smuzhiyun 		case QPSK:
2042*4882a593Smuzhiyun 				if (c->layer[layer_index].modulation == QAM_16 || c->layer[layer_index].modulation == QAM_64)
2043*4882a593Smuzhiyun 					max_constellation = c->layer[layer_index].modulation;
2044*4882a593Smuzhiyun 				break;
2045*4882a593Smuzhiyun 		case QAM_16:
2046*4882a593Smuzhiyun 				if (c->layer[layer_index].modulation == QAM_64)
2047*4882a593Smuzhiyun 					max_constellation = c->layer[layer_index].modulation;
2048*4882a593Smuzhiyun 				break;
2049*4882a593Smuzhiyun 		}
2050*4882a593Smuzhiyun 	}
2051*4882a593Smuzhiyun 
2052*4882a593Smuzhiyun 	return  max_constellation;
2053*4882a593Smuzhiyun }
2054*4882a593Smuzhiyun 
2055*4882a593Smuzhiyun static const u16 adp_Q64[4] = {0x0148, 0xfff0, 0x00a4, 0xfff8}; /* P_adp_regul_cnt 0.04, P_adp_noise_cnt -0.002, P_adp_regul_ext 0.02, P_adp_noise_ext -0.001 */
2056*4882a593Smuzhiyun static const u16 adp_Q16[4] = {0x023d, 0xffdf, 0x00a4, 0xfff0}; /* P_adp_regul_cnt 0.07, P_adp_noise_cnt -0.004, P_adp_regul_ext 0.02, P_adp_noise_ext -0.002 */
2057*4882a593Smuzhiyun static const u16 adp_Qdefault[4] = {0x099a, 0xffae, 0x0333, 0xfff8}; /* P_adp_regul_cnt 0.3,  P_adp_noise_cnt -0.01,  P_adp_regul_ext 0.1,  P_adp_noise_ext -0.002 */
dib8000_adp_fine_tune(struct dib8000_state * state,u16 max_constellation)2058*4882a593Smuzhiyun static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation)
2059*4882a593Smuzhiyun {
2060*4882a593Smuzhiyun 	u16 i, ana_gain = 0;
2061*4882a593Smuzhiyun 	const u16 *adp;
2062*4882a593Smuzhiyun 
2063*4882a593Smuzhiyun 	/* channel estimation fine configuration */
2064*4882a593Smuzhiyun 	switch (max_constellation) {
2065*4882a593Smuzhiyun 	case QAM_64:
2066*4882a593Smuzhiyun 			ana_gain = 0x7;
2067*4882a593Smuzhiyun 			adp = &adp_Q64[0];
2068*4882a593Smuzhiyun 			break;
2069*4882a593Smuzhiyun 	case QAM_16:
2070*4882a593Smuzhiyun 			ana_gain = 0x7;
2071*4882a593Smuzhiyun 			adp = &adp_Q16[0];
2072*4882a593Smuzhiyun 			break;
2073*4882a593Smuzhiyun 	default:
2074*4882a593Smuzhiyun 			ana_gain = 0;
2075*4882a593Smuzhiyun 			adp = &adp_Qdefault[0];
2076*4882a593Smuzhiyun 			break;
2077*4882a593Smuzhiyun 	}
2078*4882a593Smuzhiyun 
2079*4882a593Smuzhiyun 	for (i = 0; i < 4; i++)
2080*4882a593Smuzhiyun 		dib8000_write_word(state, 215 + i, adp[i]);
2081*4882a593Smuzhiyun 
2082*4882a593Smuzhiyun 	return ana_gain;
2083*4882a593Smuzhiyun }
2084*4882a593Smuzhiyun 
dib8000_update_ana_gain(struct dib8000_state * state,u16 ana_gain)2085*4882a593Smuzhiyun static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain)
2086*4882a593Smuzhiyun {
2087*4882a593Smuzhiyun 	u16 i;
2088*4882a593Smuzhiyun 
2089*4882a593Smuzhiyun 	dib8000_write_word(state, 116, ana_gain);
2090*4882a593Smuzhiyun 
2091*4882a593Smuzhiyun 	/* update ADC target depending on ana_gain */
2092*4882a593Smuzhiyun 	if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */
2093*4882a593Smuzhiyun 		for (i = 0; i < 10; i++)
2094*4882a593Smuzhiyun 			dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
2095*4882a593Smuzhiyun 	} else { /* set -22dB ADC target for ana_gain=0 */
2096*4882a593Smuzhiyun 		for (i = 0; i < 10; i++)
2097*4882a593Smuzhiyun 			dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
2098*4882a593Smuzhiyun 	}
2099*4882a593Smuzhiyun }
2100*4882a593Smuzhiyun 
dib8000_load_ana_fe_coefs(struct dib8000_state * state,const s16 * ana_fe)2101*4882a593Smuzhiyun static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
2102*4882a593Smuzhiyun {
2103*4882a593Smuzhiyun 	u16 mode = 0;
2104*4882a593Smuzhiyun 
2105*4882a593Smuzhiyun 	if (state->isdbt_cfg_loaded == 0)
2106*4882a593Smuzhiyun 		for (mode = 0; mode < 24; mode++)
2107*4882a593Smuzhiyun 			dib8000_write_word(state, 117 + mode, ana_fe[mode]);
2108*4882a593Smuzhiyun }
2109*4882a593Smuzhiyun 
2110*4882a593Smuzhiyun static const u16 lut_prbs_2k[13] = {
2111*4882a593Smuzhiyun 	0x423, 0x009, 0x5C7,
2112*4882a593Smuzhiyun 	0x7A6, 0x3D8, 0x527,
2113*4882a593Smuzhiyun 	0x7FF, 0x79B, 0x3D6,
2114*4882a593Smuzhiyun 	0x3A2, 0x53B, 0x2F4,
2115*4882a593Smuzhiyun 	0x213
2116*4882a593Smuzhiyun };
2117*4882a593Smuzhiyun 
2118*4882a593Smuzhiyun static const u16 lut_prbs_4k[13] = {
2119*4882a593Smuzhiyun 	0x208, 0x0C3, 0x7B9,
2120*4882a593Smuzhiyun 	0x423, 0x5C7, 0x3D8,
2121*4882a593Smuzhiyun 	0x7FF, 0x3D6, 0x53B,
2122*4882a593Smuzhiyun 	0x213, 0x029, 0x0D0,
2123*4882a593Smuzhiyun 	0x48E
2124*4882a593Smuzhiyun };
2125*4882a593Smuzhiyun 
2126*4882a593Smuzhiyun static const u16 lut_prbs_8k[13] = {
2127*4882a593Smuzhiyun 	0x740, 0x069, 0x7DD,
2128*4882a593Smuzhiyun 	0x208, 0x7B9, 0x5C7,
2129*4882a593Smuzhiyun 	0x7FF, 0x53B, 0x029,
2130*4882a593Smuzhiyun 	0x48E, 0x4C4, 0x367,
2131*4882a593Smuzhiyun 	0x684
2132*4882a593Smuzhiyun };
2133*4882a593Smuzhiyun 
dib8000_get_init_prbs(struct dib8000_state * state,u16 subchannel)2134*4882a593Smuzhiyun static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
2135*4882a593Smuzhiyun {
2136*4882a593Smuzhiyun 	int sub_channel_prbs_group = 0;
2137*4882a593Smuzhiyun 	int prbs_group;
2138*4882a593Smuzhiyun 
2139*4882a593Smuzhiyun 	sub_channel_prbs_group = subchannel / 3;
2140*4882a593Smuzhiyun 	if (sub_channel_prbs_group >= ARRAY_SIZE(lut_prbs_2k))
2141*4882a593Smuzhiyun 		return 0;
2142*4882a593Smuzhiyun 
2143*4882a593Smuzhiyun 	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
2144*4882a593Smuzhiyun 	case TRANSMISSION_MODE_2K:
2145*4882a593Smuzhiyun 		prbs_group = lut_prbs_2k[sub_channel_prbs_group];
2146*4882a593Smuzhiyun 		break;
2147*4882a593Smuzhiyun 	case TRANSMISSION_MODE_4K:
2148*4882a593Smuzhiyun 		prbs_group =  lut_prbs_4k[sub_channel_prbs_group];
2149*4882a593Smuzhiyun 		break;
2150*4882a593Smuzhiyun 	default:
2151*4882a593Smuzhiyun 	case TRANSMISSION_MODE_8K:
2152*4882a593Smuzhiyun 		prbs_group = lut_prbs_8k[sub_channel_prbs_group];
2153*4882a593Smuzhiyun 	}
2154*4882a593Smuzhiyun 
2155*4882a593Smuzhiyun 	dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x\n",
2156*4882a593Smuzhiyun 		sub_channel_prbs_group, subchannel, prbs_group);
2157*4882a593Smuzhiyun 
2158*4882a593Smuzhiyun 	return prbs_group;
2159*4882a593Smuzhiyun }
2160*4882a593Smuzhiyun 
dib8000_set_13seg_channel(struct dib8000_state * state)2161*4882a593Smuzhiyun static void dib8000_set_13seg_channel(struct dib8000_state *state)
2162*4882a593Smuzhiyun {
2163*4882a593Smuzhiyun 	u16 i;
2164*4882a593Smuzhiyun 	u16 coff_pow = 0x2800;
2165*4882a593Smuzhiyun 
2166*4882a593Smuzhiyun 	state->seg_mask = 0x1fff; /* All 13 segments enabled */
2167*4882a593Smuzhiyun 
2168*4882a593Smuzhiyun 	/* ---- COFF ---- Carloff, the most robust --- */
2169*4882a593Smuzhiyun 	if (state->isdbt_cfg_loaded == 0) {  /* if not Sound Broadcasting mode : put default values for 13 segments */
2170*4882a593Smuzhiyun 		dib8000_write_word(state, 180, (16 << 6) | 9);
2171*4882a593Smuzhiyun 		dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
2172*4882a593Smuzhiyun 		coff_pow = 0x2800;
2173*4882a593Smuzhiyun 		for (i = 0; i < 6; i++)
2174*4882a593Smuzhiyun 			dib8000_write_word(state, 181+i, coff_pow);
2175*4882a593Smuzhiyun 
2176*4882a593Smuzhiyun 		/* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */
2177*4882a593Smuzhiyun 		/* P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1 */
2178*4882a593Smuzhiyun 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
2179*4882a593Smuzhiyun 
2180*4882a593Smuzhiyun 		/* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */
2181*4882a593Smuzhiyun 		dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
2182*4882a593Smuzhiyun 		/* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */
2183*4882a593Smuzhiyun 		dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
2184*4882a593Smuzhiyun 
2185*4882a593Smuzhiyun 		dib8000_write_word(state, 228, 0);  /* default value */
2186*4882a593Smuzhiyun 		dib8000_write_word(state, 265, 31); /* default value */
2187*4882a593Smuzhiyun 		dib8000_write_word(state, 205, 0x200f); /* init value */
2188*4882a593Smuzhiyun 	}
2189*4882a593Smuzhiyun 
2190*4882a593Smuzhiyun 	/*
2191*4882a593Smuzhiyun 	 * make the cpil_coff_lock more robust but slower p_coff_winlen
2192*4882a593Smuzhiyun 	 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2193*4882a593Smuzhiyun 	 */
2194*4882a593Smuzhiyun 
2195*4882a593Smuzhiyun 	if (state->cfg.pll->ifreq == 0)
2196*4882a593Smuzhiyun 		dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
2197*4882a593Smuzhiyun 
2198*4882a593Smuzhiyun 	dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg);
2199*4882a593Smuzhiyun }
2200*4882a593Smuzhiyun 
dib8000_set_subchannel_prbs(struct dib8000_state * state,u16 init_prbs)2201*4882a593Smuzhiyun static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs)
2202*4882a593Smuzhiyun {
2203*4882a593Smuzhiyun 	u16 reg_1;
2204*4882a593Smuzhiyun 
2205*4882a593Smuzhiyun 	reg_1 = dib8000_read_word(state, 1);
2206*4882a593Smuzhiyun 	dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */
2207*4882a593Smuzhiyun }
2208*4882a593Smuzhiyun 
dib8000_small_fine_tune(struct dib8000_state * state)2209*4882a593Smuzhiyun static void dib8000_small_fine_tune(struct dib8000_state *state)
2210*4882a593Smuzhiyun {
2211*4882a593Smuzhiyun 	u16 i;
2212*4882a593Smuzhiyun 	const s16 *ncoeff;
2213*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2214*4882a593Smuzhiyun 
2215*4882a593Smuzhiyun 	dib8000_write_word(state, 352, state->seg_diff_mask);
2216*4882a593Smuzhiyun 	dib8000_write_word(state, 353, state->seg_mask);
2217*4882a593Smuzhiyun 
2218*4882a593Smuzhiyun 	/* P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 */
2219*4882a593Smuzhiyun 	dib8000_write_word(state, 351, (c->isdbt_sb_mode << 9) | (c->isdbt_sb_mode << 8) | (13 << 4) | 5);
2220*4882a593Smuzhiyun 
2221*4882a593Smuzhiyun 	if (c->isdbt_sb_mode) {
2222*4882a593Smuzhiyun 		/* ---- SMALL ---- */
2223*4882a593Smuzhiyun 		switch (c->transmission_mode) {
2224*4882a593Smuzhiyun 		case TRANSMISSION_MODE_2K:
2225*4882a593Smuzhiyun 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2226*4882a593Smuzhiyun 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2227*4882a593Smuzhiyun 						ncoeff = coeff_2k_sb_1seg_dqpsk;
2228*4882a593Smuzhiyun 					else /* QPSK or QAM */
2229*4882a593Smuzhiyun 						ncoeff = coeff_2k_sb_1seg;
2230*4882a593Smuzhiyun 				} else { /* 3-segments */
2231*4882a593Smuzhiyun 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2232*4882a593Smuzhiyun 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2233*4882a593Smuzhiyun 							ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
2234*4882a593Smuzhiyun 						else /* QPSK or QAM on external segments */
2235*4882a593Smuzhiyun 							ncoeff = coeff_2k_sb_3seg_0dqpsk;
2236*4882a593Smuzhiyun 					} else { /* QPSK or QAM on central segment */
2237*4882a593Smuzhiyun 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2238*4882a593Smuzhiyun 							ncoeff = coeff_2k_sb_3seg_1dqpsk;
2239*4882a593Smuzhiyun 						else /* QPSK or QAM on external segments */
2240*4882a593Smuzhiyun 							ncoeff = coeff_2k_sb_3seg;
2241*4882a593Smuzhiyun 					}
2242*4882a593Smuzhiyun 				}
2243*4882a593Smuzhiyun 				break;
2244*4882a593Smuzhiyun 		case TRANSMISSION_MODE_4K:
2245*4882a593Smuzhiyun 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2246*4882a593Smuzhiyun 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2247*4882a593Smuzhiyun 						ncoeff = coeff_4k_sb_1seg_dqpsk;
2248*4882a593Smuzhiyun 					else /* QPSK or QAM */
2249*4882a593Smuzhiyun 						ncoeff = coeff_4k_sb_1seg;
2250*4882a593Smuzhiyun 				} else { /* 3-segments */
2251*4882a593Smuzhiyun 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2252*4882a593Smuzhiyun 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2253*4882a593Smuzhiyun 							ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
2254*4882a593Smuzhiyun 						else /* QPSK or QAM on external segments */
2255*4882a593Smuzhiyun 							ncoeff = coeff_4k_sb_3seg_0dqpsk;
2256*4882a593Smuzhiyun 					} else { /* QPSK or QAM on central segment */
2257*4882a593Smuzhiyun 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2258*4882a593Smuzhiyun 							ncoeff = coeff_4k_sb_3seg_1dqpsk;
2259*4882a593Smuzhiyun 						else /* QPSK or QAM on external segments */
2260*4882a593Smuzhiyun 							ncoeff = coeff_4k_sb_3seg;
2261*4882a593Smuzhiyun 					}
2262*4882a593Smuzhiyun 				}
2263*4882a593Smuzhiyun 				break;
2264*4882a593Smuzhiyun 		case TRANSMISSION_MODE_AUTO:
2265*4882a593Smuzhiyun 		case TRANSMISSION_MODE_8K:
2266*4882a593Smuzhiyun 		default:
2267*4882a593Smuzhiyun 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2268*4882a593Smuzhiyun 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2269*4882a593Smuzhiyun 						ncoeff = coeff_8k_sb_1seg_dqpsk;
2270*4882a593Smuzhiyun 					else /* QPSK or QAM */
2271*4882a593Smuzhiyun 						ncoeff = coeff_8k_sb_1seg;
2272*4882a593Smuzhiyun 				} else { /* 3-segments */
2273*4882a593Smuzhiyun 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2274*4882a593Smuzhiyun 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2275*4882a593Smuzhiyun 							ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
2276*4882a593Smuzhiyun 						else /* QPSK or QAM on external segments */
2277*4882a593Smuzhiyun 							ncoeff = coeff_8k_sb_3seg_0dqpsk;
2278*4882a593Smuzhiyun 					} else { /* QPSK or QAM on central segment */
2279*4882a593Smuzhiyun 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2280*4882a593Smuzhiyun 							ncoeff = coeff_8k_sb_3seg_1dqpsk;
2281*4882a593Smuzhiyun 						else /* QPSK or QAM on external segments */
2282*4882a593Smuzhiyun 							ncoeff = coeff_8k_sb_3seg;
2283*4882a593Smuzhiyun 					}
2284*4882a593Smuzhiyun 				}
2285*4882a593Smuzhiyun 				break;
2286*4882a593Smuzhiyun 		}
2287*4882a593Smuzhiyun 
2288*4882a593Smuzhiyun 		for (i = 0; i < 8; i++)
2289*4882a593Smuzhiyun 			dib8000_write_word(state, 343 + i, ncoeff[i]);
2290*4882a593Smuzhiyun 	}
2291*4882a593Smuzhiyun }
2292*4882a593Smuzhiyun 
2293*4882a593Smuzhiyun static const u16 coff_thres_1seg[3] = {300, 150, 80};
2294*4882a593Smuzhiyun static const u16 coff_thres_3seg[3] = {350, 300, 250};
dib8000_set_sb_channel(struct dib8000_state * state)2295*4882a593Smuzhiyun static void dib8000_set_sb_channel(struct dib8000_state *state)
2296*4882a593Smuzhiyun {
2297*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2298*4882a593Smuzhiyun 	const u16 *coff;
2299*4882a593Smuzhiyun 	u16 i;
2300*4882a593Smuzhiyun 
2301*4882a593Smuzhiyun 	if (c->transmission_mode == TRANSMISSION_MODE_2K || c->transmission_mode == TRANSMISSION_MODE_4K) {
2302*4882a593Smuzhiyun 		dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */
2303*4882a593Smuzhiyun 		dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */
2304*4882a593Smuzhiyun 	} else {
2305*4882a593Smuzhiyun 		dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */
2306*4882a593Smuzhiyun 		dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */
2307*4882a593Smuzhiyun 	}
2308*4882a593Smuzhiyun 
2309*4882a593Smuzhiyun 	if (c->isdbt_partial_reception == 1) /* 3-segments */
2310*4882a593Smuzhiyun 		state->seg_mask = 0x00E0;
2311*4882a593Smuzhiyun 	else /* 1-segment */
2312*4882a593Smuzhiyun 		state->seg_mask = 0x0040;
2313*4882a593Smuzhiyun 
2314*4882a593Smuzhiyun 	dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2315*4882a593Smuzhiyun 
2316*4882a593Smuzhiyun 	/* ---- COFF ---- Carloff, the most robust --- */
2317*4882a593Smuzhiyun 	/* P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64, P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1 */
2318*4882a593Smuzhiyun 	dib8000_write_word(state, 187, (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~c->isdbt_partial_reception & 1) << 2) | 0x3);
2319*4882a593Smuzhiyun 
2320*4882a593Smuzhiyun 	dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */
2321*4882a593Smuzhiyun 	dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));/* P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 */
2322*4882a593Smuzhiyun 
2323*4882a593Smuzhiyun 	/* Sound Broadcasting mode 1 seg */
2324*4882a593Smuzhiyun 	if (c->isdbt_partial_reception == 0) {
2325*4882a593Smuzhiyun 		/* P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width = (P_mode == 3) , P_coff_one_seg_sym = (P_mode-1) */
2326*4882a593Smuzhiyun 		if (state->mode == 3)
2327*4882a593Smuzhiyun 			dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14));
2328*4882a593Smuzhiyun 		else
2329*4882a593Smuzhiyun 			dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14));
2330*4882a593Smuzhiyun 
2331*4882a593Smuzhiyun 		/* P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4 */
2332*4882a593Smuzhiyun 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
2333*4882a593Smuzhiyun 		coff = &coff_thres_1seg[0];
2334*4882a593Smuzhiyun 	} else {   /* Sound Broadcasting mode 3 seg */
2335*4882a593Smuzhiyun 		dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
2336*4882a593Smuzhiyun 		/* P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4 */
2337*4882a593Smuzhiyun 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
2338*4882a593Smuzhiyun 		coff = &coff_thres_3seg[0];
2339*4882a593Smuzhiyun 	}
2340*4882a593Smuzhiyun 
2341*4882a593Smuzhiyun 	dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */
2342*4882a593Smuzhiyun 	dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */
2343*4882a593Smuzhiyun 
2344*4882a593Smuzhiyun 	if (c->isdbt_partial_reception == 0 && c->transmission_mode == TRANSMISSION_MODE_2K)
2345*4882a593Smuzhiyun 		dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */
2346*4882a593Smuzhiyun 
2347*4882a593Smuzhiyun 	/* Write COFF thres */
2348*4882a593Smuzhiyun 	for (i = 0 ; i < 3; i++) {
2349*4882a593Smuzhiyun 		dib8000_write_word(state, 181+i, coff[i]);
2350*4882a593Smuzhiyun 		dib8000_write_word(state, 184+i, coff[i]);
2351*4882a593Smuzhiyun 	}
2352*4882a593Smuzhiyun 
2353*4882a593Smuzhiyun 	/*
2354*4882a593Smuzhiyun 	 * make the cpil_coff_lock more robust but slower p_coff_winlen
2355*4882a593Smuzhiyun 	 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2356*4882a593Smuzhiyun 	 */
2357*4882a593Smuzhiyun 
2358*4882a593Smuzhiyun 	dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */
2359*4882a593Smuzhiyun 
2360*4882a593Smuzhiyun 	if (c->isdbt_partial_reception == 0)
2361*4882a593Smuzhiyun 		dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */
2362*4882a593Smuzhiyun 	else
2363*4882a593Smuzhiyun 		dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2364*4882a593Smuzhiyun }
2365*4882a593Smuzhiyun 
dib8000_set_isdbt_common_channel(struct dib8000_state * state,u8 seq,u8 autosearching)2366*4882a593Smuzhiyun static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
2367*4882a593Smuzhiyun {
2368*4882a593Smuzhiyun 	u16 p_cfr_left_edge  = 0, p_cfr_right_edge = 0;
2369*4882a593Smuzhiyun 	u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ;
2370*4882a593Smuzhiyun 	u16 max_constellation = DQPSK;
2371*4882a593Smuzhiyun 	int init_prbs;
2372*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2373*4882a593Smuzhiyun 
2374*4882a593Smuzhiyun 	if (autosearching)
2375*4882a593Smuzhiyun 		c->isdbt_partial_reception = 1;
2376*4882a593Smuzhiyun 
2377*4882a593Smuzhiyun 	/* P_mode */
2378*4882a593Smuzhiyun 	dib8000_write_word(state, 10, (seq << 4));
2379*4882a593Smuzhiyun 
2380*4882a593Smuzhiyun 	/* init mode */
2381*4882a593Smuzhiyun 	state->mode = fft_to_mode(state);
2382*4882a593Smuzhiyun 
2383*4882a593Smuzhiyun 	/* set guard */
2384*4882a593Smuzhiyun 	tmp = dib8000_read_word(state, 1);
2385*4882a593Smuzhiyun 	dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3));
2386*4882a593Smuzhiyun 
2387*4882a593Smuzhiyun 	dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) | ((c->isdbt_partial_reception & 1) << 5) | ((c->isdbt_sb_mode & 1) << 4));
2388*4882a593Smuzhiyun 
2389*4882a593Smuzhiyun 	/* signal optimization parameter */
2390*4882a593Smuzhiyun 	if (c->isdbt_partial_reception) {
2391*4882a593Smuzhiyun 		state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0];
2392*4882a593Smuzhiyun 		for (i = 1; i < 3; i++)
2393*4882a593Smuzhiyun 			nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
2394*4882a593Smuzhiyun 		for (i = 0; i < nbseg_diff; i++)
2395*4882a593Smuzhiyun 			state->seg_diff_mask |= 1 << permu_seg[i+1];
2396*4882a593Smuzhiyun 	} else {
2397*4882a593Smuzhiyun 		for (i = 0; i < 3; i++)
2398*4882a593Smuzhiyun 			nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
2399*4882a593Smuzhiyun 		for (i = 0; i < nbseg_diff; i++)
2400*4882a593Smuzhiyun 			state->seg_diff_mask |= 1 << permu_seg[i];
2401*4882a593Smuzhiyun 	}
2402*4882a593Smuzhiyun 
2403*4882a593Smuzhiyun 	if (state->seg_diff_mask)
2404*4882a593Smuzhiyun 		dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2405*4882a593Smuzhiyun 	else
2406*4882a593Smuzhiyun 		dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */
2407*4882a593Smuzhiyun 
2408*4882a593Smuzhiyun 	for (i = 0; i < 3; i++)
2409*4882a593Smuzhiyun 		max_constellation = dib8000_set_layer(state, i, max_constellation);
2410*4882a593Smuzhiyun 	if (autosearching == 0) {
2411*4882a593Smuzhiyun 		state->layer_b_nb_seg = c->layer[1].segment_count;
2412*4882a593Smuzhiyun 		state->layer_c_nb_seg = c->layer[2].segment_count;
2413*4882a593Smuzhiyun 	}
2414*4882a593Smuzhiyun 
2415*4882a593Smuzhiyun 	/* WRITE: Mode & Diff mask */
2416*4882a593Smuzhiyun 	dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask);
2417*4882a593Smuzhiyun 
2418*4882a593Smuzhiyun 	state->differential_constellation = (state->seg_diff_mask != 0);
2419*4882a593Smuzhiyun 
2420*4882a593Smuzhiyun 	/* channel estimation fine configuration */
2421*4882a593Smuzhiyun 	ana_gain = dib8000_adp_fine_tune(state, max_constellation);
2422*4882a593Smuzhiyun 
2423*4882a593Smuzhiyun 	/* update ana_gain depending on max constellation */
2424*4882a593Smuzhiyun 	dib8000_update_ana_gain(state, ana_gain);
2425*4882a593Smuzhiyun 
2426*4882a593Smuzhiyun 	/* ---- ANA_FE ---- */
2427*4882a593Smuzhiyun 	if (c->isdbt_partial_reception) /* 3-segments */
2428*4882a593Smuzhiyun 		dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg);
2429*4882a593Smuzhiyun 	else
2430*4882a593Smuzhiyun 		dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */
2431*4882a593Smuzhiyun 
2432*4882a593Smuzhiyun 	/* TSB or ISDBT ? apply it now */
2433*4882a593Smuzhiyun 	if (c->isdbt_sb_mode) {
2434*4882a593Smuzhiyun 		dib8000_set_sb_channel(state);
2435*4882a593Smuzhiyun 		init_prbs = dib8000_get_init_prbs(state,
2436*4882a593Smuzhiyun 						  c->isdbt_sb_subchannel);
2437*4882a593Smuzhiyun 	} else {
2438*4882a593Smuzhiyun 		dib8000_set_13seg_channel(state);
2439*4882a593Smuzhiyun 		init_prbs = 0xfff;
2440*4882a593Smuzhiyun 	}
2441*4882a593Smuzhiyun 
2442*4882a593Smuzhiyun 	/* SMALL */
2443*4882a593Smuzhiyun 	dib8000_small_fine_tune(state);
2444*4882a593Smuzhiyun 
2445*4882a593Smuzhiyun 	dib8000_set_subchannel_prbs(state, init_prbs);
2446*4882a593Smuzhiyun 
2447*4882a593Smuzhiyun 	/* ---- CHAN_BLK ---- */
2448*4882a593Smuzhiyun 	for (i = 0; i < 13; i++) {
2449*4882a593Smuzhiyun 		if ((((~state->seg_diff_mask) >> i) & 1) == 1) {
2450*4882a593Smuzhiyun 			p_cfr_left_edge  += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0));
2451*4882a593Smuzhiyun 			p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0));
2452*4882a593Smuzhiyun 		}
2453*4882a593Smuzhiyun 	}
2454*4882a593Smuzhiyun 	dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */
2455*4882a593Smuzhiyun 	dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */
2456*4882a593Smuzhiyun 	/* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */
2457*4882a593Smuzhiyun 
2458*4882a593Smuzhiyun 	dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */
2459*4882a593Smuzhiyun 	dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */
2460*4882a593Smuzhiyun 	dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */
2461*4882a593Smuzhiyun 
2462*4882a593Smuzhiyun 	if (!autosearching)
2463*4882a593Smuzhiyun 		dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
2464*4882a593Smuzhiyun 	else
2465*4882a593Smuzhiyun 		dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */
2466*4882a593Smuzhiyun 
2467*4882a593Smuzhiyun 	dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */
2468*4882a593Smuzhiyun 	dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */
2469*4882a593Smuzhiyun 
2470*4882a593Smuzhiyun 	dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2471*4882a593Smuzhiyun 
2472*4882a593Smuzhiyun 	/* ---- TMCC ---- */
2473*4882a593Smuzhiyun 	for (i = 0; i < 3; i++)
2474*4882a593Smuzhiyun 		tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ;
2475*4882a593Smuzhiyun 
2476*4882a593Smuzhiyun 	/* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */
2477*4882a593Smuzhiyun 	/* Threshold is set at 1/4 of max power. */
2478*4882a593Smuzhiyun 	tmcc_pow *= (1 << (9-2));
2479*4882a593Smuzhiyun 	dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */
2480*4882a593Smuzhiyun 	dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */
2481*4882a593Smuzhiyun 	dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */
2482*4882a593Smuzhiyun 	/*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */
2483*4882a593Smuzhiyun 
2484*4882a593Smuzhiyun 	/* ---- PHA3 ---- */
2485*4882a593Smuzhiyun 	if (state->isdbt_cfg_loaded == 0)
2486*4882a593Smuzhiyun 		dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */
2487*4882a593Smuzhiyun 
2488*4882a593Smuzhiyun 	state->isdbt_cfg_loaded = 0;
2489*4882a593Smuzhiyun }
2490*4882a593Smuzhiyun 
dib8000_wait_lock(struct dib8000_state * state,u32 internal,u32 wait0_ms,u32 wait1_ms,u32 wait2_ms)2491*4882a593Smuzhiyun static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal,
2492*4882a593Smuzhiyun 			     u32 wait0_ms, u32 wait1_ms, u32 wait2_ms)
2493*4882a593Smuzhiyun {
2494*4882a593Smuzhiyun 	u32 value = 0;	/* P_search_end0 wait time */
2495*4882a593Smuzhiyun 	u16 reg = 11;	/* P_search_end0 start addr */
2496*4882a593Smuzhiyun 
2497*4882a593Smuzhiyun 	for (reg = 11; reg < 16; reg += 2) {
2498*4882a593Smuzhiyun 		if (reg == 11) {
2499*4882a593Smuzhiyun 			if (state->revision == 0x8090)
2500*4882a593Smuzhiyun 				value = internal * wait1_ms;
2501*4882a593Smuzhiyun 			else
2502*4882a593Smuzhiyun 				value = internal * wait0_ms;
2503*4882a593Smuzhiyun 		} else if (reg == 13)
2504*4882a593Smuzhiyun 			value = internal * wait1_ms;
2505*4882a593Smuzhiyun 		else if (reg == 15)
2506*4882a593Smuzhiyun 			value = internal * wait2_ms;
2507*4882a593Smuzhiyun 		dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff));
2508*4882a593Smuzhiyun 		dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff));
2509*4882a593Smuzhiyun 	}
2510*4882a593Smuzhiyun 	return value;
2511*4882a593Smuzhiyun }
2512*4882a593Smuzhiyun 
dib8000_autosearch_start(struct dvb_frontend * fe)2513*4882a593Smuzhiyun static int dib8000_autosearch_start(struct dvb_frontend *fe)
2514*4882a593Smuzhiyun {
2515*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
2516*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2517*4882a593Smuzhiyun 	u8 slist = 0;
2518*4882a593Smuzhiyun 	u32 value, internal = state->cfg.pll->internal;
2519*4882a593Smuzhiyun 
2520*4882a593Smuzhiyun 	if (state->revision == 0x8090)
2521*4882a593Smuzhiyun 		internal = dib8000_read32(state, 23) / 1000;
2522*4882a593Smuzhiyun 
2523*4882a593Smuzhiyun 	if ((state->revision >= 0x8002) &&
2524*4882a593Smuzhiyun 	    (state->autosearch_state == AS_SEARCHING_FFT)) {
2525*4882a593Smuzhiyun 		dib8000_write_word(state,  37, 0x0065); /* P_ctrl_pha_off_max default values */
2526*4882a593Smuzhiyun 		dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
2527*4882a593Smuzhiyun 
2528*4882a593Smuzhiyun 		dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */
2529*4882a593Smuzhiyun 		dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */
2530*4882a593Smuzhiyun 		dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */
2531*4882a593Smuzhiyun 		dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */
2532*4882a593Smuzhiyun 		dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */
2533*4882a593Smuzhiyun 		dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */
2534*4882a593Smuzhiyun 
2535*4882a593Smuzhiyun 		if (state->revision == 0x8090)
2536*4882a593Smuzhiyun 			value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2537*4882a593Smuzhiyun 		else
2538*4882a593Smuzhiyun 			value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2539*4882a593Smuzhiyun 
2540*4882a593Smuzhiyun 		dib8000_write_word(state, 17, 0);
2541*4882a593Smuzhiyun 		dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */
2542*4882a593Smuzhiyun 		dib8000_write_word(state, 19, 0);
2543*4882a593Smuzhiyun 		dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */
2544*4882a593Smuzhiyun 		dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */
2545*4882a593Smuzhiyun 		dib8000_write_word(state, 22, value & 0xffff);
2546*4882a593Smuzhiyun 
2547*4882a593Smuzhiyun 		if (state->revision == 0x8090)
2548*4882a593Smuzhiyun 			dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */
2549*4882a593Smuzhiyun 		else
2550*4882a593Smuzhiyun 			dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */
2551*4882a593Smuzhiyun 		dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */
2552*4882a593Smuzhiyun 
2553*4882a593Smuzhiyun 		/* P_search_param_select = (1 | 1<<4 | 1 << 8) */
2554*4882a593Smuzhiyun 		dib8000_write_word(state, 356, 0);
2555*4882a593Smuzhiyun 		dib8000_write_word(state, 357, 0x111);
2556*4882a593Smuzhiyun 
2557*4882a593Smuzhiyun 		dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
2558*4882a593Smuzhiyun 		dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
2559*4882a593Smuzhiyun 		dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */
2560*4882a593Smuzhiyun 	} else if ((state->revision >= 0x8002) &&
2561*4882a593Smuzhiyun 		   (state->autosearch_state == AS_SEARCHING_GUARD)) {
2562*4882a593Smuzhiyun 		c->transmission_mode = TRANSMISSION_MODE_8K;
2563*4882a593Smuzhiyun 		c->guard_interval = GUARD_INTERVAL_1_8;
2564*4882a593Smuzhiyun 		c->inversion = 0;
2565*4882a593Smuzhiyun 		c->layer[0].modulation = QAM_64;
2566*4882a593Smuzhiyun 		c->layer[0].fec = FEC_2_3;
2567*4882a593Smuzhiyun 		c->layer[0].interleaving = 0;
2568*4882a593Smuzhiyun 		c->layer[0].segment_count = 13;
2569*4882a593Smuzhiyun 
2570*4882a593Smuzhiyun 		slist = 16;
2571*4882a593Smuzhiyun 		c->transmission_mode = state->found_nfft;
2572*4882a593Smuzhiyun 
2573*4882a593Smuzhiyun 		dib8000_set_isdbt_common_channel(state, slist, 1);
2574*4882a593Smuzhiyun 
2575*4882a593Smuzhiyun 		/* set lock_mask values */
2576*4882a593Smuzhiyun 		dib8000_write_word(state, 6, 0x4);
2577*4882a593Smuzhiyun 		if (state->revision == 0x8090)
2578*4882a593Smuzhiyun 			dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */
2579*4882a593Smuzhiyun 		else
2580*4882a593Smuzhiyun 			dib8000_write_word(state, 7, 0x8);
2581*4882a593Smuzhiyun 		dib8000_write_word(state, 8, 0x1000);
2582*4882a593Smuzhiyun 
2583*4882a593Smuzhiyun 		/* set lock_mask wait time values */
2584*4882a593Smuzhiyun 		if (state->revision == 0x8090)
2585*4882a593Smuzhiyun 			dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2586*4882a593Smuzhiyun 		else
2587*4882a593Smuzhiyun 			dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2588*4882a593Smuzhiyun 
2589*4882a593Smuzhiyun 		dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */
2590*4882a593Smuzhiyun 
2591*4882a593Smuzhiyun 		/* P_search_param_select = 0xf; look for the 4 different guard intervals */
2592*4882a593Smuzhiyun 		dib8000_write_word(state, 356, 0);
2593*4882a593Smuzhiyun 		dib8000_write_word(state, 357, 0xf);
2594*4882a593Smuzhiyun 
2595*4882a593Smuzhiyun 		value = dib8000_read_word(state, 0);
2596*4882a593Smuzhiyun 		dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2597*4882a593Smuzhiyun 		dib8000_read_word(state, 1284);  /* reset the INT. n_irq_pending */
2598*4882a593Smuzhiyun 		dib8000_write_word(state, 0, (u16)value);
2599*4882a593Smuzhiyun 	} else {
2600*4882a593Smuzhiyun 		c->inversion = 0;
2601*4882a593Smuzhiyun 		c->layer[0].modulation = QAM_64;
2602*4882a593Smuzhiyun 		c->layer[0].fec = FEC_2_3;
2603*4882a593Smuzhiyun 		c->layer[0].interleaving = 0;
2604*4882a593Smuzhiyun 		c->layer[0].segment_count = 13;
2605*4882a593Smuzhiyun 		if (!c->isdbt_sb_mode)
2606*4882a593Smuzhiyun 			c->layer[0].segment_count = 13;
2607*4882a593Smuzhiyun 
2608*4882a593Smuzhiyun 		/* choose the right list, in sb, always do everything */
2609*4882a593Smuzhiyun 		if (c->isdbt_sb_mode) {
2610*4882a593Smuzhiyun 			slist = 7;
2611*4882a593Smuzhiyun 			dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
2612*4882a593Smuzhiyun 		} else {
2613*4882a593Smuzhiyun 			if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2614*4882a593Smuzhiyun 				if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2615*4882a593Smuzhiyun 					c->transmission_mode = TRANSMISSION_MODE_8K;
2616*4882a593Smuzhiyun 					c->guard_interval = GUARD_INTERVAL_1_8;
2617*4882a593Smuzhiyun 					slist = 7;
2618*4882a593Smuzhiyun 					dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));  /* P_mode = 1 to have autosearch start ok with mode2 */
2619*4882a593Smuzhiyun 				} else {
2620*4882a593Smuzhiyun 					c->guard_interval = GUARD_INTERVAL_1_8;
2621*4882a593Smuzhiyun 					slist = 3;
2622*4882a593Smuzhiyun 				}
2623*4882a593Smuzhiyun 			} else {
2624*4882a593Smuzhiyun 				if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2625*4882a593Smuzhiyun 					c->transmission_mode = TRANSMISSION_MODE_8K;
2626*4882a593Smuzhiyun 					slist = 2;
2627*4882a593Smuzhiyun 					dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));  /* P_mode = 1 */
2628*4882a593Smuzhiyun 				} else
2629*4882a593Smuzhiyun 					slist = 0;
2630*4882a593Smuzhiyun 			}
2631*4882a593Smuzhiyun 		}
2632*4882a593Smuzhiyun 		dprintk("Using list for autosearch : %d\n", slist);
2633*4882a593Smuzhiyun 
2634*4882a593Smuzhiyun 		dib8000_set_isdbt_common_channel(state, slist, 1);
2635*4882a593Smuzhiyun 
2636*4882a593Smuzhiyun 		/* set lock_mask values */
2637*4882a593Smuzhiyun 		dib8000_write_word(state, 6, 0x4);
2638*4882a593Smuzhiyun 		if (state->revision == 0x8090)
2639*4882a593Smuzhiyun 			dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10));
2640*4882a593Smuzhiyun 		else
2641*4882a593Smuzhiyun 			dib8000_write_word(state, 7, 0x8);
2642*4882a593Smuzhiyun 		dib8000_write_word(state, 8, 0x1000);
2643*4882a593Smuzhiyun 
2644*4882a593Smuzhiyun 		/* set lock_mask wait time values */
2645*4882a593Smuzhiyun 		if (state->revision == 0x8090)
2646*4882a593Smuzhiyun 			dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2647*4882a593Smuzhiyun 		else
2648*4882a593Smuzhiyun 			dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2649*4882a593Smuzhiyun 
2650*4882a593Smuzhiyun 		value = dib8000_read_word(state, 0);
2651*4882a593Smuzhiyun 		dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2652*4882a593Smuzhiyun 		dib8000_read_word(state, 1284);  /* reset the INT. n_irq_pending */
2653*4882a593Smuzhiyun 		dib8000_write_word(state, 0, (u16)value);
2654*4882a593Smuzhiyun 	}
2655*4882a593Smuzhiyun 	return 0;
2656*4882a593Smuzhiyun }
2657*4882a593Smuzhiyun 
dib8000_autosearch_irq(struct dvb_frontend * fe)2658*4882a593Smuzhiyun static int dib8000_autosearch_irq(struct dvb_frontend *fe)
2659*4882a593Smuzhiyun {
2660*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
2661*4882a593Smuzhiyun 	u16 irq_pending = dib8000_read_word(state, 1284);
2662*4882a593Smuzhiyun 
2663*4882a593Smuzhiyun 	if ((state->revision >= 0x8002) &&
2664*4882a593Smuzhiyun 	    (state->autosearch_state == AS_SEARCHING_FFT)) {
2665*4882a593Smuzhiyun 		if (irq_pending & 0x1) {
2666*4882a593Smuzhiyun 			dprintk("dib8000_autosearch_irq: max correlation result available\n");
2667*4882a593Smuzhiyun 			return 3;
2668*4882a593Smuzhiyun 		}
2669*4882a593Smuzhiyun 	} else {
2670*4882a593Smuzhiyun 		if (irq_pending & 0x1) {	/* failed */
2671*4882a593Smuzhiyun 			dprintk("dib8000_autosearch_irq failed\n");
2672*4882a593Smuzhiyun 			return 1;
2673*4882a593Smuzhiyun 		}
2674*4882a593Smuzhiyun 
2675*4882a593Smuzhiyun 		if (irq_pending & 0x2) {	/* succeeded */
2676*4882a593Smuzhiyun 			dprintk("dib8000_autosearch_irq succeeded\n");
2677*4882a593Smuzhiyun 			return 2;
2678*4882a593Smuzhiyun 		}
2679*4882a593Smuzhiyun 	}
2680*4882a593Smuzhiyun 
2681*4882a593Smuzhiyun 	return 0;		// still pending
2682*4882a593Smuzhiyun }
2683*4882a593Smuzhiyun 
dib8000_viterbi_state(struct dib8000_state * state,u8 onoff)2684*4882a593Smuzhiyun static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
2685*4882a593Smuzhiyun {
2686*4882a593Smuzhiyun 	u16 tmp;
2687*4882a593Smuzhiyun 
2688*4882a593Smuzhiyun 	tmp = dib8000_read_word(state, 771);
2689*4882a593Smuzhiyun 	if (onoff) /* start P_restart_chd : channel_decoder */
2690*4882a593Smuzhiyun 		dib8000_write_word(state, 771, tmp & 0xfffd);
2691*4882a593Smuzhiyun 	else /* stop P_restart_chd : channel_decoder */
2692*4882a593Smuzhiyun 		dib8000_write_word(state, 771, tmp | (1<<1));
2693*4882a593Smuzhiyun }
2694*4882a593Smuzhiyun 
dib8000_set_dds(struct dib8000_state * state,s32 offset_khz)2695*4882a593Smuzhiyun static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
2696*4882a593Smuzhiyun {
2697*4882a593Smuzhiyun 	s16 unit_khz_dds_val;
2698*4882a593Smuzhiyun 	u32 abs_offset_khz = abs(offset_khz);
2699*4882a593Smuzhiyun 	u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
2700*4882a593Smuzhiyun 	u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
2701*4882a593Smuzhiyun 	u8 ratio;
2702*4882a593Smuzhiyun 
2703*4882a593Smuzhiyun 	if (state->revision == 0x8090) {
2704*4882a593Smuzhiyun 		ratio = 4;
2705*4882a593Smuzhiyun 		unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000);
2706*4882a593Smuzhiyun 		if (offset_khz < 0)
2707*4882a593Smuzhiyun 			dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
2708*4882a593Smuzhiyun 		else
2709*4882a593Smuzhiyun 			dds = (abs_offset_khz * unit_khz_dds_val);
2710*4882a593Smuzhiyun 
2711*4882a593Smuzhiyun 		if (invert)
2712*4882a593Smuzhiyun 			dds = (1<<26) - dds;
2713*4882a593Smuzhiyun 	} else {
2714*4882a593Smuzhiyun 		ratio = 2;
2715*4882a593Smuzhiyun 		unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
2716*4882a593Smuzhiyun 
2717*4882a593Smuzhiyun 		if (offset_khz < 0)
2718*4882a593Smuzhiyun 			unit_khz_dds_val *= -1;
2719*4882a593Smuzhiyun 
2720*4882a593Smuzhiyun 		/* IF tuner */
2721*4882a593Smuzhiyun 		if (invert)
2722*4882a593Smuzhiyun 			dds -= abs_offset_khz * unit_khz_dds_val;
2723*4882a593Smuzhiyun 		else
2724*4882a593Smuzhiyun 			dds += abs_offset_khz * unit_khz_dds_val;
2725*4882a593Smuzhiyun 	}
2726*4882a593Smuzhiyun 
2727*4882a593Smuzhiyun 	dprintk("setting a DDS frequency offset of %c%dkHz\n", invert ? '-' : ' ', dds / unit_khz_dds_val);
2728*4882a593Smuzhiyun 
2729*4882a593Smuzhiyun 	if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) {
2730*4882a593Smuzhiyun 		/* Max dds offset is the half of the demod freq */
2731*4882a593Smuzhiyun 		dib8000_write_word(state, 26, invert);
2732*4882a593Smuzhiyun 		dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff);
2733*4882a593Smuzhiyun 		dib8000_write_word(state, 28, (u16)(dds & 0xffff));
2734*4882a593Smuzhiyun 	}
2735*4882a593Smuzhiyun }
2736*4882a593Smuzhiyun 
dib8000_set_frequency_offset(struct dib8000_state * state)2737*4882a593Smuzhiyun static void dib8000_set_frequency_offset(struct dib8000_state *state)
2738*4882a593Smuzhiyun {
2739*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2740*4882a593Smuzhiyun 	int i;
2741*4882a593Smuzhiyun 	u32 current_rf;
2742*4882a593Smuzhiyun 	int total_dds_offset_khz;
2743*4882a593Smuzhiyun 
2744*4882a593Smuzhiyun 	if (state->fe[0]->ops.tuner_ops.get_frequency)
2745*4882a593Smuzhiyun 		state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], &current_rf);
2746*4882a593Smuzhiyun 	else
2747*4882a593Smuzhiyun 		current_rf = c->frequency;
2748*4882a593Smuzhiyun 	current_rf /= 1000;
2749*4882a593Smuzhiyun 	total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000;
2750*4882a593Smuzhiyun 
2751*4882a593Smuzhiyun 	if (c->isdbt_sb_mode) {
2752*4882a593Smuzhiyun 		state->subchannel = c->isdbt_sb_subchannel;
2753*4882a593Smuzhiyun 
2754*4882a593Smuzhiyun 		i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */
2755*4882a593Smuzhiyun 		dib8000_write_word(state, 26, c->inversion ^ i);
2756*4882a593Smuzhiyun 
2757*4882a593Smuzhiyun 		if (state->cfg.pll->ifreq == 0) { /* low if tuner */
2758*4882a593Smuzhiyun 			if ((c->inversion ^ i) == 0)
2759*4882a593Smuzhiyun 				dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
2760*4882a593Smuzhiyun 		} else {
2761*4882a593Smuzhiyun 			if ((c->inversion ^ i) == 0)
2762*4882a593Smuzhiyun 				total_dds_offset_khz *= -1;
2763*4882a593Smuzhiyun 		}
2764*4882a593Smuzhiyun 	}
2765*4882a593Smuzhiyun 
2766*4882a593Smuzhiyun 	dprintk("%dkhz tuner offset (frequency = %dHz & current_rf = %dHz) total_dds_offset_hz = %d\n", c->frequency - current_rf, c->frequency, current_rf, total_dds_offset_khz);
2767*4882a593Smuzhiyun 
2768*4882a593Smuzhiyun 	/* apply dds offset now */
2769*4882a593Smuzhiyun 	dib8000_set_dds(state, total_dds_offset_khz);
2770*4882a593Smuzhiyun }
2771*4882a593Smuzhiyun 
2772*4882a593Smuzhiyun static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 };
2773*4882a593Smuzhiyun 
dib8000_get_symbol_duration(struct dib8000_state * state)2774*4882a593Smuzhiyun static u32 dib8000_get_symbol_duration(struct dib8000_state *state)
2775*4882a593Smuzhiyun {
2776*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2777*4882a593Smuzhiyun 	u16 i;
2778*4882a593Smuzhiyun 
2779*4882a593Smuzhiyun 	switch (c->transmission_mode) {
2780*4882a593Smuzhiyun 	case TRANSMISSION_MODE_2K:
2781*4882a593Smuzhiyun 			i = 0;
2782*4882a593Smuzhiyun 			break;
2783*4882a593Smuzhiyun 	case TRANSMISSION_MODE_4K:
2784*4882a593Smuzhiyun 			i = 2;
2785*4882a593Smuzhiyun 			break;
2786*4882a593Smuzhiyun 	default:
2787*4882a593Smuzhiyun 	case TRANSMISSION_MODE_AUTO:
2788*4882a593Smuzhiyun 	case TRANSMISSION_MODE_8K:
2789*4882a593Smuzhiyun 			i = 1;
2790*4882a593Smuzhiyun 			break;
2791*4882a593Smuzhiyun 	}
2792*4882a593Smuzhiyun 
2793*4882a593Smuzhiyun 	return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1;
2794*4882a593Smuzhiyun }
2795*4882a593Smuzhiyun 
dib8000_set_isdbt_loop_params(struct dib8000_state * state,enum param_loop_step loop_step)2796*4882a593Smuzhiyun static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step)
2797*4882a593Smuzhiyun {
2798*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2799*4882a593Smuzhiyun 	u16 reg_32 = 0, reg_37 = 0;
2800*4882a593Smuzhiyun 
2801*4882a593Smuzhiyun 	switch (loop_step) {
2802*4882a593Smuzhiyun 	case LOOP_TUNE_1:
2803*4882a593Smuzhiyun 			if (c->isdbt_sb_mode)  {
2804*4882a593Smuzhiyun 				if (c->isdbt_partial_reception == 0) {
2805*4882a593Smuzhiyun 					reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */
2806*4882a593Smuzhiyun 					reg_37 = (3 << 5) | (0 << 4) | (10 - state->mode); /* P_ctrl_pha_off_max=3   P_ctrl_sfreq_inh =0  P_ctrl_sfreq_step = (10-P_mode)  */
2807*4882a593Smuzhiyun 				} else { /* Sound Broadcasting mode 3 seg */
2808*4882a593Smuzhiyun 					reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */
2809*4882a593Smuzhiyun 					reg_37 = (3 << 5) | (0 << 4) | (9 - state->mode); /* P_ctrl_pha_off_max=3   P_ctrl_sfreq_inh =0  P_ctrl_sfreq_step = (9-P_mode)  */
2810*4882a593Smuzhiyun 				}
2811*4882a593Smuzhiyun 			} else { /* 13-seg start conf offset loop parameters */
2812*4882a593Smuzhiyun 				reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
2813*4882a593Smuzhiyun 				reg_37 = (3 << 5) | (0 << 4) | (8 - state->mode); /* P_ctrl_pha_off_max=3   P_ctrl_sfreq_inh =0  P_ctrl_sfreq_step = 9  */
2814*4882a593Smuzhiyun 			}
2815*4882a593Smuzhiyun 			break;
2816*4882a593Smuzhiyun 	case LOOP_TUNE_2:
2817*4882a593Smuzhiyun 			if (c->isdbt_sb_mode)  {
2818*4882a593Smuzhiyun 				if (c->isdbt_partial_reception == 0) {  /* Sound Broadcasting mode 1 seg */
2819*4882a593Smuzhiyun 					reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/
2820*4882a593Smuzhiyun 					reg_37 = (12-state->mode) | ((5 + state->mode) << 5);
2821*4882a593Smuzhiyun 				} else {  /* Sound Broadcasting mode 3 seg */
2822*4882a593Smuzhiyun 					reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */
2823*4882a593Smuzhiyun 					reg_37 = (11-state->mode) | ((5 + state->mode) << 5);
2824*4882a593Smuzhiyun 				}
2825*4882a593Smuzhiyun 			} else {  /* 13 seg */
2826*4882a593Smuzhiyun 				reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */
2827*4882a593Smuzhiyun 				reg_37 = ((5+state->mode) << 5) | (10 - state->mode);
2828*4882a593Smuzhiyun 			}
2829*4882a593Smuzhiyun 			break;
2830*4882a593Smuzhiyun 	}
2831*4882a593Smuzhiyun 	dib8000_write_word(state, 32, reg_32);
2832*4882a593Smuzhiyun 	dib8000_write_word(state, 37, reg_37);
2833*4882a593Smuzhiyun }
2834*4882a593Smuzhiyun 
dib8000_demod_restart(struct dib8000_state * state)2835*4882a593Smuzhiyun static void dib8000_demod_restart(struct dib8000_state *state)
2836*4882a593Smuzhiyun {
2837*4882a593Smuzhiyun 	dib8000_write_word(state, 770, 0x4000);
2838*4882a593Smuzhiyun 	dib8000_write_word(state, 770, 0x0000);
2839*4882a593Smuzhiyun 	return;
2840*4882a593Smuzhiyun }
2841*4882a593Smuzhiyun 
dib8000_set_sync_wait(struct dib8000_state * state)2842*4882a593Smuzhiyun static void dib8000_set_sync_wait(struct dib8000_state *state)
2843*4882a593Smuzhiyun {
2844*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2845*4882a593Smuzhiyun 	u16 sync_wait = 64;
2846*4882a593Smuzhiyun 
2847*4882a593Smuzhiyun 	/* P_dvsy_sync_wait - reuse mode */
2848*4882a593Smuzhiyun 	switch (c->transmission_mode) {
2849*4882a593Smuzhiyun 	case TRANSMISSION_MODE_8K:
2850*4882a593Smuzhiyun 			sync_wait = 256;
2851*4882a593Smuzhiyun 			break;
2852*4882a593Smuzhiyun 	case TRANSMISSION_MODE_4K:
2853*4882a593Smuzhiyun 			sync_wait = 128;
2854*4882a593Smuzhiyun 			break;
2855*4882a593Smuzhiyun 	default:
2856*4882a593Smuzhiyun 	case TRANSMISSION_MODE_2K:
2857*4882a593Smuzhiyun 			sync_wait =  64;
2858*4882a593Smuzhiyun 			break;
2859*4882a593Smuzhiyun 	}
2860*4882a593Smuzhiyun 
2861*4882a593Smuzhiyun 	if (state->cfg.diversity_delay == 0)
2862*4882a593Smuzhiyun 		sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */
2863*4882a593Smuzhiyun 	else
2864*4882a593Smuzhiyun 		sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */
2865*4882a593Smuzhiyun 
2866*4882a593Smuzhiyun 	dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
2867*4882a593Smuzhiyun }
2868*4882a593Smuzhiyun 
dib8000_get_timeout(struct dib8000_state * state,u32 delay,enum timeout_mode mode)2869*4882a593Smuzhiyun static unsigned long dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
2870*4882a593Smuzhiyun {
2871*4882a593Smuzhiyun 	if (mode == SYMBOL_DEPENDENT_ON)
2872*4882a593Smuzhiyun 		delay *= state->symbol_duration;
2873*4882a593Smuzhiyun 
2874*4882a593Smuzhiyun 	return jiffies + usecs_to_jiffies(delay * 100);
2875*4882a593Smuzhiyun }
2876*4882a593Smuzhiyun 
dib8000_get_status(struct dvb_frontend * fe)2877*4882a593Smuzhiyun static s32 dib8000_get_status(struct dvb_frontend *fe)
2878*4882a593Smuzhiyun {
2879*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
2880*4882a593Smuzhiyun 	return state->status;
2881*4882a593Smuzhiyun }
2882*4882a593Smuzhiyun 
dib8000_get_tune_state(struct dvb_frontend * fe)2883*4882a593Smuzhiyun static enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
2884*4882a593Smuzhiyun {
2885*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
2886*4882a593Smuzhiyun 	return state->tune_state;
2887*4882a593Smuzhiyun }
2888*4882a593Smuzhiyun 
dib8000_set_tune_state(struct dvb_frontend * fe,enum frontend_tune_state tune_state)2889*4882a593Smuzhiyun static int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2890*4882a593Smuzhiyun {
2891*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
2892*4882a593Smuzhiyun 
2893*4882a593Smuzhiyun 	state->tune_state = tune_state;
2894*4882a593Smuzhiyun 	return 0;
2895*4882a593Smuzhiyun }
2896*4882a593Smuzhiyun 
dib8000_tune_restart_from_demod(struct dvb_frontend * fe)2897*4882a593Smuzhiyun static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
2898*4882a593Smuzhiyun {
2899*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
2900*4882a593Smuzhiyun 
2901*4882a593Smuzhiyun 	state->status = FE_STATUS_TUNE_PENDING;
2902*4882a593Smuzhiyun 	state->tune_state = CT_DEMOD_START;
2903*4882a593Smuzhiyun 	return 0;
2904*4882a593Smuzhiyun }
2905*4882a593Smuzhiyun 
dib8000_read_lock(struct dvb_frontend * fe)2906*4882a593Smuzhiyun static u16 dib8000_read_lock(struct dvb_frontend *fe)
2907*4882a593Smuzhiyun {
2908*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
2909*4882a593Smuzhiyun 
2910*4882a593Smuzhiyun 	if (state->revision == 0x8090)
2911*4882a593Smuzhiyun 		return dib8000_read_word(state, 570);
2912*4882a593Smuzhiyun 	return dib8000_read_word(state, 568);
2913*4882a593Smuzhiyun }
2914*4882a593Smuzhiyun 
dib8090p_init_sdram(struct dib8000_state * state)2915*4882a593Smuzhiyun static int dib8090p_init_sdram(struct dib8000_state *state)
2916*4882a593Smuzhiyun {
2917*4882a593Smuzhiyun 	u16 reg = 0;
2918*4882a593Smuzhiyun 	dprintk("init sdram\n");
2919*4882a593Smuzhiyun 
2920*4882a593Smuzhiyun 	reg = dib8000_read_word(state, 274) & 0xfff0;
2921*4882a593Smuzhiyun 	dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */
2922*4882a593Smuzhiyun 
2923*4882a593Smuzhiyun 	dib8000_write_word(state, 1803, (7 << 2));
2924*4882a593Smuzhiyun 
2925*4882a593Smuzhiyun 	reg = dib8000_read_word(state, 1280);
2926*4882a593Smuzhiyun 	dib8000_write_word(state, 1280,  reg | (1 << 2)); /* force restart P_restart_sdram */
2927*4882a593Smuzhiyun 	dib8000_write_word(state, 1280,  reg); /* release restart P_restart_sdram */
2928*4882a593Smuzhiyun 
2929*4882a593Smuzhiyun 	return 0;
2930*4882a593Smuzhiyun }
2931*4882a593Smuzhiyun 
2932*4882a593Smuzhiyun /**
2933*4882a593Smuzhiyun  * is_manual_mode - Check if TMCC should be used for parameters settings
2934*4882a593Smuzhiyun  * @c:	struct dvb_frontend_properties
2935*4882a593Smuzhiyun  *
2936*4882a593Smuzhiyun  * By default, TMCC table should be used for parameter settings on most
2937*4882a593Smuzhiyun  * usercases. However, sometimes it is desirable to lock the demod to
2938*4882a593Smuzhiyun  * use the manual parameters.
2939*4882a593Smuzhiyun  *
2940*4882a593Smuzhiyun  * On manual mode, the current dib8000_tune state machine is very restrict:
2941*4882a593Smuzhiyun  * It requires that both per-layer and per-transponder parameters to be
2942*4882a593Smuzhiyun  * properly specified, otherwise the device won't lock.
2943*4882a593Smuzhiyun  *
2944*4882a593Smuzhiyun  * Check if all those conditions are properly satisfied before allowing
2945*4882a593Smuzhiyun  * the device to use the manual frequency lock mode.
2946*4882a593Smuzhiyun  */
is_manual_mode(struct dtv_frontend_properties * c)2947*4882a593Smuzhiyun static int is_manual_mode(struct dtv_frontend_properties *c)
2948*4882a593Smuzhiyun {
2949*4882a593Smuzhiyun 	int i, n_segs = 0;
2950*4882a593Smuzhiyun 
2951*4882a593Smuzhiyun 	/* Use auto mode on DVB-T compat mode */
2952*4882a593Smuzhiyun 	if (c->delivery_system != SYS_ISDBT)
2953*4882a593Smuzhiyun 		return 0;
2954*4882a593Smuzhiyun 
2955*4882a593Smuzhiyun 	/*
2956*4882a593Smuzhiyun 	 * Transmission mode is only detected on auto mode, currently
2957*4882a593Smuzhiyun 	 */
2958*4882a593Smuzhiyun 	if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2959*4882a593Smuzhiyun 		dprintk("transmission mode auto\n");
2960*4882a593Smuzhiyun 		return 0;
2961*4882a593Smuzhiyun 	}
2962*4882a593Smuzhiyun 
2963*4882a593Smuzhiyun 	/*
2964*4882a593Smuzhiyun 	 * Guard interval is only detected on auto mode, currently
2965*4882a593Smuzhiyun 	 */
2966*4882a593Smuzhiyun 	if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2967*4882a593Smuzhiyun 		dprintk("guard interval auto\n");
2968*4882a593Smuzhiyun 		return 0;
2969*4882a593Smuzhiyun 	}
2970*4882a593Smuzhiyun 
2971*4882a593Smuzhiyun 	/*
2972*4882a593Smuzhiyun 	 * If no layer is enabled, assume auto mode, as at least one
2973*4882a593Smuzhiyun 	 * layer should be enabled
2974*4882a593Smuzhiyun 	 */
2975*4882a593Smuzhiyun 	if (!c->isdbt_layer_enabled) {
2976*4882a593Smuzhiyun 		dprintk("no layer modulation specified\n");
2977*4882a593Smuzhiyun 		return 0;
2978*4882a593Smuzhiyun 	}
2979*4882a593Smuzhiyun 
2980*4882a593Smuzhiyun 	/*
2981*4882a593Smuzhiyun 	 * Check if the per-layer parameters aren't auto and
2982*4882a593Smuzhiyun 	 * disable a layer if segment count is 0 or invalid.
2983*4882a593Smuzhiyun 	 */
2984*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
2985*4882a593Smuzhiyun 		if (!(c->isdbt_layer_enabled & 1 << i))
2986*4882a593Smuzhiyun 			continue;
2987*4882a593Smuzhiyun 
2988*4882a593Smuzhiyun 		if ((c->layer[i].segment_count > 13) ||
2989*4882a593Smuzhiyun 		    (c->layer[i].segment_count == 0)) {
2990*4882a593Smuzhiyun 			c->isdbt_layer_enabled &= ~(1 << i);
2991*4882a593Smuzhiyun 			continue;
2992*4882a593Smuzhiyun 		}
2993*4882a593Smuzhiyun 
2994*4882a593Smuzhiyun 		n_segs += c->layer[i].segment_count;
2995*4882a593Smuzhiyun 
2996*4882a593Smuzhiyun 		if ((c->layer[i].modulation == QAM_AUTO) ||
2997*4882a593Smuzhiyun 		    (c->layer[i].fec == FEC_AUTO)) {
2998*4882a593Smuzhiyun 			dprintk("layer %c has either modulation or FEC auto\n",
2999*4882a593Smuzhiyun 				'A' + i);
3000*4882a593Smuzhiyun 			return 0;
3001*4882a593Smuzhiyun 		}
3002*4882a593Smuzhiyun 	}
3003*4882a593Smuzhiyun 
3004*4882a593Smuzhiyun 	/*
3005*4882a593Smuzhiyun 	 * Userspace specified a wrong number of segments.
3006*4882a593Smuzhiyun 	 *	fallback to auto mode.
3007*4882a593Smuzhiyun 	 */
3008*4882a593Smuzhiyun 	if (n_segs == 0 || n_segs > 13) {
3009*4882a593Smuzhiyun 		dprintk("number of segments is invalid\n");
3010*4882a593Smuzhiyun 		return 0;
3011*4882a593Smuzhiyun 	}
3012*4882a593Smuzhiyun 
3013*4882a593Smuzhiyun 	/* Everything looks ok for manual mode */
3014*4882a593Smuzhiyun 	return 1;
3015*4882a593Smuzhiyun }
3016*4882a593Smuzhiyun 
dib8000_tune(struct dvb_frontend * fe)3017*4882a593Smuzhiyun static int dib8000_tune(struct dvb_frontend *fe)
3018*4882a593Smuzhiyun {
3019*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
3020*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3021*4882a593Smuzhiyun 	enum frontend_tune_state *tune_state = &state->tune_state;
3022*4882a593Smuzhiyun 
3023*4882a593Smuzhiyun 	u16 locks, deeper_interleaver = 0, i;
3024*4882a593Smuzhiyun 	int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
3025*4882a593Smuzhiyun 
3026*4882a593Smuzhiyun 	unsigned long *timeout = &state->timeout;
3027*4882a593Smuzhiyun 	unsigned long now = jiffies;
3028*4882a593Smuzhiyun 	u16 init_prbs;
3029*4882a593Smuzhiyun #ifdef DIB8000_AGC_FREEZE
3030*4882a593Smuzhiyun 	u16 agc1, agc2;
3031*4882a593Smuzhiyun #endif
3032*4882a593Smuzhiyun 
3033*4882a593Smuzhiyun 	u32 corm[4] = {0, 0, 0, 0};
3034*4882a593Smuzhiyun 	u8 find_index, max_value;
3035*4882a593Smuzhiyun 
3036*4882a593Smuzhiyun #if 0
3037*4882a593Smuzhiyun 	if (*tune_state < CT_DEMOD_STOP)
3038*4882a593Smuzhiyun 		dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u jiffies = %lu\n",
3039*4882a593Smuzhiyun 			state->channel_parameters_set, *tune_state, state->autosearch_state, now);
3040*4882a593Smuzhiyun #endif
3041*4882a593Smuzhiyun 
3042*4882a593Smuzhiyun 	switch (*tune_state) {
3043*4882a593Smuzhiyun 	case CT_DEMOD_START: /* 30 */
3044*4882a593Smuzhiyun 		dib8000_reset_stats(fe);
3045*4882a593Smuzhiyun 
3046*4882a593Smuzhiyun 		if (state->revision == 0x8090)
3047*4882a593Smuzhiyun 			dib8090p_init_sdram(state);
3048*4882a593Smuzhiyun 		state->status = FE_STATUS_TUNE_PENDING;
3049*4882a593Smuzhiyun 		state->channel_parameters_set = is_manual_mode(c);
3050*4882a593Smuzhiyun 
3051*4882a593Smuzhiyun 		dprintk("Tuning channel on %s search mode\n",
3052*4882a593Smuzhiyun 			state->channel_parameters_set ? "manual" : "auto");
3053*4882a593Smuzhiyun 
3054*4882a593Smuzhiyun 		dib8000_viterbi_state(state, 0); /* force chan dec in restart */
3055*4882a593Smuzhiyun 
3056*4882a593Smuzhiyun 		/* Layer monitor */
3057*4882a593Smuzhiyun 		dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
3058*4882a593Smuzhiyun 
3059*4882a593Smuzhiyun 		dib8000_set_frequency_offset(state);
3060*4882a593Smuzhiyun 		dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
3061*4882a593Smuzhiyun 
3062*4882a593Smuzhiyun 		if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
3063*4882a593Smuzhiyun #ifdef DIB8000_AGC_FREEZE
3064*4882a593Smuzhiyun 			if (state->revision != 0x8090) {
3065*4882a593Smuzhiyun 				state->agc1_max = dib8000_read_word(state, 108);
3066*4882a593Smuzhiyun 				state->agc1_min = dib8000_read_word(state, 109);
3067*4882a593Smuzhiyun 				state->agc2_max = dib8000_read_word(state, 110);
3068*4882a593Smuzhiyun 				state->agc2_min = dib8000_read_word(state, 111);
3069*4882a593Smuzhiyun 				agc1 = dib8000_read_word(state, 388);
3070*4882a593Smuzhiyun 				agc2 = dib8000_read_word(state, 389);
3071*4882a593Smuzhiyun 				dib8000_write_word(state, 108, agc1);
3072*4882a593Smuzhiyun 				dib8000_write_word(state, 109, agc1);
3073*4882a593Smuzhiyun 				dib8000_write_word(state, 110, agc2);
3074*4882a593Smuzhiyun 				dib8000_write_word(state, 111, agc2);
3075*4882a593Smuzhiyun 			}
3076*4882a593Smuzhiyun #endif
3077*4882a593Smuzhiyun 			state->autosearch_state = AS_SEARCHING_FFT;
3078*4882a593Smuzhiyun 			state->found_nfft = TRANSMISSION_MODE_AUTO;
3079*4882a593Smuzhiyun 			state->found_guard = GUARD_INTERVAL_AUTO;
3080*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_SEARCH_NEXT;
3081*4882a593Smuzhiyun 		} else { /* we already know the channel struct so TUNE only ! */
3082*4882a593Smuzhiyun 			state->autosearch_state = AS_DONE;
3083*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STEP_3;
3084*4882a593Smuzhiyun 		}
3085*4882a593Smuzhiyun 		state->symbol_duration = dib8000_get_symbol_duration(state);
3086*4882a593Smuzhiyun 		break;
3087*4882a593Smuzhiyun 
3088*4882a593Smuzhiyun 	case CT_DEMOD_SEARCH_NEXT: /* 51 */
3089*4882a593Smuzhiyun 		dib8000_autosearch_start(fe);
3090*4882a593Smuzhiyun 		if (state->revision == 0x8090)
3091*4882a593Smuzhiyun 			ret = 50;
3092*4882a593Smuzhiyun 		else
3093*4882a593Smuzhiyun 			ret = 15;
3094*4882a593Smuzhiyun 		*tune_state = CT_DEMOD_STEP_1;
3095*4882a593Smuzhiyun 		break;
3096*4882a593Smuzhiyun 
3097*4882a593Smuzhiyun 	case CT_DEMOD_STEP_1: /* 31 */
3098*4882a593Smuzhiyun 		switch (dib8000_autosearch_irq(fe)) {
3099*4882a593Smuzhiyun 		case 1: /* fail */
3100*4882a593Smuzhiyun 			state->status = FE_STATUS_TUNE_FAILED;
3101*4882a593Smuzhiyun 			state->autosearch_state = AS_DONE;
3102*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STOP; /* else we are done here */
3103*4882a593Smuzhiyun 			break;
3104*4882a593Smuzhiyun 		case 2: /* Success */
3105*4882a593Smuzhiyun 			state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
3106*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STEP_3;
3107*4882a593Smuzhiyun 			if (state->autosearch_state == AS_SEARCHING_GUARD)
3108*4882a593Smuzhiyun 				*tune_state = CT_DEMOD_STEP_2;
3109*4882a593Smuzhiyun 			else
3110*4882a593Smuzhiyun 				state->autosearch_state = AS_DONE;
3111*4882a593Smuzhiyun 			break;
3112*4882a593Smuzhiyun 		case 3: /* Autosearch FFT max correlation endded */
3113*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STEP_2;
3114*4882a593Smuzhiyun 			break;
3115*4882a593Smuzhiyun 		}
3116*4882a593Smuzhiyun 		break;
3117*4882a593Smuzhiyun 
3118*4882a593Smuzhiyun 	case CT_DEMOD_STEP_2:
3119*4882a593Smuzhiyun 		switch (state->autosearch_state) {
3120*4882a593Smuzhiyun 		case AS_SEARCHING_FFT:
3121*4882a593Smuzhiyun 			/* searching for the correct FFT */
3122*4882a593Smuzhiyun 			if (state->revision == 0x8090) {
3123*4882a593Smuzhiyun 				corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3124*4882a593Smuzhiyun 				corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3125*4882a593Smuzhiyun 				corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
3126*4882a593Smuzhiyun 			} else {
3127*4882a593Smuzhiyun 				corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
3128*4882a593Smuzhiyun 				corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3129*4882a593Smuzhiyun 				corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3130*4882a593Smuzhiyun 			}
3131*4882a593Smuzhiyun 			/* dprintk("corm fft: %u %u %u\n", corm[0], corm[1], corm[2]); */
3132*4882a593Smuzhiyun 
3133*4882a593Smuzhiyun 			max_value = 0;
3134*4882a593Smuzhiyun 			for (find_index = 1 ; find_index < 3 ; find_index++) {
3135*4882a593Smuzhiyun 				if (corm[max_value] < corm[find_index])
3136*4882a593Smuzhiyun 					max_value = find_index ;
3137*4882a593Smuzhiyun 			}
3138*4882a593Smuzhiyun 
3139*4882a593Smuzhiyun 			switch (max_value) {
3140*4882a593Smuzhiyun 			case 0:
3141*4882a593Smuzhiyun 				state->found_nfft = TRANSMISSION_MODE_2K;
3142*4882a593Smuzhiyun 				break;
3143*4882a593Smuzhiyun 			case 1:
3144*4882a593Smuzhiyun 				state->found_nfft = TRANSMISSION_MODE_4K;
3145*4882a593Smuzhiyun 				break;
3146*4882a593Smuzhiyun 			case 2:
3147*4882a593Smuzhiyun 			default:
3148*4882a593Smuzhiyun 				state->found_nfft = TRANSMISSION_MODE_8K;
3149*4882a593Smuzhiyun 				break;
3150*4882a593Smuzhiyun 			}
3151*4882a593Smuzhiyun 			/* dprintk("Autosearch FFT has found Mode %d\n", max_value + 1); */
3152*4882a593Smuzhiyun 
3153*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_SEARCH_NEXT;
3154*4882a593Smuzhiyun 			state->autosearch_state = AS_SEARCHING_GUARD;
3155*4882a593Smuzhiyun 			if (state->revision == 0x8090)
3156*4882a593Smuzhiyun 				ret = 50;
3157*4882a593Smuzhiyun 			else
3158*4882a593Smuzhiyun 				ret = 10;
3159*4882a593Smuzhiyun 			break;
3160*4882a593Smuzhiyun 		case AS_SEARCHING_GUARD:
3161*4882a593Smuzhiyun 			/* searching for the correct guard interval */
3162*4882a593Smuzhiyun 			if (state->revision == 0x8090)
3163*4882a593Smuzhiyun 				state->found_guard = dib8000_read_word(state, 572) & 0x3;
3164*4882a593Smuzhiyun 			else
3165*4882a593Smuzhiyun 				state->found_guard = dib8000_read_word(state, 570) & 0x3;
3166*4882a593Smuzhiyun 			/* dprintk("guard interval found=%i\n", state->found_guard); */
3167*4882a593Smuzhiyun 
3168*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STEP_3;
3169*4882a593Smuzhiyun 			break;
3170*4882a593Smuzhiyun 		default:
3171*4882a593Smuzhiyun 			/* the demod should never be in this state */
3172*4882a593Smuzhiyun 			state->status = FE_STATUS_TUNE_FAILED;
3173*4882a593Smuzhiyun 			state->autosearch_state = AS_DONE;
3174*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STOP; /* else we are done here */
3175*4882a593Smuzhiyun 			break;
3176*4882a593Smuzhiyun 		}
3177*4882a593Smuzhiyun 		break;
3178*4882a593Smuzhiyun 
3179*4882a593Smuzhiyun 	case CT_DEMOD_STEP_3: /* 33 */
3180*4882a593Smuzhiyun 		dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
3181*4882a593Smuzhiyun 		dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
3182*4882a593Smuzhiyun 		*tune_state = CT_DEMOD_STEP_4;
3183*4882a593Smuzhiyun 		break;
3184*4882a593Smuzhiyun 
3185*4882a593Smuzhiyun 	case CT_DEMOD_STEP_4: /* (34) */
3186*4882a593Smuzhiyun 		dib8000_demod_restart(state);
3187*4882a593Smuzhiyun 
3188*4882a593Smuzhiyun 		dib8000_set_sync_wait(state);
3189*4882a593Smuzhiyun 		dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
3190*4882a593Smuzhiyun 
3191*4882a593Smuzhiyun 		locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
3192*4882a593Smuzhiyun 		/* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */
3193*4882a593Smuzhiyun 		*timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
3194*4882a593Smuzhiyun 		*tune_state = CT_DEMOD_STEP_5;
3195*4882a593Smuzhiyun 		break;
3196*4882a593Smuzhiyun 
3197*4882a593Smuzhiyun 	case CT_DEMOD_STEP_5: /* (35) */
3198*4882a593Smuzhiyun 		locks = dib8000_read_lock(fe);
3199*4882a593Smuzhiyun 		if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
3200*4882a593Smuzhiyun 			dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
3201*4882a593Smuzhiyun 			if (!state->differential_constellation) {
3202*4882a593Smuzhiyun 				/* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
3203*4882a593Smuzhiyun 				*timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
3204*4882a593Smuzhiyun 				*tune_state = CT_DEMOD_STEP_7;
3205*4882a593Smuzhiyun 			} else {
3206*4882a593Smuzhiyun 				*tune_state = CT_DEMOD_STEP_8;
3207*4882a593Smuzhiyun 			}
3208*4882a593Smuzhiyun 		} else if (time_after(now, *timeout)) {
3209*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3210*4882a593Smuzhiyun 		}
3211*4882a593Smuzhiyun 		break;
3212*4882a593Smuzhiyun 
3213*4882a593Smuzhiyun 	case CT_DEMOD_STEP_6: /* (36)  if there is an input (diversity) */
3214*4882a593Smuzhiyun 		if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
3215*4882a593Smuzhiyun 			/* if there is a diversity fe in input and this fe is has not already failed : wait here until this this fe has succedeed or failed */
3216*4882a593Smuzhiyun 			if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
3217*4882a593Smuzhiyun 				*tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
3218*4882a593Smuzhiyun 			else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failed also, break the current one */
3219*4882a593Smuzhiyun 				*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3220*4882a593Smuzhiyun 				dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3221*4882a593Smuzhiyun 				dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3222*4882a593Smuzhiyun 				state->status = FE_STATUS_TUNE_FAILED;
3223*4882a593Smuzhiyun 			}
3224*4882a593Smuzhiyun 		} else {
3225*4882a593Smuzhiyun 			dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3226*4882a593Smuzhiyun 			dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3227*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3228*4882a593Smuzhiyun 			state->status = FE_STATUS_TUNE_FAILED;
3229*4882a593Smuzhiyun 		}
3230*4882a593Smuzhiyun 		break;
3231*4882a593Smuzhiyun 
3232*4882a593Smuzhiyun 	case CT_DEMOD_STEP_7: /* 37 */
3233*4882a593Smuzhiyun 		locks = dib8000_read_lock(fe);
3234*4882a593Smuzhiyun 		if (locks & (1<<10)) { /* lmod4_lock */
3235*4882a593Smuzhiyun 			ret = 14; /* wait for 14 symbols */
3236*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STEP_8;
3237*4882a593Smuzhiyun 		} else if (time_after(now, *timeout))
3238*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3239*4882a593Smuzhiyun 		break;
3240*4882a593Smuzhiyun 
3241*4882a593Smuzhiyun 	case CT_DEMOD_STEP_8: /* 38 */
3242*4882a593Smuzhiyun 		dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3243*4882a593Smuzhiyun 		dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3244*4882a593Smuzhiyun 
3245*4882a593Smuzhiyun 		/* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
3246*4882a593Smuzhiyun 		if (c->isdbt_sb_mode
3247*4882a593Smuzhiyun 		    && c->isdbt_sb_subchannel < 14
3248*4882a593Smuzhiyun 		    && !state->differential_constellation) {
3249*4882a593Smuzhiyun 			state->subchannel = 0;
3250*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STEP_11;
3251*4882a593Smuzhiyun 		} else {
3252*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STEP_9;
3253*4882a593Smuzhiyun 			state->status = FE_STATUS_LOCKED;
3254*4882a593Smuzhiyun 		}
3255*4882a593Smuzhiyun 		break;
3256*4882a593Smuzhiyun 
3257*4882a593Smuzhiyun 	case CT_DEMOD_STEP_9: /* 39 */
3258*4882a593Smuzhiyun 		if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
3259*4882a593Smuzhiyun 			/* defines timeout for mpeg lock depending on interleaver length of longest layer */
3260*4882a593Smuzhiyun 			for (i = 0; i < 3; i++) {
3261*4882a593Smuzhiyun 				if (c->layer[i].interleaving >= deeper_interleaver) {
3262*4882a593Smuzhiyun 					dprintk("layer%i: time interleaver = %d\n", i, c->layer[i].interleaving);
3263*4882a593Smuzhiyun 					if (c->layer[i].segment_count > 0) { /* valid layer */
3264*4882a593Smuzhiyun 						deeper_interleaver = c->layer[0].interleaving;
3265*4882a593Smuzhiyun 						state->longest_intlv_layer = i;
3266*4882a593Smuzhiyun 					}
3267*4882a593Smuzhiyun 				}
3268*4882a593Smuzhiyun 			}
3269*4882a593Smuzhiyun 
3270*4882a593Smuzhiyun 			if (deeper_interleaver == 0)
3271*4882a593Smuzhiyun 				locks = 2; /* locks is the tmp local variable name */
3272*4882a593Smuzhiyun 			else if (deeper_interleaver == 3)
3273*4882a593Smuzhiyun 				locks = 8;
3274*4882a593Smuzhiyun 			else
3275*4882a593Smuzhiyun 				locks = 2 * deeper_interleaver;
3276*4882a593Smuzhiyun 
3277*4882a593Smuzhiyun 			if (state->diversity_onoff != 0) /* because of diversity sync */
3278*4882a593Smuzhiyun 				locks *= 2;
3279*4882a593Smuzhiyun 
3280*4882a593Smuzhiyun 			*timeout = now + msecs_to_jiffies(200 * locks); /* give the mpeg lock 800ms if sram is present */
3281*4882a593Smuzhiyun 			dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %ld\n",
3282*4882a593Smuzhiyun 				deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
3283*4882a593Smuzhiyun 
3284*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STEP_10;
3285*4882a593Smuzhiyun 		} else
3286*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STOP;
3287*4882a593Smuzhiyun 		break;
3288*4882a593Smuzhiyun 
3289*4882a593Smuzhiyun 	case CT_DEMOD_STEP_10: /* 40 */
3290*4882a593Smuzhiyun 		locks = dib8000_read_lock(fe);
3291*4882a593Smuzhiyun 		if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
3292*4882a593Smuzhiyun 			dprintk("ISDB-T layer locks: Layer A %s, Layer B %s, Layer C %s\n",
3293*4882a593Smuzhiyun 				c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
3294*4882a593Smuzhiyun 				c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
3295*4882a593Smuzhiyun 				c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
3296*4882a593Smuzhiyun 			if (c->isdbt_sb_mode
3297*4882a593Smuzhiyun 			    && c->isdbt_sb_subchannel < 14
3298*4882a593Smuzhiyun 			    && !state->differential_constellation)
3299*4882a593Smuzhiyun 				/* signal to the upper layer, that there was a channel found and the parameters can be read */
3300*4882a593Smuzhiyun 				state->status = FE_STATUS_DEMOD_SUCCESS;
3301*4882a593Smuzhiyun 			else
3302*4882a593Smuzhiyun 				state->status = FE_STATUS_DATA_LOCKED;
3303*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STOP;
3304*4882a593Smuzhiyun 		} else if (time_after(now, *timeout)) {
3305*4882a593Smuzhiyun 			if (c->isdbt_sb_mode
3306*4882a593Smuzhiyun 			    && c->isdbt_sb_subchannel < 14
3307*4882a593Smuzhiyun 			    && !state->differential_constellation) { /* continue to try init prbs autosearch */
3308*4882a593Smuzhiyun 				state->subchannel += 3;
3309*4882a593Smuzhiyun 				*tune_state = CT_DEMOD_STEP_11;
3310*4882a593Smuzhiyun 			} else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */
3311*4882a593Smuzhiyun 				if (locks & (0x7 << 5)) {
3312*4882a593Smuzhiyun 					dprintk("Not all ISDB-T layers locked in %d ms: Layer A %s, Layer B %s, Layer C %s\n",
3313*4882a593Smuzhiyun 						jiffies_to_msecs(now - *timeout),
3314*4882a593Smuzhiyun 						c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
3315*4882a593Smuzhiyun 						c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
3316*4882a593Smuzhiyun 						c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
3317*4882a593Smuzhiyun 
3318*4882a593Smuzhiyun 					state->status = FE_STATUS_DATA_LOCKED;
3319*4882a593Smuzhiyun 				} else
3320*4882a593Smuzhiyun 					state->status = FE_STATUS_TUNE_FAILED;
3321*4882a593Smuzhiyun 				*tune_state = CT_DEMOD_STOP;
3322*4882a593Smuzhiyun 			}
3323*4882a593Smuzhiyun 		}
3324*4882a593Smuzhiyun 		break;
3325*4882a593Smuzhiyun 
3326*4882a593Smuzhiyun 	case CT_DEMOD_STEP_11:  /* 41 : init prbs autosearch */
3327*4882a593Smuzhiyun 		init_prbs = dib8000_get_init_prbs(state, state->subchannel);
3328*4882a593Smuzhiyun 
3329*4882a593Smuzhiyun 		if (init_prbs) {
3330*4882a593Smuzhiyun 			dib8000_set_subchannel_prbs(state, init_prbs);
3331*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STEP_9;
3332*4882a593Smuzhiyun 		} else {
3333*4882a593Smuzhiyun 			*tune_state = CT_DEMOD_STOP;
3334*4882a593Smuzhiyun 			state->status = FE_STATUS_TUNE_FAILED;
3335*4882a593Smuzhiyun 		}
3336*4882a593Smuzhiyun 		break;
3337*4882a593Smuzhiyun 
3338*4882a593Smuzhiyun 	default:
3339*4882a593Smuzhiyun 		break;
3340*4882a593Smuzhiyun 	}
3341*4882a593Smuzhiyun 
3342*4882a593Smuzhiyun 	/* tuning is finished - cleanup the demod */
3343*4882a593Smuzhiyun 	switch (*tune_state) {
3344*4882a593Smuzhiyun 	case CT_DEMOD_STOP: /* (42) */
3345*4882a593Smuzhiyun #ifdef DIB8000_AGC_FREEZE
3346*4882a593Smuzhiyun 		if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
3347*4882a593Smuzhiyun 			dib8000_write_word(state, 108, state->agc1_max);
3348*4882a593Smuzhiyun 			dib8000_write_word(state, 109, state->agc1_min);
3349*4882a593Smuzhiyun 			dib8000_write_word(state, 110, state->agc2_max);
3350*4882a593Smuzhiyun 			dib8000_write_word(state, 111, state->agc2_min);
3351*4882a593Smuzhiyun 			state->agc1_max = 0;
3352*4882a593Smuzhiyun 			state->agc1_min = 0;
3353*4882a593Smuzhiyun 			state->agc2_max = 0;
3354*4882a593Smuzhiyun 			state->agc2_min = 0;
3355*4882a593Smuzhiyun 		}
3356*4882a593Smuzhiyun #endif
3357*4882a593Smuzhiyun 		ret = 0;
3358*4882a593Smuzhiyun 		break;
3359*4882a593Smuzhiyun 	default:
3360*4882a593Smuzhiyun 		break;
3361*4882a593Smuzhiyun 	}
3362*4882a593Smuzhiyun 
3363*4882a593Smuzhiyun 	if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
3364*4882a593Smuzhiyun 		return ret * state->symbol_duration;
3365*4882a593Smuzhiyun 	if ((ret > 0) && (ret < state->symbol_duration))
3366*4882a593Smuzhiyun 		return state->symbol_duration; /* at least one symbol */
3367*4882a593Smuzhiyun 	return ret;
3368*4882a593Smuzhiyun }
3369*4882a593Smuzhiyun 
dib8000_wakeup(struct dvb_frontend * fe)3370*4882a593Smuzhiyun static int dib8000_wakeup(struct dvb_frontend *fe)
3371*4882a593Smuzhiyun {
3372*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
3373*4882a593Smuzhiyun 	u8 index_frontend;
3374*4882a593Smuzhiyun 	int ret;
3375*4882a593Smuzhiyun 
3376*4882a593Smuzhiyun 	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
3377*4882a593Smuzhiyun 	dib8000_set_adc_state(state, DIBX000_ADC_ON);
3378*4882a593Smuzhiyun 	if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
3379*4882a593Smuzhiyun 		dprintk("could not start Slow ADC\n");
3380*4882a593Smuzhiyun 
3381*4882a593Smuzhiyun 	if (state->revision == 0x8090)
3382*4882a593Smuzhiyun 		dib8000_sad_calib(state);
3383*4882a593Smuzhiyun 
3384*4882a593Smuzhiyun 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3385*4882a593Smuzhiyun 		ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
3386*4882a593Smuzhiyun 		if (ret < 0)
3387*4882a593Smuzhiyun 			return ret;
3388*4882a593Smuzhiyun 	}
3389*4882a593Smuzhiyun 
3390*4882a593Smuzhiyun 	return 0;
3391*4882a593Smuzhiyun }
3392*4882a593Smuzhiyun 
dib8000_sleep(struct dvb_frontend * fe)3393*4882a593Smuzhiyun static int dib8000_sleep(struct dvb_frontend *fe)
3394*4882a593Smuzhiyun {
3395*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
3396*4882a593Smuzhiyun 	u8 index_frontend;
3397*4882a593Smuzhiyun 	int ret;
3398*4882a593Smuzhiyun 
3399*4882a593Smuzhiyun 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3400*4882a593Smuzhiyun 		ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
3401*4882a593Smuzhiyun 		if (ret < 0)
3402*4882a593Smuzhiyun 			return ret;
3403*4882a593Smuzhiyun 	}
3404*4882a593Smuzhiyun 
3405*4882a593Smuzhiyun 	if (state->revision != 0x8090)
3406*4882a593Smuzhiyun 		dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
3407*4882a593Smuzhiyun 	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
3408*4882a593Smuzhiyun 	return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
3409*4882a593Smuzhiyun }
3410*4882a593Smuzhiyun 
3411*4882a593Smuzhiyun static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat);
3412*4882a593Smuzhiyun 
dib8000_get_frontend(struct dvb_frontend * fe,struct dtv_frontend_properties * c)3413*4882a593Smuzhiyun static int dib8000_get_frontend(struct dvb_frontend *fe,
3414*4882a593Smuzhiyun 				struct dtv_frontend_properties *c)
3415*4882a593Smuzhiyun {
3416*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
3417*4882a593Smuzhiyun 	u16 i, val = 0;
3418*4882a593Smuzhiyun 	enum fe_status stat = 0;
3419*4882a593Smuzhiyun 	u8 index_frontend, sub_index_frontend;
3420*4882a593Smuzhiyun 
3421*4882a593Smuzhiyun 	c->bandwidth_hz = 6000000;
3422*4882a593Smuzhiyun 
3423*4882a593Smuzhiyun 	/*
3424*4882a593Smuzhiyun 	 * If called to early, get_frontend makes dib8000_tune to either
3425*4882a593Smuzhiyun 	 * not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail.
3426*4882a593Smuzhiyun 	 * So, let's just return if frontend 0 has not locked.
3427*4882a593Smuzhiyun 	 */
3428*4882a593Smuzhiyun 	dib8000_read_status(fe, &stat);
3429*4882a593Smuzhiyun 	if (!(stat & FE_HAS_SYNC))
3430*4882a593Smuzhiyun 		return 0;
3431*4882a593Smuzhiyun 
3432*4882a593Smuzhiyun 	dprintk("dib8000_get_frontend: TMCC lock\n");
3433*4882a593Smuzhiyun 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3434*4882a593Smuzhiyun 		state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
3435*4882a593Smuzhiyun 		if (stat&FE_HAS_SYNC) {
3436*4882a593Smuzhiyun 			dprintk("TMCC lock on the slave%i\n", index_frontend);
3437*4882a593Smuzhiyun 			/* synchronize the cache with the other frontends */
3438*4882a593Smuzhiyun 			state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], c);
3439*4882a593Smuzhiyun 			for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {
3440*4882a593Smuzhiyun 				if (sub_index_frontend != index_frontend) {
3441*4882a593Smuzhiyun 					state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3442*4882a593Smuzhiyun 					state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3443*4882a593Smuzhiyun 					state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3444*4882a593Smuzhiyun 					state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3445*4882a593Smuzhiyun 					state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3446*4882a593Smuzhiyun 					for (i = 0; i < 3; i++) {
3447*4882a593Smuzhiyun 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3448*4882a593Smuzhiyun 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3449*4882a593Smuzhiyun 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3450*4882a593Smuzhiyun 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3451*4882a593Smuzhiyun 					}
3452*4882a593Smuzhiyun 				}
3453*4882a593Smuzhiyun 			}
3454*4882a593Smuzhiyun 			return 0;
3455*4882a593Smuzhiyun 		}
3456*4882a593Smuzhiyun 	}
3457*4882a593Smuzhiyun 
3458*4882a593Smuzhiyun 	c->isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
3459*4882a593Smuzhiyun 
3460*4882a593Smuzhiyun 	if (state->revision == 0x8090)
3461*4882a593Smuzhiyun 		val = dib8000_read_word(state, 572);
3462*4882a593Smuzhiyun 	else
3463*4882a593Smuzhiyun 		val = dib8000_read_word(state, 570);
3464*4882a593Smuzhiyun 	c->inversion = (val & 0x40) >> 6;
3465*4882a593Smuzhiyun 	switch ((val & 0x30) >> 4) {
3466*4882a593Smuzhiyun 	case 1:
3467*4882a593Smuzhiyun 		c->transmission_mode = TRANSMISSION_MODE_2K;
3468*4882a593Smuzhiyun 		dprintk("dib8000_get_frontend: transmission mode 2K\n");
3469*4882a593Smuzhiyun 		break;
3470*4882a593Smuzhiyun 	case 2:
3471*4882a593Smuzhiyun 		c->transmission_mode = TRANSMISSION_MODE_4K;
3472*4882a593Smuzhiyun 		dprintk("dib8000_get_frontend: transmission mode 4K\n");
3473*4882a593Smuzhiyun 		break;
3474*4882a593Smuzhiyun 	case 3:
3475*4882a593Smuzhiyun 	default:
3476*4882a593Smuzhiyun 		c->transmission_mode = TRANSMISSION_MODE_8K;
3477*4882a593Smuzhiyun 		dprintk("dib8000_get_frontend: transmission mode 8K\n");
3478*4882a593Smuzhiyun 		break;
3479*4882a593Smuzhiyun 	}
3480*4882a593Smuzhiyun 
3481*4882a593Smuzhiyun 	switch (val & 0x3) {
3482*4882a593Smuzhiyun 	case 0:
3483*4882a593Smuzhiyun 		c->guard_interval = GUARD_INTERVAL_1_32;
3484*4882a593Smuzhiyun 		dprintk("dib8000_get_frontend: Guard Interval = 1/32\n");
3485*4882a593Smuzhiyun 		break;
3486*4882a593Smuzhiyun 	case 1:
3487*4882a593Smuzhiyun 		c->guard_interval = GUARD_INTERVAL_1_16;
3488*4882a593Smuzhiyun 		dprintk("dib8000_get_frontend: Guard Interval = 1/16\n");
3489*4882a593Smuzhiyun 		break;
3490*4882a593Smuzhiyun 	case 2:
3491*4882a593Smuzhiyun 		dprintk("dib8000_get_frontend: Guard Interval = 1/8\n");
3492*4882a593Smuzhiyun 		c->guard_interval = GUARD_INTERVAL_1_8;
3493*4882a593Smuzhiyun 		break;
3494*4882a593Smuzhiyun 	case 3:
3495*4882a593Smuzhiyun 		dprintk("dib8000_get_frontend: Guard Interval = 1/4\n");
3496*4882a593Smuzhiyun 		c->guard_interval = GUARD_INTERVAL_1_4;
3497*4882a593Smuzhiyun 		break;
3498*4882a593Smuzhiyun 	}
3499*4882a593Smuzhiyun 
3500*4882a593Smuzhiyun 	val = dib8000_read_word(state, 505);
3501*4882a593Smuzhiyun 	c->isdbt_partial_reception = val & 1;
3502*4882a593Smuzhiyun 	dprintk("dib8000_get_frontend: partial_reception = %d\n", c->isdbt_partial_reception);
3503*4882a593Smuzhiyun 
3504*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
3505*4882a593Smuzhiyun 		int show;
3506*4882a593Smuzhiyun 
3507*4882a593Smuzhiyun 		val = dib8000_read_word(state, 493 + i) & 0x0f;
3508*4882a593Smuzhiyun 		c->layer[i].segment_count = val;
3509*4882a593Smuzhiyun 
3510*4882a593Smuzhiyun 		if (val == 0 || val > 13)
3511*4882a593Smuzhiyun 			show = 0;
3512*4882a593Smuzhiyun 		else
3513*4882a593Smuzhiyun 			show = 1;
3514*4882a593Smuzhiyun 
3515*4882a593Smuzhiyun 		if (show)
3516*4882a593Smuzhiyun 			dprintk("dib8000_get_frontend: Layer %d segments = %d\n",
3517*4882a593Smuzhiyun 				i, c->layer[i].segment_count);
3518*4882a593Smuzhiyun 
3519*4882a593Smuzhiyun 		val = dib8000_read_word(state, 499 + i) & 0x3;
3520*4882a593Smuzhiyun 		/* Interleaving can be 0, 1, 2 or 4 */
3521*4882a593Smuzhiyun 		if (val == 3)
3522*4882a593Smuzhiyun 			val = 4;
3523*4882a593Smuzhiyun 		c->layer[i].interleaving = val;
3524*4882a593Smuzhiyun 		if (show)
3525*4882a593Smuzhiyun 			dprintk("dib8000_get_frontend: Layer %d time_intlv = %d\n",
3526*4882a593Smuzhiyun 				i, c->layer[i].interleaving);
3527*4882a593Smuzhiyun 
3528*4882a593Smuzhiyun 		val = dib8000_read_word(state, 481 + i);
3529*4882a593Smuzhiyun 		switch (val & 0x7) {
3530*4882a593Smuzhiyun 		case 1:
3531*4882a593Smuzhiyun 			c->layer[i].fec = FEC_1_2;
3532*4882a593Smuzhiyun 			if (show)
3533*4882a593Smuzhiyun 				dprintk("dib8000_get_frontend: Layer %d Code Rate = 1/2\n", i);
3534*4882a593Smuzhiyun 			break;
3535*4882a593Smuzhiyun 		case 2:
3536*4882a593Smuzhiyun 			c->layer[i].fec = FEC_2_3;
3537*4882a593Smuzhiyun 			if (show)
3538*4882a593Smuzhiyun 				dprintk("dib8000_get_frontend: Layer %d Code Rate = 2/3\n", i);
3539*4882a593Smuzhiyun 			break;
3540*4882a593Smuzhiyun 		case 3:
3541*4882a593Smuzhiyun 			c->layer[i].fec = FEC_3_4;
3542*4882a593Smuzhiyun 			if (show)
3543*4882a593Smuzhiyun 				dprintk("dib8000_get_frontend: Layer %d Code Rate = 3/4\n", i);
3544*4882a593Smuzhiyun 			break;
3545*4882a593Smuzhiyun 		case 5:
3546*4882a593Smuzhiyun 			c->layer[i].fec = FEC_5_6;
3547*4882a593Smuzhiyun 			if (show)
3548*4882a593Smuzhiyun 				dprintk("dib8000_get_frontend: Layer %d Code Rate = 5/6\n", i);
3549*4882a593Smuzhiyun 			break;
3550*4882a593Smuzhiyun 		default:
3551*4882a593Smuzhiyun 			c->layer[i].fec = FEC_7_8;
3552*4882a593Smuzhiyun 			if (show)
3553*4882a593Smuzhiyun 				dprintk("dib8000_get_frontend: Layer %d Code Rate = 7/8\n", i);
3554*4882a593Smuzhiyun 			break;
3555*4882a593Smuzhiyun 		}
3556*4882a593Smuzhiyun 
3557*4882a593Smuzhiyun 		val = dib8000_read_word(state, 487 + i);
3558*4882a593Smuzhiyun 		switch (val & 0x3) {
3559*4882a593Smuzhiyun 		case 0:
3560*4882a593Smuzhiyun 			c->layer[i].modulation = DQPSK;
3561*4882a593Smuzhiyun 			if (show)
3562*4882a593Smuzhiyun 				dprintk("dib8000_get_frontend: Layer %d DQPSK\n", i);
3563*4882a593Smuzhiyun 			break;
3564*4882a593Smuzhiyun 		case 1:
3565*4882a593Smuzhiyun 			c->layer[i].modulation = QPSK;
3566*4882a593Smuzhiyun 			if (show)
3567*4882a593Smuzhiyun 				dprintk("dib8000_get_frontend: Layer %d QPSK\n", i);
3568*4882a593Smuzhiyun 			break;
3569*4882a593Smuzhiyun 		case 2:
3570*4882a593Smuzhiyun 			c->layer[i].modulation = QAM_16;
3571*4882a593Smuzhiyun 			if (show)
3572*4882a593Smuzhiyun 				dprintk("dib8000_get_frontend: Layer %d QAM16\n", i);
3573*4882a593Smuzhiyun 			break;
3574*4882a593Smuzhiyun 		case 3:
3575*4882a593Smuzhiyun 		default:
3576*4882a593Smuzhiyun 			c->layer[i].modulation = QAM_64;
3577*4882a593Smuzhiyun 			if (show)
3578*4882a593Smuzhiyun 				dprintk("dib8000_get_frontend: Layer %d QAM64\n", i);
3579*4882a593Smuzhiyun 			break;
3580*4882a593Smuzhiyun 		}
3581*4882a593Smuzhiyun 	}
3582*4882a593Smuzhiyun 
3583*4882a593Smuzhiyun 	/* synchronize the cache with the other frontends */
3584*4882a593Smuzhiyun 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3585*4882a593Smuzhiyun 		state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = c->isdbt_sb_mode;
3586*4882a593Smuzhiyun 		state->fe[index_frontend]->dtv_property_cache.inversion = c->inversion;
3587*4882a593Smuzhiyun 		state->fe[index_frontend]->dtv_property_cache.transmission_mode = c->transmission_mode;
3588*4882a593Smuzhiyun 		state->fe[index_frontend]->dtv_property_cache.guard_interval = c->guard_interval;
3589*4882a593Smuzhiyun 		state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = c->isdbt_partial_reception;
3590*4882a593Smuzhiyun 		for (i = 0; i < 3; i++) {
3591*4882a593Smuzhiyun 			state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = c->layer[i].segment_count;
3592*4882a593Smuzhiyun 			state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = c->layer[i].interleaving;
3593*4882a593Smuzhiyun 			state->fe[index_frontend]->dtv_property_cache.layer[i].fec = c->layer[i].fec;
3594*4882a593Smuzhiyun 			state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = c->layer[i].modulation;
3595*4882a593Smuzhiyun 		}
3596*4882a593Smuzhiyun 	}
3597*4882a593Smuzhiyun 	return 0;
3598*4882a593Smuzhiyun }
3599*4882a593Smuzhiyun 
dib8000_set_frontend(struct dvb_frontend * fe)3600*4882a593Smuzhiyun static int dib8000_set_frontend(struct dvb_frontend *fe)
3601*4882a593Smuzhiyun {
3602*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
3603*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3604*4882a593Smuzhiyun 	int l, i, active, time, time_slave = 0;
3605*4882a593Smuzhiyun 	u8 exit_condition, index_frontend;
3606*4882a593Smuzhiyun 	unsigned long delay, callback_time;
3607*4882a593Smuzhiyun 
3608*4882a593Smuzhiyun 	if (c->frequency == 0) {
3609*4882a593Smuzhiyun 		dprintk("dib8000: must at least specify frequency\n");
3610*4882a593Smuzhiyun 		return 0;
3611*4882a593Smuzhiyun 	}
3612*4882a593Smuzhiyun 
3613*4882a593Smuzhiyun 	if (c->bandwidth_hz == 0) {
3614*4882a593Smuzhiyun 		dprintk("dib8000: no bandwidth specified, set to default\n");
3615*4882a593Smuzhiyun 		c->bandwidth_hz = 6000000;
3616*4882a593Smuzhiyun 	}
3617*4882a593Smuzhiyun 
3618*4882a593Smuzhiyun 	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3619*4882a593Smuzhiyun 		/* synchronization of the cache */
3620*4882a593Smuzhiyun 		state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
3621*4882a593Smuzhiyun 		memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
3622*4882a593Smuzhiyun 
3623*4882a593Smuzhiyun 		/* set output mode and diversity input */
3624*4882a593Smuzhiyun 		if (state->revision != 0x8090) {
3625*4882a593Smuzhiyun 			dib8000_set_diversity_in(state->fe[index_frontend], 1);
3626*4882a593Smuzhiyun 			if (index_frontend != 0)
3627*4882a593Smuzhiyun 				dib8000_set_output_mode(state->fe[index_frontend],
3628*4882a593Smuzhiyun 						OUTMODE_DIVERSITY);
3629*4882a593Smuzhiyun 			else
3630*4882a593Smuzhiyun 				dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3631*4882a593Smuzhiyun 		} else {
3632*4882a593Smuzhiyun 			dib8096p_set_diversity_in(state->fe[index_frontend], 1);
3633*4882a593Smuzhiyun 			if (index_frontend != 0)
3634*4882a593Smuzhiyun 				dib8096p_set_output_mode(state->fe[index_frontend],
3635*4882a593Smuzhiyun 						OUTMODE_DIVERSITY);
3636*4882a593Smuzhiyun 			else
3637*4882a593Smuzhiyun 				dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3638*4882a593Smuzhiyun 		}
3639*4882a593Smuzhiyun 
3640*4882a593Smuzhiyun 		/* tune the tuner */
3641*4882a593Smuzhiyun 		if (state->fe[index_frontend]->ops.tuner_ops.set_params)
3642*4882a593Smuzhiyun 			state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
3643*4882a593Smuzhiyun 
3644*4882a593Smuzhiyun 		dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
3645*4882a593Smuzhiyun 	}
3646*4882a593Smuzhiyun 
3647*4882a593Smuzhiyun 	/* turn off the diversity of the last chip */
3648*4882a593Smuzhiyun 	if (state->revision != 0x8090)
3649*4882a593Smuzhiyun 		dib8000_set_diversity_in(state->fe[index_frontend - 1], 0);
3650*4882a593Smuzhiyun 	else
3651*4882a593Smuzhiyun 		dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0);
3652*4882a593Smuzhiyun 
3653*4882a593Smuzhiyun 	/* start up the AGC */
3654*4882a593Smuzhiyun 	do {
3655*4882a593Smuzhiyun 		time = dib8000_agc_startup(state->fe[0]);
3656*4882a593Smuzhiyun 		for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3657*4882a593Smuzhiyun 			time_slave = dib8000_agc_startup(state->fe[index_frontend]);
3658*4882a593Smuzhiyun 			if (time == 0)
3659*4882a593Smuzhiyun 				time = time_slave;
3660*4882a593Smuzhiyun 			else if ((time_slave != 0) && (time_slave > time))
3661*4882a593Smuzhiyun 				time = time_slave;
3662*4882a593Smuzhiyun 		}
3663*4882a593Smuzhiyun 		if (time == 0)
3664*4882a593Smuzhiyun 			break;
3665*4882a593Smuzhiyun 
3666*4882a593Smuzhiyun 		/*
3667*4882a593Smuzhiyun 		 * Despite dib8000_agc_startup returns time at a 0.1 ms range,
3668*4882a593Smuzhiyun 		 * the actual sleep time depends on CONFIG_HZ. The worse case
3669*4882a593Smuzhiyun 		 * is when CONFIG_HZ=100. In such case, the minimum granularity
3670*4882a593Smuzhiyun 		 * is 10ms. On some real field tests, the tuner sometimes don't
3671*4882a593Smuzhiyun 		 * lock when this timer is lower than 10ms. So, enforce a 10ms
3672*4882a593Smuzhiyun 		 * granularity.
3673*4882a593Smuzhiyun 		 */
3674*4882a593Smuzhiyun 		time = 10 * (time + 99)/100;
3675*4882a593Smuzhiyun 		usleep_range(time * 1000, (time + 1) * 1000);
3676*4882a593Smuzhiyun 		exit_condition = 1;
3677*4882a593Smuzhiyun 		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3678*4882a593Smuzhiyun 			if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
3679*4882a593Smuzhiyun 				exit_condition = 0;
3680*4882a593Smuzhiyun 				break;
3681*4882a593Smuzhiyun 			}
3682*4882a593Smuzhiyun 		}
3683*4882a593Smuzhiyun 	} while (exit_condition == 0);
3684*4882a593Smuzhiyun 
3685*4882a593Smuzhiyun 	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
3686*4882a593Smuzhiyun 		dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
3687*4882a593Smuzhiyun 
3688*4882a593Smuzhiyun 	active = 1;
3689*4882a593Smuzhiyun 	do {
3690*4882a593Smuzhiyun 		callback_time = 0;
3691*4882a593Smuzhiyun 		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3692*4882a593Smuzhiyun 			delay = dib8000_tune(state->fe[index_frontend]);
3693*4882a593Smuzhiyun 			if (delay != 0) {
3694*4882a593Smuzhiyun 				delay = jiffies + usecs_to_jiffies(100 * delay);
3695*4882a593Smuzhiyun 				if (!callback_time || delay < callback_time)
3696*4882a593Smuzhiyun 					callback_time = delay;
3697*4882a593Smuzhiyun 			}
3698*4882a593Smuzhiyun 
3699*4882a593Smuzhiyun 			/* we are in autosearch */
3700*4882a593Smuzhiyun 			if (state->channel_parameters_set == 0) { /* searching */
3701*4882a593Smuzhiyun 				if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) {
3702*4882a593Smuzhiyun 					dprintk("autosearch succeeded on fe%i\n", index_frontend);
3703*4882a593Smuzhiyun 					dib8000_get_frontend(state->fe[index_frontend], c); /* we read the channel parameters from the frontend which was successful */
3704*4882a593Smuzhiyun 					state->channel_parameters_set = 1;
3705*4882a593Smuzhiyun 
3706*4882a593Smuzhiyun 					for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
3707*4882a593Smuzhiyun 						if (l != index_frontend) { /* and for all frontend except the successful one */
3708*4882a593Smuzhiyun 							dprintk("Restarting frontend %d\n", l);
3709*4882a593Smuzhiyun 							dib8000_tune_restart_from_demod(state->fe[l]);
3710*4882a593Smuzhiyun 
3711*4882a593Smuzhiyun 							state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3712*4882a593Smuzhiyun 							state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3713*4882a593Smuzhiyun 							state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3714*4882a593Smuzhiyun 							state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3715*4882a593Smuzhiyun 							state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3716*4882a593Smuzhiyun 							for (i = 0; i < 3; i++) {
3717*4882a593Smuzhiyun 								state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3718*4882a593Smuzhiyun 								state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3719*4882a593Smuzhiyun 								state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3720*4882a593Smuzhiyun 								state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3721*4882a593Smuzhiyun 							}
3722*4882a593Smuzhiyun 
3723*4882a593Smuzhiyun 						}
3724*4882a593Smuzhiyun 					}
3725*4882a593Smuzhiyun 				}
3726*4882a593Smuzhiyun 			}
3727*4882a593Smuzhiyun 		}
3728*4882a593Smuzhiyun 		/* tuning is done when the master frontend is done (failed or success) */
3729*4882a593Smuzhiyun 		if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
3730*4882a593Smuzhiyun 				dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED ||
3731*4882a593Smuzhiyun 				dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) {
3732*4882a593Smuzhiyun 			active = 0;
3733*4882a593Smuzhiyun 			/* we need to wait for all frontends to be finished */
3734*4882a593Smuzhiyun 			for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3735*4882a593Smuzhiyun 				if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP)
3736*4882a593Smuzhiyun 					active = 1;
3737*4882a593Smuzhiyun 			}
3738*4882a593Smuzhiyun 			if (active == 0)
3739*4882a593Smuzhiyun 				dprintk("tuning done with status %d\n", dib8000_get_status(state->fe[0]));
3740*4882a593Smuzhiyun 		}
3741*4882a593Smuzhiyun 
3742*4882a593Smuzhiyun 		if ((active == 1) && (callback_time == 0)) {
3743*4882a593Smuzhiyun 			dprintk("strange callback time something went wrong\n");
3744*4882a593Smuzhiyun 			active = 0;
3745*4882a593Smuzhiyun 		}
3746*4882a593Smuzhiyun 
3747*4882a593Smuzhiyun 		while ((active == 1) && (time_before(jiffies, callback_time)))
3748*4882a593Smuzhiyun 			msleep(100);
3749*4882a593Smuzhiyun 	} while (active);
3750*4882a593Smuzhiyun 
3751*4882a593Smuzhiyun 	/* set output mode */
3752*4882a593Smuzhiyun 	if (state->revision != 0x8090)
3753*4882a593Smuzhiyun 		dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
3754*4882a593Smuzhiyun 	else {
3755*4882a593Smuzhiyun 		dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
3756*4882a593Smuzhiyun 		if (state->cfg.enMpegOutput == 0) {
3757*4882a593Smuzhiyun 			dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
3758*4882a593Smuzhiyun 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
3759*4882a593Smuzhiyun 		}
3760*4882a593Smuzhiyun 	}
3761*4882a593Smuzhiyun 
3762*4882a593Smuzhiyun 	return 0;
3763*4882a593Smuzhiyun }
3764*4882a593Smuzhiyun 
3765*4882a593Smuzhiyun static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat);
3766*4882a593Smuzhiyun 
dib8000_read_status(struct dvb_frontend * fe,enum fe_status * stat)3767*4882a593Smuzhiyun static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat)
3768*4882a593Smuzhiyun {
3769*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
3770*4882a593Smuzhiyun 	u16 lock_slave = 0, lock;
3771*4882a593Smuzhiyun 	u8 index_frontend;
3772*4882a593Smuzhiyun 
3773*4882a593Smuzhiyun 	lock = dib8000_read_lock(fe);
3774*4882a593Smuzhiyun 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
3775*4882a593Smuzhiyun 		lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
3776*4882a593Smuzhiyun 
3777*4882a593Smuzhiyun 	*stat = 0;
3778*4882a593Smuzhiyun 
3779*4882a593Smuzhiyun 	if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
3780*4882a593Smuzhiyun 		*stat |= FE_HAS_SIGNAL;
3781*4882a593Smuzhiyun 
3782*4882a593Smuzhiyun 	if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
3783*4882a593Smuzhiyun 		*stat |= FE_HAS_CARRIER;
3784*4882a593Smuzhiyun 
3785*4882a593Smuzhiyun 	if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
3786*4882a593Smuzhiyun 		*stat |= FE_HAS_SYNC;
3787*4882a593Smuzhiyun 
3788*4882a593Smuzhiyun 	if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
3789*4882a593Smuzhiyun 		*stat |= FE_HAS_LOCK;
3790*4882a593Smuzhiyun 
3791*4882a593Smuzhiyun 	if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
3792*4882a593Smuzhiyun 		lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
3793*4882a593Smuzhiyun 		if (lock & 0x01)
3794*4882a593Smuzhiyun 			*stat |= FE_HAS_VITERBI;
3795*4882a593Smuzhiyun 
3796*4882a593Smuzhiyun 		lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
3797*4882a593Smuzhiyun 		if (lock & 0x01)
3798*4882a593Smuzhiyun 			*stat |= FE_HAS_VITERBI;
3799*4882a593Smuzhiyun 
3800*4882a593Smuzhiyun 		lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
3801*4882a593Smuzhiyun 		if (lock & 0x01)
3802*4882a593Smuzhiyun 			*stat |= FE_HAS_VITERBI;
3803*4882a593Smuzhiyun 	}
3804*4882a593Smuzhiyun 	dib8000_get_stats(fe, *stat);
3805*4882a593Smuzhiyun 
3806*4882a593Smuzhiyun 	return 0;
3807*4882a593Smuzhiyun }
3808*4882a593Smuzhiyun 
dib8000_read_ber(struct dvb_frontend * fe,u32 * ber)3809*4882a593Smuzhiyun static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
3810*4882a593Smuzhiyun {
3811*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
3812*4882a593Smuzhiyun 
3813*4882a593Smuzhiyun 	/* 13 segments */
3814*4882a593Smuzhiyun 	if (state->revision == 0x8090)
3815*4882a593Smuzhiyun 		*ber = (dib8000_read_word(state, 562) << 16) |
3816*4882a593Smuzhiyun 			dib8000_read_word(state, 563);
3817*4882a593Smuzhiyun 	else
3818*4882a593Smuzhiyun 		*ber = (dib8000_read_word(state, 560) << 16) |
3819*4882a593Smuzhiyun 			dib8000_read_word(state, 561);
3820*4882a593Smuzhiyun 	return 0;
3821*4882a593Smuzhiyun }
3822*4882a593Smuzhiyun 
dib8000_read_unc_blocks(struct dvb_frontend * fe,u32 * unc)3823*4882a593Smuzhiyun static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
3824*4882a593Smuzhiyun {
3825*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
3826*4882a593Smuzhiyun 
3827*4882a593Smuzhiyun 	/* packet error on 13 seg */
3828*4882a593Smuzhiyun 	if (state->revision == 0x8090)
3829*4882a593Smuzhiyun 		*unc = dib8000_read_word(state, 567);
3830*4882a593Smuzhiyun 	else
3831*4882a593Smuzhiyun 		*unc = dib8000_read_word(state, 565);
3832*4882a593Smuzhiyun 	return 0;
3833*4882a593Smuzhiyun }
3834*4882a593Smuzhiyun 
dib8000_read_signal_strength(struct dvb_frontend * fe,u16 * strength)3835*4882a593Smuzhiyun static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
3836*4882a593Smuzhiyun {
3837*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
3838*4882a593Smuzhiyun 	u8 index_frontend;
3839*4882a593Smuzhiyun 	u16 val;
3840*4882a593Smuzhiyun 
3841*4882a593Smuzhiyun 	*strength = 0;
3842*4882a593Smuzhiyun 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3843*4882a593Smuzhiyun 		state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
3844*4882a593Smuzhiyun 		if (val > 65535 - *strength)
3845*4882a593Smuzhiyun 			*strength = 65535;
3846*4882a593Smuzhiyun 		else
3847*4882a593Smuzhiyun 			*strength += val;
3848*4882a593Smuzhiyun 	}
3849*4882a593Smuzhiyun 
3850*4882a593Smuzhiyun 	val = 65535 - dib8000_read_word(state, 390);
3851*4882a593Smuzhiyun 	if (val > 65535 - *strength)
3852*4882a593Smuzhiyun 		*strength = 65535;
3853*4882a593Smuzhiyun 	else
3854*4882a593Smuzhiyun 		*strength += val;
3855*4882a593Smuzhiyun 	return 0;
3856*4882a593Smuzhiyun }
3857*4882a593Smuzhiyun 
dib8000_get_snr(struct dvb_frontend * fe)3858*4882a593Smuzhiyun static u32 dib8000_get_snr(struct dvb_frontend *fe)
3859*4882a593Smuzhiyun {
3860*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
3861*4882a593Smuzhiyun 	u32 n, s, exp;
3862*4882a593Smuzhiyun 	u16 val;
3863*4882a593Smuzhiyun 
3864*4882a593Smuzhiyun 	if (state->revision != 0x8090)
3865*4882a593Smuzhiyun 		val = dib8000_read_word(state, 542);
3866*4882a593Smuzhiyun 	else
3867*4882a593Smuzhiyun 		val = dib8000_read_word(state, 544);
3868*4882a593Smuzhiyun 	n = (val >> 6) & 0xff;
3869*4882a593Smuzhiyun 	exp = (val & 0x3f);
3870*4882a593Smuzhiyun 	if ((exp & 0x20) != 0)
3871*4882a593Smuzhiyun 		exp -= 0x40;
3872*4882a593Smuzhiyun 	n <<= exp+16;
3873*4882a593Smuzhiyun 
3874*4882a593Smuzhiyun 	if (state->revision != 0x8090)
3875*4882a593Smuzhiyun 		val = dib8000_read_word(state, 543);
3876*4882a593Smuzhiyun 	else
3877*4882a593Smuzhiyun 		val = dib8000_read_word(state, 545);
3878*4882a593Smuzhiyun 	s = (val >> 6) & 0xff;
3879*4882a593Smuzhiyun 	exp = (val & 0x3f);
3880*4882a593Smuzhiyun 	if ((exp & 0x20) != 0)
3881*4882a593Smuzhiyun 		exp -= 0x40;
3882*4882a593Smuzhiyun 	s <<= exp+16;
3883*4882a593Smuzhiyun 
3884*4882a593Smuzhiyun 	if (n > 0) {
3885*4882a593Smuzhiyun 		u32 t = (s/n) << 16;
3886*4882a593Smuzhiyun 		return t + ((s << 16) - n*t) / n;
3887*4882a593Smuzhiyun 	}
3888*4882a593Smuzhiyun 	return 0xffffffff;
3889*4882a593Smuzhiyun }
3890*4882a593Smuzhiyun 
dib8000_read_snr(struct dvb_frontend * fe,u16 * snr)3891*4882a593Smuzhiyun static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
3892*4882a593Smuzhiyun {
3893*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
3894*4882a593Smuzhiyun 	u8 index_frontend;
3895*4882a593Smuzhiyun 	u32 snr_master;
3896*4882a593Smuzhiyun 
3897*4882a593Smuzhiyun 	snr_master = dib8000_get_snr(fe);
3898*4882a593Smuzhiyun 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
3899*4882a593Smuzhiyun 		snr_master += dib8000_get_snr(state->fe[index_frontend]);
3900*4882a593Smuzhiyun 
3901*4882a593Smuzhiyun 	if ((snr_master >> 16) != 0) {
3902*4882a593Smuzhiyun 		snr_master = 10*intlog10(snr_master>>16);
3903*4882a593Smuzhiyun 		*snr = snr_master / ((1 << 24) / 10);
3904*4882a593Smuzhiyun 	}
3905*4882a593Smuzhiyun 	else
3906*4882a593Smuzhiyun 		*snr = 0;
3907*4882a593Smuzhiyun 
3908*4882a593Smuzhiyun 	return 0;
3909*4882a593Smuzhiyun }
3910*4882a593Smuzhiyun 
3911*4882a593Smuzhiyun struct per_layer_regs {
3912*4882a593Smuzhiyun 	u16 lock, ber, per;
3913*4882a593Smuzhiyun };
3914*4882a593Smuzhiyun 
3915*4882a593Smuzhiyun static const struct per_layer_regs per_layer_regs[] = {
3916*4882a593Smuzhiyun 	{ 554, 560, 562 },
3917*4882a593Smuzhiyun 	{ 555, 576, 578 },
3918*4882a593Smuzhiyun 	{ 556, 581, 583 },
3919*4882a593Smuzhiyun };
3920*4882a593Smuzhiyun 
3921*4882a593Smuzhiyun struct linear_segments {
3922*4882a593Smuzhiyun 	unsigned x;
3923*4882a593Smuzhiyun 	signed y;
3924*4882a593Smuzhiyun };
3925*4882a593Smuzhiyun 
3926*4882a593Smuzhiyun /*
3927*4882a593Smuzhiyun  * Table to estimate signal strength in dBm.
3928*4882a593Smuzhiyun  * This table was empirically determinated by measuring the signal
3929*4882a593Smuzhiyun  * strength generated by a DTA-2111 RF generator directly connected into
3930*4882a593Smuzhiyun  * a dib8076 device (a PixelView PV-D231U stick), using a good quality
3931*4882a593Smuzhiyun  * 3 meters RC6 cable and good RC6 connectors.
3932*4882a593Smuzhiyun  * The real value can actually be different on other devices, depending
3933*4882a593Smuzhiyun  * on several factors, like if LNA is enabled or not, if diversity is
3934*4882a593Smuzhiyun  * enabled, type of connectors, etc.
3935*4882a593Smuzhiyun  * Yet, it is better to use this measure in dB than a random non-linear
3936*4882a593Smuzhiyun  * percentage value, especially for antenna adjustments.
3937*4882a593Smuzhiyun  * On my tests, the precision of the measure using this table is about
3938*4882a593Smuzhiyun  * 0.5 dB, with sounds reasonable enough.
3939*4882a593Smuzhiyun  */
3940*4882a593Smuzhiyun static struct linear_segments strength_to_db_table[] = {
3941*4882a593Smuzhiyun 	{ 55953, 108500 },	/* -22.5 dBm */
3942*4882a593Smuzhiyun 	{ 55394, 108000 },
3943*4882a593Smuzhiyun 	{ 53834, 107000 },
3944*4882a593Smuzhiyun 	{ 52863, 106000 },
3945*4882a593Smuzhiyun 	{ 52239, 105000 },
3946*4882a593Smuzhiyun 	{ 52012, 104000 },
3947*4882a593Smuzhiyun 	{ 51803, 103000 },
3948*4882a593Smuzhiyun 	{ 51566, 102000 },
3949*4882a593Smuzhiyun 	{ 51356, 101000 },
3950*4882a593Smuzhiyun 	{ 51112, 100000 },
3951*4882a593Smuzhiyun 	{ 50869,  99000 },
3952*4882a593Smuzhiyun 	{ 50600,  98000 },
3953*4882a593Smuzhiyun 	{ 50363,  97000 },
3954*4882a593Smuzhiyun 	{ 50117,  96000 },	/* -35 dBm */
3955*4882a593Smuzhiyun 	{ 49889,  95000 },
3956*4882a593Smuzhiyun 	{ 49680,  94000 },
3957*4882a593Smuzhiyun 	{ 49493,  93000 },
3958*4882a593Smuzhiyun 	{ 49302,  92000 },
3959*4882a593Smuzhiyun 	{ 48929,  91000 },
3960*4882a593Smuzhiyun 	{ 48416,  90000 },
3961*4882a593Smuzhiyun 	{ 48035,  89000 },
3962*4882a593Smuzhiyun 	{ 47593,  88000 },
3963*4882a593Smuzhiyun 	{ 47282,  87000 },
3964*4882a593Smuzhiyun 	{ 46953,  86000 },
3965*4882a593Smuzhiyun 	{ 46698,  85000 },
3966*4882a593Smuzhiyun 	{ 45617,  84000 },
3967*4882a593Smuzhiyun 	{ 44773,  83000 },
3968*4882a593Smuzhiyun 	{ 43845,  82000 },
3969*4882a593Smuzhiyun 	{ 43020,  81000 },
3970*4882a593Smuzhiyun 	{ 42010,  80000 },	/* -51 dBm */
3971*4882a593Smuzhiyun 	{     0,      0 },
3972*4882a593Smuzhiyun };
3973*4882a593Smuzhiyun 
interpolate_value(u32 value,struct linear_segments * segments,unsigned len)3974*4882a593Smuzhiyun static u32 interpolate_value(u32 value, struct linear_segments *segments,
3975*4882a593Smuzhiyun 			     unsigned len)
3976*4882a593Smuzhiyun {
3977*4882a593Smuzhiyun 	u64 tmp64;
3978*4882a593Smuzhiyun 	u32 dx;
3979*4882a593Smuzhiyun 	s32 dy;
3980*4882a593Smuzhiyun 	int i, ret;
3981*4882a593Smuzhiyun 
3982*4882a593Smuzhiyun 	if (value >= segments[0].x)
3983*4882a593Smuzhiyun 		return segments[0].y;
3984*4882a593Smuzhiyun 	if (value < segments[len-1].x)
3985*4882a593Smuzhiyun 		return segments[len-1].y;
3986*4882a593Smuzhiyun 
3987*4882a593Smuzhiyun 	for (i = 1; i < len - 1; i++) {
3988*4882a593Smuzhiyun 		/* If value is identical, no need to interpolate */
3989*4882a593Smuzhiyun 		if (value == segments[i].x)
3990*4882a593Smuzhiyun 			return segments[i].y;
3991*4882a593Smuzhiyun 		if (value > segments[i].x)
3992*4882a593Smuzhiyun 			break;
3993*4882a593Smuzhiyun 	}
3994*4882a593Smuzhiyun 
3995*4882a593Smuzhiyun 	/* Linear interpolation between the two (x,y) points */
3996*4882a593Smuzhiyun 	dy = segments[i - 1].y - segments[i].y;
3997*4882a593Smuzhiyun 	dx = segments[i - 1].x - segments[i].x;
3998*4882a593Smuzhiyun 
3999*4882a593Smuzhiyun 	tmp64 = value - segments[i].x;
4000*4882a593Smuzhiyun 	tmp64 *= dy;
4001*4882a593Smuzhiyun 	do_div(tmp64, dx);
4002*4882a593Smuzhiyun 	ret = segments[i].y + tmp64;
4003*4882a593Smuzhiyun 
4004*4882a593Smuzhiyun 	return ret;
4005*4882a593Smuzhiyun }
4006*4882a593Smuzhiyun 
dib8000_get_time_us(struct dvb_frontend * fe,int layer)4007*4882a593Smuzhiyun static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer)
4008*4882a593Smuzhiyun {
4009*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
4010*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
4011*4882a593Smuzhiyun 	int ini_layer, end_layer, i;
4012*4882a593Smuzhiyun 	u64 time_us, tmp64;
4013*4882a593Smuzhiyun 	u32 tmp, denom;
4014*4882a593Smuzhiyun 	int guard, rate_num, rate_denum = 1, bits_per_symbol, nsegs;
4015*4882a593Smuzhiyun 	int interleaving = 0, fft_div;
4016*4882a593Smuzhiyun 
4017*4882a593Smuzhiyun 	if (layer >= 0) {
4018*4882a593Smuzhiyun 		ini_layer = layer;
4019*4882a593Smuzhiyun 		end_layer = layer + 1;
4020*4882a593Smuzhiyun 	} else {
4021*4882a593Smuzhiyun 		ini_layer = 0;
4022*4882a593Smuzhiyun 		end_layer = 3;
4023*4882a593Smuzhiyun 	}
4024*4882a593Smuzhiyun 
4025*4882a593Smuzhiyun 	switch (c->guard_interval) {
4026*4882a593Smuzhiyun 	case GUARD_INTERVAL_1_4:
4027*4882a593Smuzhiyun 		guard = 4;
4028*4882a593Smuzhiyun 		break;
4029*4882a593Smuzhiyun 	case GUARD_INTERVAL_1_8:
4030*4882a593Smuzhiyun 		guard = 8;
4031*4882a593Smuzhiyun 		break;
4032*4882a593Smuzhiyun 	case GUARD_INTERVAL_1_16:
4033*4882a593Smuzhiyun 		guard = 16;
4034*4882a593Smuzhiyun 		break;
4035*4882a593Smuzhiyun 	default:
4036*4882a593Smuzhiyun 	case GUARD_INTERVAL_1_32:
4037*4882a593Smuzhiyun 		guard = 32;
4038*4882a593Smuzhiyun 		break;
4039*4882a593Smuzhiyun 	}
4040*4882a593Smuzhiyun 
4041*4882a593Smuzhiyun 	switch (c->transmission_mode) {
4042*4882a593Smuzhiyun 	case TRANSMISSION_MODE_2K:
4043*4882a593Smuzhiyun 		fft_div = 4;
4044*4882a593Smuzhiyun 		break;
4045*4882a593Smuzhiyun 	case TRANSMISSION_MODE_4K:
4046*4882a593Smuzhiyun 		fft_div = 2;
4047*4882a593Smuzhiyun 		break;
4048*4882a593Smuzhiyun 	default:
4049*4882a593Smuzhiyun 	case TRANSMISSION_MODE_8K:
4050*4882a593Smuzhiyun 		fft_div = 1;
4051*4882a593Smuzhiyun 		break;
4052*4882a593Smuzhiyun 	}
4053*4882a593Smuzhiyun 
4054*4882a593Smuzhiyun 	denom = 0;
4055*4882a593Smuzhiyun 	for (i = ini_layer; i < end_layer; i++) {
4056*4882a593Smuzhiyun 		nsegs = c->layer[i].segment_count;
4057*4882a593Smuzhiyun 		if (nsegs == 0 || nsegs > 13)
4058*4882a593Smuzhiyun 			continue;
4059*4882a593Smuzhiyun 
4060*4882a593Smuzhiyun 		switch (c->layer[i].modulation) {
4061*4882a593Smuzhiyun 		case DQPSK:
4062*4882a593Smuzhiyun 		case QPSK:
4063*4882a593Smuzhiyun 			bits_per_symbol = 2;
4064*4882a593Smuzhiyun 			break;
4065*4882a593Smuzhiyun 		case QAM_16:
4066*4882a593Smuzhiyun 			bits_per_symbol = 4;
4067*4882a593Smuzhiyun 			break;
4068*4882a593Smuzhiyun 		default:
4069*4882a593Smuzhiyun 		case QAM_64:
4070*4882a593Smuzhiyun 			bits_per_symbol = 6;
4071*4882a593Smuzhiyun 			break;
4072*4882a593Smuzhiyun 		}
4073*4882a593Smuzhiyun 
4074*4882a593Smuzhiyun 		switch (c->layer[i].fec) {
4075*4882a593Smuzhiyun 		case FEC_1_2:
4076*4882a593Smuzhiyun 			rate_num = 1;
4077*4882a593Smuzhiyun 			rate_denum = 2;
4078*4882a593Smuzhiyun 			break;
4079*4882a593Smuzhiyun 		case FEC_2_3:
4080*4882a593Smuzhiyun 			rate_num = 2;
4081*4882a593Smuzhiyun 			rate_denum = 3;
4082*4882a593Smuzhiyun 			break;
4083*4882a593Smuzhiyun 		case FEC_3_4:
4084*4882a593Smuzhiyun 			rate_num = 3;
4085*4882a593Smuzhiyun 			rate_denum = 4;
4086*4882a593Smuzhiyun 			break;
4087*4882a593Smuzhiyun 		case FEC_5_6:
4088*4882a593Smuzhiyun 			rate_num = 5;
4089*4882a593Smuzhiyun 			rate_denum = 6;
4090*4882a593Smuzhiyun 			break;
4091*4882a593Smuzhiyun 		default:
4092*4882a593Smuzhiyun 		case FEC_7_8:
4093*4882a593Smuzhiyun 			rate_num = 7;
4094*4882a593Smuzhiyun 			rate_denum = 8;
4095*4882a593Smuzhiyun 			break;
4096*4882a593Smuzhiyun 		}
4097*4882a593Smuzhiyun 
4098*4882a593Smuzhiyun 		interleaving = c->layer[i].interleaving;
4099*4882a593Smuzhiyun 
4100*4882a593Smuzhiyun 		denom += bits_per_symbol * rate_num * fft_div * nsegs * 384;
4101*4882a593Smuzhiyun 	}
4102*4882a593Smuzhiyun 
4103*4882a593Smuzhiyun 	/* If all goes wrong, wait for 1s for the next stats */
4104*4882a593Smuzhiyun 	if (!denom)
4105*4882a593Smuzhiyun 		return 0;
4106*4882a593Smuzhiyun 
4107*4882a593Smuzhiyun 	/* Estimate the period for the total bit rate */
4108*4882a593Smuzhiyun 	time_us = rate_denum * (1008 * 1562500L);
4109*4882a593Smuzhiyun 	tmp64 = time_us;
4110*4882a593Smuzhiyun 	do_div(tmp64, guard);
4111*4882a593Smuzhiyun 	time_us = time_us + tmp64;
4112*4882a593Smuzhiyun 	time_us += denom / 2;
4113*4882a593Smuzhiyun 	do_div(time_us, denom);
4114*4882a593Smuzhiyun 
4115*4882a593Smuzhiyun 	tmp = 1008 * 96 * interleaving;
4116*4882a593Smuzhiyun 	time_us += tmp + tmp / guard;
4117*4882a593Smuzhiyun 
4118*4882a593Smuzhiyun 	return time_us;
4119*4882a593Smuzhiyun }
4120*4882a593Smuzhiyun 
dib8000_get_stats(struct dvb_frontend * fe,enum fe_status stat)4121*4882a593Smuzhiyun static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat)
4122*4882a593Smuzhiyun {
4123*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
4124*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
4125*4882a593Smuzhiyun 	int i;
4126*4882a593Smuzhiyun 	int show_per_stats = 0;
4127*4882a593Smuzhiyun 	u32 time_us = 0, snr, val;
4128*4882a593Smuzhiyun 	u64 blocks;
4129*4882a593Smuzhiyun 	s32 db;
4130*4882a593Smuzhiyun 	u16 strength;
4131*4882a593Smuzhiyun 
4132*4882a593Smuzhiyun 	/* Get Signal strength */
4133*4882a593Smuzhiyun 	dib8000_read_signal_strength(fe, &strength);
4134*4882a593Smuzhiyun 	val = strength;
4135*4882a593Smuzhiyun 	db = interpolate_value(val,
4136*4882a593Smuzhiyun 			       strength_to_db_table,
4137*4882a593Smuzhiyun 			       ARRAY_SIZE(strength_to_db_table)) - 131000;
4138*4882a593Smuzhiyun 	c->strength.stat[0].svalue = db;
4139*4882a593Smuzhiyun 
4140*4882a593Smuzhiyun 	/* UCB/BER/CNR measures require lock */
4141*4882a593Smuzhiyun 	if (!(stat & FE_HAS_LOCK)) {
4142*4882a593Smuzhiyun 		c->cnr.len = 1;
4143*4882a593Smuzhiyun 		c->block_count.len = 1;
4144*4882a593Smuzhiyun 		c->block_error.len = 1;
4145*4882a593Smuzhiyun 		c->post_bit_error.len = 1;
4146*4882a593Smuzhiyun 		c->post_bit_count.len = 1;
4147*4882a593Smuzhiyun 		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4148*4882a593Smuzhiyun 		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4149*4882a593Smuzhiyun 		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4150*4882a593Smuzhiyun 		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4151*4882a593Smuzhiyun 		c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4152*4882a593Smuzhiyun 		return 0;
4153*4882a593Smuzhiyun 	}
4154*4882a593Smuzhiyun 
4155*4882a593Smuzhiyun 	/* Check if time for stats was elapsed */
4156*4882a593Smuzhiyun 	if (time_after(jiffies, state->per_jiffies_stats)) {
4157*4882a593Smuzhiyun 		state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
4158*4882a593Smuzhiyun 
4159*4882a593Smuzhiyun 		/* Get SNR */
4160*4882a593Smuzhiyun 		snr = dib8000_get_snr(fe);
4161*4882a593Smuzhiyun 		for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) {
4162*4882a593Smuzhiyun 			if (state->fe[i])
4163*4882a593Smuzhiyun 				snr += dib8000_get_snr(state->fe[i]);
4164*4882a593Smuzhiyun 		}
4165*4882a593Smuzhiyun 		snr = snr >> 16;
4166*4882a593Smuzhiyun 
4167*4882a593Smuzhiyun 		if (snr) {
4168*4882a593Smuzhiyun 			snr = 10 * intlog10(snr);
4169*4882a593Smuzhiyun 			snr = (1000L * snr) >> 24;
4170*4882a593Smuzhiyun 		} else {
4171*4882a593Smuzhiyun 			snr = 0;
4172*4882a593Smuzhiyun 		}
4173*4882a593Smuzhiyun 		c->cnr.stat[0].svalue = snr;
4174*4882a593Smuzhiyun 		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
4175*4882a593Smuzhiyun 
4176*4882a593Smuzhiyun 		/* Get UCB measures */
4177*4882a593Smuzhiyun 		dib8000_read_unc_blocks(fe, &val);
4178*4882a593Smuzhiyun 		if (val < state->init_ucb)
4179*4882a593Smuzhiyun 			state->init_ucb += 0x100000000LL;
4180*4882a593Smuzhiyun 
4181*4882a593Smuzhiyun 		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
4182*4882a593Smuzhiyun 		c->block_error.stat[0].uvalue = val + state->init_ucb;
4183*4882a593Smuzhiyun 
4184*4882a593Smuzhiyun 		/* Estimate the number of packets based on bitrate */
4185*4882a593Smuzhiyun 		if (!time_us)
4186*4882a593Smuzhiyun 			time_us = dib8000_get_time_us(fe, -1);
4187*4882a593Smuzhiyun 
4188*4882a593Smuzhiyun 		if (time_us) {
4189*4882a593Smuzhiyun 			blocks = 1250000ULL * 1000000ULL;
4190*4882a593Smuzhiyun 			do_div(blocks, time_us * 8 * 204);
4191*4882a593Smuzhiyun 			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
4192*4882a593Smuzhiyun 			c->block_count.stat[0].uvalue += blocks;
4193*4882a593Smuzhiyun 		}
4194*4882a593Smuzhiyun 
4195*4882a593Smuzhiyun 		show_per_stats = 1;
4196*4882a593Smuzhiyun 	}
4197*4882a593Smuzhiyun 
4198*4882a593Smuzhiyun 	/* Get post-BER measures */
4199*4882a593Smuzhiyun 	if (time_after(jiffies, state->ber_jiffies_stats)) {
4200*4882a593Smuzhiyun 		time_us = dib8000_get_time_us(fe, -1);
4201*4882a593Smuzhiyun 		state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
4202*4882a593Smuzhiyun 
4203*4882a593Smuzhiyun 		dprintk("Next all layers stats available in %u us.\n", time_us);
4204*4882a593Smuzhiyun 
4205*4882a593Smuzhiyun 		dib8000_read_ber(fe, &val);
4206*4882a593Smuzhiyun 		c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
4207*4882a593Smuzhiyun 		c->post_bit_error.stat[0].uvalue += val;
4208*4882a593Smuzhiyun 
4209*4882a593Smuzhiyun 		c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
4210*4882a593Smuzhiyun 		c->post_bit_count.stat[0].uvalue += 100000000;
4211*4882a593Smuzhiyun 	}
4212*4882a593Smuzhiyun 
4213*4882a593Smuzhiyun 	if (state->revision < 0x8002)
4214*4882a593Smuzhiyun 		return 0;
4215*4882a593Smuzhiyun 
4216*4882a593Smuzhiyun 	c->block_error.len = 4;
4217*4882a593Smuzhiyun 	c->post_bit_error.len = 4;
4218*4882a593Smuzhiyun 	c->post_bit_count.len = 4;
4219*4882a593Smuzhiyun 
4220*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
4221*4882a593Smuzhiyun 		unsigned nsegs = c->layer[i].segment_count;
4222*4882a593Smuzhiyun 
4223*4882a593Smuzhiyun 		if (nsegs == 0 || nsegs > 13)
4224*4882a593Smuzhiyun 			continue;
4225*4882a593Smuzhiyun 
4226*4882a593Smuzhiyun 		time_us = 0;
4227*4882a593Smuzhiyun 
4228*4882a593Smuzhiyun 		if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) {
4229*4882a593Smuzhiyun 			time_us = dib8000_get_time_us(fe, i);
4230*4882a593Smuzhiyun 
4231*4882a593Smuzhiyun 			state->ber_jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
4232*4882a593Smuzhiyun 			dprintk("Next layer %c  stats will be available in %u us\n",
4233*4882a593Smuzhiyun 				'A' + i, time_us);
4234*4882a593Smuzhiyun 
4235*4882a593Smuzhiyun 			val = dib8000_read_word(state, per_layer_regs[i].ber);
4236*4882a593Smuzhiyun 			c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
4237*4882a593Smuzhiyun 			c->post_bit_error.stat[1 + i].uvalue += val;
4238*4882a593Smuzhiyun 
4239*4882a593Smuzhiyun 			c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
4240*4882a593Smuzhiyun 			c->post_bit_count.stat[1 + i].uvalue += 100000000;
4241*4882a593Smuzhiyun 		}
4242*4882a593Smuzhiyun 
4243*4882a593Smuzhiyun 		if (show_per_stats) {
4244*4882a593Smuzhiyun 			val = dib8000_read_word(state, per_layer_regs[i].per);
4245*4882a593Smuzhiyun 
4246*4882a593Smuzhiyun 			c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
4247*4882a593Smuzhiyun 			c->block_error.stat[1 + i].uvalue += val;
4248*4882a593Smuzhiyun 
4249*4882a593Smuzhiyun 			if (!time_us)
4250*4882a593Smuzhiyun 				time_us = dib8000_get_time_us(fe, i);
4251*4882a593Smuzhiyun 			if (time_us) {
4252*4882a593Smuzhiyun 				blocks = 1250000ULL * 1000000ULL;
4253*4882a593Smuzhiyun 				do_div(blocks, time_us * 8 * 204);
4254*4882a593Smuzhiyun 				c->block_count.stat[0].scale = FE_SCALE_COUNTER;
4255*4882a593Smuzhiyun 				c->block_count.stat[0].uvalue += blocks;
4256*4882a593Smuzhiyun 			}
4257*4882a593Smuzhiyun 		}
4258*4882a593Smuzhiyun 	}
4259*4882a593Smuzhiyun 	return 0;
4260*4882a593Smuzhiyun }
4261*4882a593Smuzhiyun 
dib8000_set_slave_frontend(struct dvb_frontend * fe,struct dvb_frontend * fe_slave)4262*4882a593Smuzhiyun static int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
4263*4882a593Smuzhiyun {
4264*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
4265*4882a593Smuzhiyun 	u8 index_frontend = 1;
4266*4882a593Smuzhiyun 
4267*4882a593Smuzhiyun 	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
4268*4882a593Smuzhiyun 		index_frontend++;
4269*4882a593Smuzhiyun 	if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
4270*4882a593Smuzhiyun 		dprintk("set slave fe %p to index %i\n", fe_slave, index_frontend);
4271*4882a593Smuzhiyun 		state->fe[index_frontend] = fe_slave;
4272*4882a593Smuzhiyun 		return 0;
4273*4882a593Smuzhiyun 	}
4274*4882a593Smuzhiyun 
4275*4882a593Smuzhiyun 	dprintk("too many slave frontend\n");
4276*4882a593Smuzhiyun 	return -ENOMEM;
4277*4882a593Smuzhiyun }
4278*4882a593Smuzhiyun 
dib8000_get_slave_frontend(struct dvb_frontend * fe,int slave_index)4279*4882a593Smuzhiyun static struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
4280*4882a593Smuzhiyun {
4281*4882a593Smuzhiyun 	struct dib8000_state *state = fe->demodulator_priv;
4282*4882a593Smuzhiyun 
4283*4882a593Smuzhiyun 	if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
4284*4882a593Smuzhiyun 		return NULL;
4285*4882a593Smuzhiyun 	return state->fe[slave_index];
4286*4882a593Smuzhiyun }
4287*4882a593Smuzhiyun 
dib8000_i2c_enumeration(struct i2c_adapter * host,int no_of_demods,u8 default_addr,u8 first_addr,u8 is_dib8096p)4288*4882a593Smuzhiyun static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
4289*4882a593Smuzhiyun 		u8 default_addr, u8 first_addr, u8 is_dib8096p)
4290*4882a593Smuzhiyun {
4291*4882a593Smuzhiyun 	int k = 0, ret = 0;
4292*4882a593Smuzhiyun 	u8 new_addr = 0;
4293*4882a593Smuzhiyun 	struct i2c_device client = {.adap = host };
4294*4882a593Smuzhiyun 
4295*4882a593Smuzhiyun 	client.i2c_write_buffer = kzalloc(4, GFP_KERNEL);
4296*4882a593Smuzhiyun 	if (!client.i2c_write_buffer) {
4297*4882a593Smuzhiyun 		dprintk("%s: not enough memory\n", __func__);
4298*4882a593Smuzhiyun 		return -ENOMEM;
4299*4882a593Smuzhiyun 	}
4300*4882a593Smuzhiyun 	client.i2c_read_buffer = kzalloc(4, GFP_KERNEL);
4301*4882a593Smuzhiyun 	if (!client.i2c_read_buffer) {
4302*4882a593Smuzhiyun 		dprintk("%s: not enough memory\n", __func__);
4303*4882a593Smuzhiyun 		ret = -ENOMEM;
4304*4882a593Smuzhiyun 		goto error_memory_read;
4305*4882a593Smuzhiyun 	}
4306*4882a593Smuzhiyun 	client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
4307*4882a593Smuzhiyun 	if (!client.i2c_buffer_lock) {
4308*4882a593Smuzhiyun 		dprintk("%s: not enough memory\n", __func__);
4309*4882a593Smuzhiyun 		ret = -ENOMEM;
4310*4882a593Smuzhiyun 		goto error_memory_lock;
4311*4882a593Smuzhiyun 	}
4312*4882a593Smuzhiyun 	mutex_init(client.i2c_buffer_lock);
4313*4882a593Smuzhiyun 
4314*4882a593Smuzhiyun 	for (k = no_of_demods - 1; k >= 0; k--) {
4315*4882a593Smuzhiyun 		/* designated i2c address */
4316*4882a593Smuzhiyun 		new_addr = first_addr + (k << 1);
4317*4882a593Smuzhiyun 
4318*4882a593Smuzhiyun 		client.addr = new_addr;
4319*4882a593Smuzhiyun 		if (!is_dib8096p)
4320*4882a593Smuzhiyun 			dib8000_i2c_write16(&client, 1287, 0x0003);	/* sram lead in, rdy */
4321*4882a593Smuzhiyun 		if (dib8000_identify(&client) == 0) {
4322*4882a593Smuzhiyun 			/* sram lead in, rdy */
4323*4882a593Smuzhiyun 			if (!is_dib8096p)
4324*4882a593Smuzhiyun 				dib8000_i2c_write16(&client, 1287, 0x0003);
4325*4882a593Smuzhiyun 			client.addr = default_addr;
4326*4882a593Smuzhiyun 			if (dib8000_identify(&client) == 0) {
4327*4882a593Smuzhiyun 				dprintk("#%d: not identified\n", k);
4328*4882a593Smuzhiyun 				ret  = -EINVAL;
4329*4882a593Smuzhiyun 				goto error;
4330*4882a593Smuzhiyun 			}
4331*4882a593Smuzhiyun 		}
4332*4882a593Smuzhiyun 
4333*4882a593Smuzhiyun 		/* start diversity to pull_down div_str - just for i2c-enumeration */
4334*4882a593Smuzhiyun 		dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
4335*4882a593Smuzhiyun 
4336*4882a593Smuzhiyun 		/* set new i2c address and force divstart */
4337*4882a593Smuzhiyun 		dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
4338*4882a593Smuzhiyun 		client.addr = new_addr;
4339*4882a593Smuzhiyun 		dib8000_identify(&client);
4340*4882a593Smuzhiyun 
4341*4882a593Smuzhiyun 		dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
4342*4882a593Smuzhiyun 	}
4343*4882a593Smuzhiyun 
4344*4882a593Smuzhiyun 	for (k = 0; k < no_of_demods; k++) {
4345*4882a593Smuzhiyun 		new_addr = first_addr | (k << 1);
4346*4882a593Smuzhiyun 		client.addr = new_addr;
4347*4882a593Smuzhiyun 
4348*4882a593Smuzhiyun 		// unforce divstr
4349*4882a593Smuzhiyun 		dib8000_i2c_write16(&client, 1285, new_addr << 2);
4350*4882a593Smuzhiyun 
4351*4882a593Smuzhiyun 		/* deactivate div - it was just for i2c-enumeration */
4352*4882a593Smuzhiyun 		dib8000_i2c_write16(&client, 1286, 0);
4353*4882a593Smuzhiyun 	}
4354*4882a593Smuzhiyun 
4355*4882a593Smuzhiyun error:
4356*4882a593Smuzhiyun 	kfree(client.i2c_buffer_lock);
4357*4882a593Smuzhiyun error_memory_lock:
4358*4882a593Smuzhiyun 	kfree(client.i2c_read_buffer);
4359*4882a593Smuzhiyun error_memory_read:
4360*4882a593Smuzhiyun 	kfree(client.i2c_write_buffer);
4361*4882a593Smuzhiyun 
4362*4882a593Smuzhiyun 	return ret;
4363*4882a593Smuzhiyun }
4364*4882a593Smuzhiyun 
dib8000_fe_get_tune_settings(struct dvb_frontend * fe,struct dvb_frontend_tune_settings * tune)4365*4882a593Smuzhiyun static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
4366*4882a593Smuzhiyun {
4367*4882a593Smuzhiyun 	tune->min_delay_ms = 1000;
4368*4882a593Smuzhiyun 	tune->step_size = 0;
4369*4882a593Smuzhiyun 	tune->max_drift = 0;
4370*4882a593Smuzhiyun 	return 0;
4371*4882a593Smuzhiyun }
4372*4882a593Smuzhiyun 
dib8000_release(struct dvb_frontend * fe)4373*4882a593Smuzhiyun static void dib8000_release(struct dvb_frontend *fe)
4374*4882a593Smuzhiyun {
4375*4882a593Smuzhiyun 	struct dib8000_state *st = fe->demodulator_priv;
4376*4882a593Smuzhiyun 	u8 index_frontend;
4377*4882a593Smuzhiyun 
4378*4882a593Smuzhiyun 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
4379*4882a593Smuzhiyun 		dvb_frontend_detach(st->fe[index_frontend]);
4380*4882a593Smuzhiyun 
4381*4882a593Smuzhiyun 	dibx000_exit_i2c_master(&st->i2c_master);
4382*4882a593Smuzhiyun 	i2c_del_adapter(&st->dib8096p_tuner_adap);
4383*4882a593Smuzhiyun 	kfree(st->fe[0]);
4384*4882a593Smuzhiyun 	kfree(st);
4385*4882a593Smuzhiyun }
4386*4882a593Smuzhiyun 
dib8000_get_i2c_master(struct dvb_frontend * fe,enum dibx000_i2c_interface intf,int gating)4387*4882a593Smuzhiyun static struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
4388*4882a593Smuzhiyun {
4389*4882a593Smuzhiyun 	struct dib8000_state *st = fe->demodulator_priv;
4390*4882a593Smuzhiyun 	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
4391*4882a593Smuzhiyun }
4392*4882a593Smuzhiyun 
dib8000_pid_filter_ctrl(struct dvb_frontend * fe,u8 onoff)4393*4882a593Smuzhiyun static int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
4394*4882a593Smuzhiyun {
4395*4882a593Smuzhiyun 	struct dib8000_state *st = fe->demodulator_priv;
4396*4882a593Smuzhiyun 	u16 val = dib8000_read_word(st, 299) & 0xffef;
4397*4882a593Smuzhiyun 	val |= (onoff & 0x1) << 4;
4398*4882a593Smuzhiyun 
4399*4882a593Smuzhiyun 	dprintk("pid filter enabled %d\n", onoff);
4400*4882a593Smuzhiyun 	return dib8000_write_word(st, 299, val);
4401*4882a593Smuzhiyun }
4402*4882a593Smuzhiyun 
dib8000_pid_filter(struct dvb_frontend * fe,u8 id,u16 pid,u8 onoff)4403*4882a593Smuzhiyun static int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
4404*4882a593Smuzhiyun {
4405*4882a593Smuzhiyun 	struct dib8000_state *st = fe->demodulator_priv;
4406*4882a593Smuzhiyun 	dprintk("Index %x, PID %d, OnOff %d\n", id, pid, onoff);
4407*4882a593Smuzhiyun 	return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
4408*4882a593Smuzhiyun }
4409*4882a593Smuzhiyun 
4410*4882a593Smuzhiyun static const struct dvb_frontend_ops dib8000_ops = {
4411*4882a593Smuzhiyun 	.delsys = { SYS_ISDBT },
4412*4882a593Smuzhiyun 	.info = {
4413*4882a593Smuzhiyun 		 .name = "DiBcom 8000 ISDB-T",
4414*4882a593Smuzhiyun 		 .frequency_min_hz =  44250 * kHz,
4415*4882a593Smuzhiyun 		 .frequency_max_hz = 867250 * kHz,
4416*4882a593Smuzhiyun 		 .frequency_stepsize_hz = 62500,
4417*4882a593Smuzhiyun 		 .caps = FE_CAN_INVERSION_AUTO |
4418*4882a593Smuzhiyun 		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
4419*4882a593Smuzhiyun 		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
4420*4882a593Smuzhiyun 		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
4421*4882a593Smuzhiyun 		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
4422*4882a593Smuzhiyun 		 },
4423*4882a593Smuzhiyun 
4424*4882a593Smuzhiyun 	.release = dib8000_release,
4425*4882a593Smuzhiyun 
4426*4882a593Smuzhiyun 	.init = dib8000_wakeup,
4427*4882a593Smuzhiyun 	.sleep = dib8000_sleep,
4428*4882a593Smuzhiyun 
4429*4882a593Smuzhiyun 	.set_frontend = dib8000_set_frontend,
4430*4882a593Smuzhiyun 	.get_tune_settings = dib8000_fe_get_tune_settings,
4431*4882a593Smuzhiyun 	.get_frontend = dib8000_get_frontend,
4432*4882a593Smuzhiyun 
4433*4882a593Smuzhiyun 	.read_status = dib8000_read_status,
4434*4882a593Smuzhiyun 	.read_ber = dib8000_read_ber,
4435*4882a593Smuzhiyun 	.read_signal_strength = dib8000_read_signal_strength,
4436*4882a593Smuzhiyun 	.read_snr = dib8000_read_snr,
4437*4882a593Smuzhiyun 	.read_ucblocks = dib8000_read_unc_blocks,
4438*4882a593Smuzhiyun };
4439*4882a593Smuzhiyun 
dib8000_init(struct i2c_adapter * i2c_adap,u8 i2c_addr,struct dib8000_config * cfg)4440*4882a593Smuzhiyun static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
4441*4882a593Smuzhiyun {
4442*4882a593Smuzhiyun 	struct dvb_frontend *fe;
4443*4882a593Smuzhiyun 	struct dib8000_state *state;
4444*4882a593Smuzhiyun 
4445*4882a593Smuzhiyun 	dprintk("dib8000_init\n");
4446*4882a593Smuzhiyun 
4447*4882a593Smuzhiyun 	state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
4448*4882a593Smuzhiyun 	if (state == NULL)
4449*4882a593Smuzhiyun 		return NULL;
4450*4882a593Smuzhiyun 	fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
4451*4882a593Smuzhiyun 	if (fe == NULL)
4452*4882a593Smuzhiyun 		goto error;
4453*4882a593Smuzhiyun 
4454*4882a593Smuzhiyun 	memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
4455*4882a593Smuzhiyun 	state->i2c.adap = i2c_adap;
4456*4882a593Smuzhiyun 	state->i2c.addr = i2c_addr;
4457*4882a593Smuzhiyun 	state->i2c.i2c_write_buffer = state->i2c_write_buffer;
4458*4882a593Smuzhiyun 	state->i2c.i2c_read_buffer = state->i2c_read_buffer;
4459*4882a593Smuzhiyun 	mutex_init(&state->i2c_buffer_lock);
4460*4882a593Smuzhiyun 	state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
4461*4882a593Smuzhiyun 	state->gpio_val = cfg->gpio_val;
4462*4882a593Smuzhiyun 	state->gpio_dir = cfg->gpio_dir;
4463*4882a593Smuzhiyun 
4464*4882a593Smuzhiyun 	/* Ensure the output mode remains at the previous default if it's
4465*4882a593Smuzhiyun 	 * not specifically set by the caller.
4466*4882a593Smuzhiyun 	 */
4467*4882a593Smuzhiyun 	if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
4468*4882a593Smuzhiyun 		state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
4469*4882a593Smuzhiyun 
4470*4882a593Smuzhiyun 	state->fe[0] = fe;
4471*4882a593Smuzhiyun 	fe->demodulator_priv = state;
4472*4882a593Smuzhiyun 	memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
4473*4882a593Smuzhiyun 
4474*4882a593Smuzhiyun 	state->timf_default = cfg->pll->timf;
4475*4882a593Smuzhiyun 
4476*4882a593Smuzhiyun 	if (dib8000_identify(&state->i2c) == 0) {
4477*4882a593Smuzhiyun 		kfree(fe);
4478*4882a593Smuzhiyun 		goto error;
4479*4882a593Smuzhiyun 	}
4480*4882a593Smuzhiyun 
4481*4882a593Smuzhiyun 	dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
4482*4882a593Smuzhiyun 
4483*4882a593Smuzhiyun 	/* init 8096p tuner adapter */
4484*4882a593Smuzhiyun 	strscpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
4485*4882a593Smuzhiyun 		sizeof(state->dib8096p_tuner_adap.name));
4486*4882a593Smuzhiyun 	state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
4487*4882a593Smuzhiyun 	state->dib8096p_tuner_adap.algo_data = NULL;
4488*4882a593Smuzhiyun 	state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
4489*4882a593Smuzhiyun 	i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
4490*4882a593Smuzhiyun 	i2c_add_adapter(&state->dib8096p_tuner_adap);
4491*4882a593Smuzhiyun 
4492*4882a593Smuzhiyun 	dib8000_reset(fe);
4493*4882a593Smuzhiyun 
4494*4882a593Smuzhiyun 	dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));	/* ber_rs_len = 3 */
4495*4882a593Smuzhiyun 	state->current_demod_bw = 6000;
4496*4882a593Smuzhiyun 
4497*4882a593Smuzhiyun 	return fe;
4498*4882a593Smuzhiyun 
4499*4882a593Smuzhiyun error:
4500*4882a593Smuzhiyun 	kfree(state);
4501*4882a593Smuzhiyun 	return NULL;
4502*4882a593Smuzhiyun }
4503*4882a593Smuzhiyun 
dib8000_attach(struct dib8000_ops * ops)4504*4882a593Smuzhiyun void *dib8000_attach(struct dib8000_ops *ops)
4505*4882a593Smuzhiyun {
4506*4882a593Smuzhiyun 	if (!ops)
4507*4882a593Smuzhiyun 		return NULL;
4508*4882a593Smuzhiyun 
4509*4882a593Smuzhiyun 	ops->pwm_agc_reset = dib8000_pwm_agc_reset;
4510*4882a593Smuzhiyun 	ops->get_dc_power = dib8090p_get_dc_power;
4511*4882a593Smuzhiyun 	ops->set_gpio = dib8000_set_gpio;
4512*4882a593Smuzhiyun 	ops->get_slave_frontend = dib8000_get_slave_frontend;
4513*4882a593Smuzhiyun 	ops->set_tune_state = dib8000_set_tune_state;
4514*4882a593Smuzhiyun 	ops->pid_filter_ctrl = dib8000_pid_filter_ctrl;
4515*4882a593Smuzhiyun 	ops->get_adc_power = dib8000_get_adc_power;
4516*4882a593Smuzhiyun 	ops->update_pll = dib8000_update_pll;
4517*4882a593Smuzhiyun 	ops->tuner_sleep = dib8096p_tuner_sleep;
4518*4882a593Smuzhiyun 	ops->get_tune_state = dib8000_get_tune_state;
4519*4882a593Smuzhiyun 	ops->get_i2c_tuner = dib8096p_get_i2c_tuner;
4520*4882a593Smuzhiyun 	ops->set_slave_frontend = dib8000_set_slave_frontend;
4521*4882a593Smuzhiyun 	ops->pid_filter = dib8000_pid_filter;
4522*4882a593Smuzhiyun 	ops->ctrl_timf = dib8000_ctrl_timf;
4523*4882a593Smuzhiyun 	ops->init = dib8000_init;
4524*4882a593Smuzhiyun 	ops->get_i2c_master = dib8000_get_i2c_master;
4525*4882a593Smuzhiyun 	ops->i2c_enumeration = dib8000_i2c_enumeration;
4526*4882a593Smuzhiyun 	ops->set_wbd_ref = dib8000_set_wbd_ref;
4527*4882a593Smuzhiyun 
4528*4882a593Smuzhiyun 	return ops;
4529*4882a593Smuzhiyun }
4530*4882a593Smuzhiyun EXPORT_SYMBOL(dib8000_attach);
4531*4882a593Smuzhiyun 
4532*4882a593Smuzhiyun MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@parrot.com, Patrick Boettcher <patrick.boettcher@posteo.de>");
4533*4882a593Smuzhiyun MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
4534*4882a593Smuzhiyun MODULE_LICENSE("GPL");
4535