19a0bf528SMauro Carvalho Chehab /*
29a0bf528SMauro Carvalho Chehab  * Linux-DVB Driver for DiBcom's DiB8000 chip (ISDB-T).
39a0bf528SMauro Carvalho Chehab  *
49a0bf528SMauro Carvalho Chehab  * Copyright (C) 2009 DiBcom (http://www.dibcom.fr/)
59a0bf528SMauro Carvalho Chehab  *
69a0bf528SMauro Carvalho Chehab  * This program is free software; you can redistribute it and/or
79a0bf528SMauro Carvalho Chehab  *  modify it under the terms of the GNU General Public License as
89a0bf528SMauro Carvalho Chehab  *  published by the Free Software Foundation, version 2.
99a0bf528SMauro Carvalho Chehab  */
109a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
119a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
129a0bf528SMauro Carvalho Chehab #include <linux/i2c.h>
139a0bf528SMauro Carvalho Chehab #include <linux/mutex.h>
149a0bf528SMauro Carvalho Chehab 
159a0bf528SMauro Carvalho Chehab #include "dvb_math.h"
169a0bf528SMauro Carvalho Chehab 
179a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h"
189a0bf528SMauro Carvalho Chehab 
199a0bf528SMauro Carvalho Chehab #include "dib8000.h"
209a0bf528SMauro Carvalho Chehab 
219a0bf528SMauro Carvalho Chehab #define LAYER_ALL -1
229a0bf528SMauro Carvalho Chehab #define LAYER_A   1
239a0bf528SMauro Carvalho Chehab #define LAYER_B   2
249a0bf528SMauro Carvalho Chehab #define LAYER_C   3
259a0bf528SMauro Carvalho Chehab 
269a0bf528SMauro Carvalho Chehab #define MAX_NUMBER_OF_FRONTENDS 6
27173a64cbSPatrick Boettcher /* #define DIB8000_AGC_FREEZE */
289a0bf528SMauro Carvalho Chehab 
299a0bf528SMauro Carvalho Chehab static int debug;
309a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
319a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
329a0bf528SMauro Carvalho Chehab 
339a0bf528SMauro Carvalho Chehab #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0)
349a0bf528SMauro Carvalho Chehab 
359a0bf528SMauro Carvalho Chehab struct i2c_device {
369a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *adap;
379a0bf528SMauro Carvalho Chehab 	u8 addr;
389a0bf528SMauro Carvalho Chehab 	u8 *i2c_write_buffer;
399a0bf528SMauro Carvalho Chehab 	u8 *i2c_read_buffer;
409a0bf528SMauro Carvalho Chehab 	struct mutex *i2c_buffer_lock;
419a0bf528SMauro Carvalho Chehab };
429a0bf528SMauro Carvalho Chehab 
43173a64cbSPatrick Boettcher enum param_loop_step {
44173a64cbSPatrick Boettcher 	LOOP_TUNE_1,
45173a64cbSPatrick Boettcher 	LOOP_TUNE_2
46173a64cbSPatrick Boettcher };
47173a64cbSPatrick Boettcher 
48173a64cbSPatrick Boettcher enum dib8000_autosearch_step {
49173a64cbSPatrick Boettcher 	AS_START = 0,
50173a64cbSPatrick Boettcher 	AS_SEARCHING_FFT,
51173a64cbSPatrick Boettcher 	AS_SEARCHING_GUARD,
52173a64cbSPatrick Boettcher 	AS_DONE = 100,
53173a64cbSPatrick Boettcher };
54173a64cbSPatrick Boettcher 
55173a64cbSPatrick Boettcher enum timeout_mode {
56173a64cbSPatrick Boettcher 	SYMBOL_DEPENDENT_OFF = 0,
57173a64cbSPatrick Boettcher 	SYMBOL_DEPENDENT_ON,
58173a64cbSPatrick Boettcher };
59173a64cbSPatrick Boettcher 
609a0bf528SMauro Carvalho Chehab struct dib8000_state {
619a0bf528SMauro Carvalho Chehab 	struct dib8000_config cfg;
629a0bf528SMauro Carvalho Chehab 
639a0bf528SMauro Carvalho Chehab 	struct i2c_device i2c;
649a0bf528SMauro Carvalho Chehab 
659a0bf528SMauro Carvalho Chehab 	struct dibx000_i2c_master i2c_master;
669a0bf528SMauro Carvalho Chehab 
679a0bf528SMauro Carvalho Chehab 	u16 wbd_ref;
689a0bf528SMauro Carvalho Chehab 
699a0bf528SMauro Carvalho Chehab 	u8 current_band;
709a0bf528SMauro Carvalho Chehab 	u32 current_bandwidth;
719a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *current_agc;
729a0bf528SMauro Carvalho Chehab 	u32 timf;
739a0bf528SMauro Carvalho Chehab 	u32 timf_default;
749a0bf528SMauro Carvalho Chehab 
759a0bf528SMauro Carvalho Chehab 	u8 div_force_off:1;
769a0bf528SMauro Carvalho Chehab 	u8 div_state:1;
779a0bf528SMauro Carvalho Chehab 	u16 div_sync_wait;
789a0bf528SMauro Carvalho Chehab 
799a0bf528SMauro Carvalho Chehab 	u8 agc_state;
809a0bf528SMauro Carvalho Chehab 	u8 differential_constellation;
819a0bf528SMauro Carvalho Chehab 	u8 diversity_onoff;
829a0bf528SMauro Carvalho Chehab 
839a0bf528SMauro Carvalho Chehab 	s16 ber_monitored_layer;
849a0bf528SMauro Carvalho Chehab 	u16 gpio_dir;
859a0bf528SMauro Carvalho Chehab 	u16 gpio_val;
869a0bf528SMauro Carvalho Chehab 
879a0bf528SMauro Carvalho Chehab 	u16 revision;
889a0bf528SMauro Carvalho Chehab 	u8 isdbt_cfg_loaded;
899a0bf528SMauro Carvalho Chehab 	enum frontend_tune_state tune_state;
90173a64cbSPatrick Boettcher 	s32 status;
919a0bf528SMauro Carvalho Chehab 
929a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
939a0bf528SMauro Carvalho Chehab 
949a0bf528SMauro Carvalho Chehab 	/* for the I2C transfer */
959a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2];
969a0bf528SMauro Carvalho Chehab 	u8 i2c_write_buffer[4];
979a0bf528SMauro Carvalho Chehab 	u8 i2c_read_buffer[2];
989a0bf528SMauro Carvalho Chehab 	struct mutex i2c_buffer_lock;
999a0bf528SMauro Carvalho Chehab 	u8 input_mode_mpeg;
1009a0bf528SMauro Carvalho Chehab 
1019a0bf528SMauro Carvalho Chehab 	u16 tuner_enable;
1029a0bf528SMauro Carvalho Chehab 	struct i2c_adapter dib8096p_tuner_adap;
103173a64cbSPatrick Boettcher 	u16 current_demod_bw;
104173a64cbSPatrick Boettcher 
105173a64cbSPatrick Boettcher 	u16 seg_mask;
106173a64cbSPatrick Boettcher 	u16 seg_diff_mask;
107173a64cbSPatrick Boettcher 	u16 mode;
108173a64cbSPatrick Boettcher 	u8 layer_b_nb_seg;
109173a64cbSPatrick Boettcher 	u8 layer_c_nb_seg;
110173a64cbSPatrick Boettcher 
111173a64cbSPatrick Boettcher 	u8 channel_parameters_set;
112173a64cbSPatrick Boettcher 	u16 autosearch_state;
113173a64cbSPatrick Boettcher 	u16 found_nfft;
114173a64cbSPatrick Boettcher 	u16 found_guard;
115173a64cbSPatrick Boettcher 	u8 subchannel;
116173a64cbSPatrick Boettcher 	u8 symbol_duration;
117173a64cbSPatrick Boettcher 	u32 timeout;
118173a64cbSPatrick Boettcher 	u8 longest_intlv_layer;
119173a64cbSPatrick Boettcher 	u16 output_mode;
120173a64cbSPatrick Boettcher 
121173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
122173a64cbSPatrick Boettcher 	u16 agc1_max;
123173a64cbSPatrick Boettcher 	u16 agc1_min;
124173a64cbSPatrick Boettcher 	u16 agc2_max;
125173a64cbSPatrick Boettcher 	u16 agc2_min;
126173a64cbSPatrick Boettcher #endif
1279a0bf528SMauro Carvalho Chehab };
1289a0bf528SMauro Carvalho Chehab 
1299a0bf528SMauro Carvalho Chehab enum dib8000_power_mode {
1309a0bf528SMauro Carvalho Chehab 	DIB8000_POWER_ALL = 0,
1319a0bf528SMauro Carvalho Chehab 	DIB8000_POWER_INTERFACE_ONLY,
1329a0bf528SMauro Carvalho Chehab };
1339a0bf528SMauro Carvalho Chehab 
1349a0bf528SMauro Carvalho Chehab static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
1359a0bf528SMauro Carvalho Chehab {
1369a0bf528SMauro Carvalho Chehab 	u16 ret;
1379a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2] = {
1389a0bf528SMauro Carvalho Chehab 		{.addr = i2c->addr >> 1, .flags = 0, .len = 2},
1399a0bf528SMauro Carvalho Chehab 		{.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
1409a0bf528SMauro Carvalho Chehab 	};
1419a0bf528SMauro Carvalho Chehab 
1429a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
1439a0bf528SMauro Carvalho Chehab 		dprintk("could not acquire lock");
1449a0bf528SMauro Carvalho Chehab 		return 0;
1459a0bf528SMauro Carvalho Chehab 	}
1469a0bf528SMauro Carvalho Chehab 
1479a0bf528SMauro Carvalho Chehab 	msg[0].buf    = i2c->i2c_write_buffer;
1489a0bf528SMauro Carvalho Chehab 	msg[0].buf[0] = reg >> 8;
1499a0bf528SMauro Carvalho Chehab 	msg[0].buf[1] = reg & 0xff;
1509a0bf528SMauro Carvalho Chehab 	msg[1].buf    = i2c->i2c_read_buffer;
1519a0bf528SMauro Carvalho Chehab 
1529a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(i2c->adap, msg, 2) != 2)
1539a0bf528SMauro Carvalho Chehab 		dprintk("i2c read error on %d", reg);
1549a0bf528SMauro Carvalho Chehab 
1559a0bf528SMauro Carvalho Chehab 	ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
1569a0bf528SMauro Carvalho Chehab 	mutex_unlock(i2c->i2c_buffer_lock);
1579a0bf528SMauro Carvalho Chehab 	return ret;
1589a0bf528SMauro Carvalho Chehab }
1599a0bf528SMauro Carvalho Chehab 
1605ac64ba1SMauro Carvalho Chehab static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg)
1619a0bf528SMauro Carvalho Chehab {
1629a0bf528SMauro Carvalho Chehab 	u16 ret;
1639a0bf528SMauro Carvalho Chehab 
1649a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = reg >> 8;
1659a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
1669a0bf528SMauro Carvalho Chehab 
1679a0bf528SMauro Carvalho Chehab 	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
1689a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c.addr >> 1;
1699a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
1709a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
1719a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 2;
1729a0bf528SMauro Carvalho Chehab 	state->msg[1].addr = state->i2c.addr >> 1;
1739a0bf528SMauro Carvalho Chehab 	state->msg[1].flags = I2C_M_RD;
1749a0bf528SMauro Carvalho Chehab 	state->msg[1].buf = state->i2c_read_buffer;
1759a0bf528SMauro Carvalho Chehab 	state->msg[1].len = 2;
1769a0bf528SMauro Carvalho Chehab 
1779a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
1789a0bf528SMauro Carvalho Chehab 		dprintk("i2c read error on %d", reg);
1799a0bf528SMauro Carvalho Chehab 
1809a0bf528SMauro Carvalho Chehab 	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
1815ac64ba1SMauro Carvalho Chehab 
1825ac64ba1SMauro Carvalho Chehab 	return ret;
1835ac64ba1SMauro Carvalho Chehab }
1845ac64ba1SMauro Carvalho Chehab 
1855ac64ba1SMauro Carvalho Chehab static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
1865ac64ba1SMauro Carvalho Chehab {
1875ac64ba1SMauro Carvalho Chehab 	u16 ret;
1885ac64ba1SMauro Carvalho Chehab 
1895ac64ba1SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
1905ac64ba1SMauro Carvalho Chehab 		dprintk("could not acquire lock");
1915ac64ba1SMauro Carvalho Chehab 		return 0;
1925ac64ba1SMauro Carvalho Chehab 	}
1935ac64ba1SMauro Carvalho Chehab 
1945ac64ba1SMauro Carvalho Chehab 	ret = __dib8000_read_word(state, reg);
1955ac64ba1SMauro Carvalho Chehab 
1969a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
1979a0bf528SMauro Carvalho Chehab 
1989a0bf528SMauro Carvalho Chehab 	return ret;
1999a0bf528SMauro Carvalho Chehab }
2009a0bf528SMauro Carvalho Chehab 
2019a0bf528SMauro Carvalho Chehab static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
2029a0bf528SMauro Carvalho Chehab {
2039a0bf528SMauro Carvalho Chehab 	u16 rw[2];
2049a0bf528SMauro Carvalho Chehab 
2055ac64ba1SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2065ac64ba1SMauro Carvalho Chehab 		dprintk("could not acquire lock");
2075ac64ba1SMauro Carvalho Chehab 		return 0;
2085ac64ba1SMauro Carvalho Chehab 	}
2095ac64ba1SMauro Carvalho Chehab 
2105ac64ba1SMauro Carvalho Chehab 	rw[0] = __dib8000_read_word(state, reg + 0);
2115ac64ba1SMauro Carvalho Chehab 	rw[1] = __dib8000_read_word(state, reg + 1);
2125ac64ba1SMauro Carvalho Chehab 
2135ac64ba1SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
2149a0bf528SMauro Carvalho Chehab 
2159a0bf528SMauro Carvalho Chehab 	return ((rw[0] << 16) | (rw[1]));
2169a0bf528SMauro Carvalho Chehab }
2179a0bf528SMauro Carvalho Chehab 
2189a0bf528SMauro Carvalho Chehab static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
2199a0bf528SMauro Carvalho Chehab {
2209a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
2219a0bf528SMauro Carvalho Chehab 	int ret = 0;
2229a0bf528SMauro Carvalho Chehab 
2239a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
2249a0bf528SMauro Carvalho Chehab 		dprintk("could not acquire lock");
2259a0bf528SMauro Carvalho Chehab 		return -EINVAL;
2269a0bf528SMauro Carvalho Chehab 	}
2279a0bf528SMauro Carvalho Chehab 
2289a0bf528SMauro Carvalho Chehab 	msg.buf    = i2c->i2c_write_buffer;
2299a0bf528SMauro Carvalho Chehab 	msg.buf[0] = (reg >> 8) & 0xff;
2309a0bf528SMauro Carvalho Chehab 	msg.buf[1] = reg & 0xff;
2319a0bf528SMauro Carvalho Chehab 	msg.buf[2] = (val >> 8) & 0xff;
2329a0bf528SMauro Carvalho Chehab 	msg.buf[3] = val & 0xff;
2339a0bf528SMauro Carvalho Chehab 
2349a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
2359a0bf528SMauro Carvalho Chehab 	mutex_unlock(i2c->i2c_buffer_lock);
2369a0bf528SMauro Carvalho Chehab 
2379a0bf528SMauro Carvalho Chehab 	return ret;
2389a0bf528SMauro Carvalho Chehab }
2399a0bf528SMauro Carvalho Chehab 
2409a0bf528SMauro Carvalho Chehab static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
2419a0bf528SMauro Carvalho Chehab {
2429a0bf528SMauro Carvalho Chehab 	int ret;
2439a0bf528SMauro Carvalho Chehab 
2449a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2459a0bf528SMauro Carvalho Chehab 		dprintk("could not acquire lock");
2469a0bf528SMauro Carvalho Chehab 		return -EINVAL;
2479a0bf528SMauro Carvalho Chehab 	}
2489a0bf528SMauro Carvalho Chehab 
2499a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
2509a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
2519a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
2529a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[3] = val & 0xff;
2539a0bf528SMauro Carvalho Chehab 
2549a0bf528SMauro Carvalho Chehab 	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
2559a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c.addr >> 1;
2569a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
2579a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
2589a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 4;
2599a0bf528SMauro Carvalho Chehab 
2609a0bf528SMauro Carvalho Chehab 	ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
2619a0bf528SMauro Carvalho Chehab 			-EREMOTEIO : 0);
2629a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
2639a0bf528SMauro Carvalho Chehab 
2649a0bf528SMauro Carvalho Chehab 	return ret;
2659a0bf528SMauro Carvalho Chehab }
2669a0bf528SMauro Carvalho Chehab 
2679a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
2689a0bf528SMauro Carvalho Chehab 	(769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c,
2699a0bf528SMauro Carvalho Chehab 		(920 << 5) | 0x09
2709a0bf528SMauro Carvalho Chehab };
2719a0bf528SMauro Carvalho Chehab 
2729a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg[8] = {
2739a0bf528SMauro Carvalho Chehab 	(692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
2749a0bf528SMauro Carvalho Chehab };
2759a0bf528SMauro Carvalho Chehab 
2769a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
2779a0bf528SMauro Carvalho Chehab 	(832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11,
2789a0bf528SMauro Carvalho Chehab 		(-931 << 5) | 0x0f
2799a0bf528SMauro Carvalho Chehab };
2809a0bf528SMauro Carvalho Chehab 
2819a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
2829a0bf528SMauro Carvalho Chehab 	(622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e,
2839a0bf528SMauro Carvalho Chehab 		(982 << 5) | 0x0c
2849a0bf528SMauro Carvalho Chehab };
2859a0bf528SMauro Carvalho Chehab 
2869a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
2879a0bf528SMauro Carvalho Chehab 	(699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12,
2889a0bf528SMauro Carvalho Chehab 		(-720 << 5) | 0x0d
2899a0bf528SMauro Carvalho Chehab };
2909a0bf528SMauro Carvalho Chehab 
2919a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg[8] = {
2929a0bf528SMauro Carvalho Chehab 	(664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e,
2939a0bf528SMauro Carvalho Chehab 		(-610 << 5) | 0x0a
2949a0bf528SMauro Carvalho Chehab };
2959a0bf528SMauro Carvalho Chehab 
2969a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
2979a0bf528SMauro Carvalho Chehab 	(-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f,
2989a0bf528SMauro Carvalho Chehab 		(-922 << 5) | 0x0d
2999a0bf528SMauro Carvalho Chehab };
3009a0bf528SMauro Carvalho Chehab 
3019a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg[8] = {
3029a0bf528SMauro Carvalho Chehab 	(638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d,
3039a0bf528SMauro Carvalho Chehab 		(-655 << 5) | 0x0a
3049a0bf528SMauro Carvalho Chehab };
3059a0bf528SMauro Carvalho Chehab 
3069a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
3079a0bf528SMauro Carvalho Chehab 	(-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14,
3089a0bf528SMauro Carvalho Chehab 		(-958 << 5) | 0x13
3099a0bf528SMauro Carvalho Chehab };
3109a0bf528SMauro Carvalho Chehab 
3119a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
3129a0bf528SMauro Carvalho Chehab 	(-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12,
3139a0bf528SMauro Carvalho Chehab 		(-568 << 5) | 0x0f
3149a0bf528SMauro Carvalho Chehab };
3159a0bf528SMauro Carvalho Chehab 
3169a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
3179a0bf528SMauro Carvalho Chehab 	(-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14,
3189a0bf528SMauro Carvalho Chehab 		(-848 << 5) | 0x13
3199a0bf528SMauro Carvalho Chehab };
3209a0bf528SMauro Carvalho Chehab 
3219a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg[8] = {
3229a0bf528SMauro Carvalho Chehab 	(612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12,
3239a0bf528SMauro Carvalho Chehab 		(-869 << 5) | 0x13
3249a0bf528SMauro Carvalho Chehab };
3259a0bf528SMauro Carvalho Chehab 
3269a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
3279a0bf528SMauro Carvalho Chehab 	(-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13,
3289a0bf528SMauro Carvalho Chehab 		(-598 << 5) | 0x10
3299a0bf528SMauro Carvalho Chehab };
3309a0bf528SMauro Carvalho Chehab 
3319a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg[8] = {
3329a0bf528SMauro Carvalho Chehab 	(673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f,
3339a0bf528SMauro Carvalho Chehab 		(585 << 5) | 0x0f
3349a0bf528SMauro Carvalho Chehab };
3359a0bf528SMauro Carvalho Chehab 
3369a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
3379a0bf528SMauro Carvalho Chehab 	(863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18,
3389a0bf528SMauro Carvalho Chehab 		(0 << 5) | 0x14
3399a0bf528SMauro Carvalho Chehab };
3409a0bf528SMauro Carvalho Chehab 
3419a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
3429a0bf528SMauro Carvalho Chehab 	(-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15,
3439a0bf528SMauro Carvalho Chehab 		(-877 << 5) | 0x15
3449a0bf528SMauro Carvalho Chehab };
3459a0bf528SMauro Carvalho Chehab 
3469a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
3479a0bf528SMauro Carvalho Chehab 	(-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18,
3489a0bf528SMauro Carvalho Chehab 		(-921 << 5) | 0x14
3499a0bf528SMauro Carvalho Chehab };
3509a0bf528SMauro Carvalho Chehab 
3519a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg[8] = {
3529a0bf528SMauro Carvalho Chehab 	(514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15,
3539a0bf528SMauro Carvalho Chehab 		(690 << 5) | 0x14
3549a0bf528SMauro Carvalho Chehab };
3559a0bf528SMauro Carvalho Chehab 
3569a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_3seg[24] = {
3579a0bf528SMauro Carvalho Chehab 	81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017
3589a0bf528SMauro Carvalho Chehab };
3599a0bf528SMauro Carvalho Chehab 
3609a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_1seg[24] = {
3619a0bf528SMauro Carvalho Chehab 	249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003
3629a0bf528SMauro Carvalho Chehab };
3639a0bf528SMauro Carvalho Chehab 
3649a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_13seg[24] = {
3659a0bf528SMauro Carvalho Chehab 	396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1
3669a0bf528SMauro Carvalho Chehab };
3679a0bf528SMauro Carvalho Chehab 
3689a0bf528SMauro Carvalho Chehab static u16 fft_to_mode(struct dib8000_state *state)
3699a0bf528SMauro Carvalho Chehab {
3709a0bf528SMauro Carvalho Chehab 	u16 mode;
3719a0bf528SMauro Carvalho Chehab 	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
3729a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
3739a0bf528SMauro Carvalho Chehab 		mode = 1;
3749a0bf528SMauro Carvalho Chehab 		break;
3759a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
3769a0bf528SMauro Carvalho Chehab 		mode = 2;
3779a0bf528SMauro Carvalho Chehab 		break;
3789a0bf528SMauro Carvalho Chehab 	default:
3799a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_AUTO:
3809a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
3819a0bf528SMauro Carvalho Chehab 		mode = 3;
3829a0bf528SMauro Carvalho Chehab 		break;
3839a0bf528SMauro Carvalho Chehab 	}
3849a0bf528SMauro Carvalho Chehab 	return mode;
3859a0bf528SMauro Carvalho Chehab }
3869a0bf528SMauro Carvalho Chehab 
3879a0bf528SMauro Carvalho Chehab static void dib8000_set_acquisition_mode(struct dib8000_state *state)
3889a0bf528SMauro Carvalho Chehab {
3899a0bf528SMauro Carvalho Chehab 	u16 nud = dib8000_read_word(state, 298);
3909a0bf528SMauro Carvalho Chehab 	nud |= (1 << 3) | (1 << 0);
3919a0bf528SMauro Carvalho Chehab 	dprintk("acquisition mode activated");
3929a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 298, nud);
3939a0bf528SMauro Carvalho Chehab }
3949a0bf528SMauro Carvalho Chehab static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
3959a0bf528SMauro Carvalho Chehab {
3969a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
3979a0bf528SMauro Carvalho Chehab 	u16 outreg, fifo_threshold, smo_mode, sram = 0x0205;	/* by default SDRAM deintlv is enabled */
3989a0bf528SMauro Carvalho Chehab 
399173a64cbSPatrick Boettcher 	state->output_mode = mode;
4009a0bf528SMauro Carvalho Chehab 	outreg = 0;
4019a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
4029a0bf528SMauro Carvalho Chehab 	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
4039a0bf528SMauro Carvalho Chehab 
4049a0bf528SMauro Carvalho Chehab 	dprintk("-I-	Setting output mode for demod %p to %d",
4059a0bf528SMauro Carvalho Chehab 			&state->fe[0], mode);
4069a0bf528SMauro Carvalho Chehab 
4079a0bf528SMauro Carvalho Chehab 	switch (mode) {
4089a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:	// STBs with parallel gated clock
4099a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10);	/* 0x0400 */
4109a0bf528SMauro Carvalho Chehab 		break;
4119a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK:	// STBs with parallel continues clock
4129a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (1 << 6);	/* 0x0440 */
4139a0bf528SMauro Carvalho Chehab 		break;
4149a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:	// STBs with serial input
4159a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (2 << 6) | (0 << 1);	/* 0x0482 */
4169a0bf528SMauro Carvalho Chehab 		break;
4179a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
4189a0bf528SMauro Carvalho Chehab 		if (state->cfg.hostbus_diversity) {
4199a0bf528SMauro Carvalho Chehab 			outreg = (1 << 10) | (4 << 6);	/* 0x0500 */
4209a0bf528SMauro Carvalho Chehab 			sram &= 0xfdff;
4219a0bf528SMauro Carvalho Chehab 		} else
4229a0bf528SMauro Carvalho Chehab 			sram |= 0x0c00;
4239a0bf528SMauro Carvalho Chehab 		break;
4249a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:	// e.g. USB feeding
4259a0bf528SMauro Carvalho Chehab 		smo_mode |= (3 << 1);
4269a0bf528SMauro Carvalho Chehab 		fifo_threshold = 512;
4279a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (5 << 6);
4289a0bf528SMauro Carvalho Chehab 		break;
4299a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:	// disable
4309a0bf528SMauro Carvalho Chehab 		outreg = 0;
4319a0bf528SMauro Carvalho Chehab 		break;
4329a0bf528SMauro Carvalho Chehab 
4339a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
4349a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (3 << 6);
4359a0bf528SMauro Carvalho Chehab 		dib8000_set_acquisition_mode(state);
4369a0bf528SMauro Carvalho Chehab 		break;
4379a0bf528SMauro Carvalho Chehab 
4389a0bf528SMauro Carvalho Chehab 	default:
4399a0bf528SMauro Carvalho Chehab 		dprintk("Unhandled output_mode passed to be set for demod %p",
4409a0bf528SMauro Carvalho Chehab 				&state->fe[0]);
4419a0bf528SMauro Carvalho Chehab 		return -EINVAL;
4429a0bf528SMauro Carvalho Chehab 	}
4439a0bf528SMauro Carvalho Chehab 
4449a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
4459a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
4469a0bf528SMauro Carvalho Chehab 
4479a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 299, smo_mode);
4489a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 300, fifo_threshold);	/* synchronous fread */
4499a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1286, outreg);
4509a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1291, sram);
4519a0bf528SMauro Carvalho Chehab 
4529a0bf528SMauro Carvalho Chehab 	return 0;
4539a0bf528SMauro Carvalho Chehab }
4549a0bf528SMauro Carvalho Chehab 
4559a0bf528SMauro Carvalho Chehab static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
4569a0bf528SMauro Carvalho Chehab {
4579a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
458173a64cbSPatrick Boettcher 	u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0;
4599a0bf528SMauro Carvalho Chehab 
460173a64cbSPatrick Boettcher 	dprintk("set diversity input to %i", onoff);
4619a0bf528SMauro Carvalho Chehab 	if (!state->differential_constellation) {
4629a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 272, 1 << 9);	//dvsy_off_lmod4 = 1
4639a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2);	// sync_enable = 1; comb_mode = 2
4649a0bf528SMauro Carvalho Chehab 	} else {
4659a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 272, 0);	//dvsy_off_lmod4 = 0
4669a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 273, sync_wait);	// sync_enable = 0; comb_mode = 0
4679a0bf528SMauro Carvalho Chehab 	}
4689a0bf528SMauro Carvalho Chehab 	state->diversity_onoff = onoff;
4699a0bf528SMauro Carvalho Chehab 
4709a0bf528SMauro Carvalho Chehab 	switch (onoff) {
4719a0bf528SMauro Carvalho Chehab 	case 0:		/* only use the internal way - not the diversity input */
4729a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 270, 1);
4739a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 271, 0);
4749a0bf528SMauro Carvalho Chehab 		break;
4759a0bf528SMauro Carvalho Chehab 	case 1:		/* both ways */
4769a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 270, 6);
4779a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 271, 6);
4789a0bf528SMauro Carvalho Chehab 		break;
4799a0bf528SMauro Carvalho Chehab 	case 2:		/* only the diversity input */
4809a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 270, 0);
4819a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 271, 1);
4829a0bf528SMauro Carvalho Chehab 		break;
4839a0bf528SMauro Carvalho Chehab 	}
484173a64cbSPatrick Boettcher 
485173a64cbSPatrick Boettcher 	if (state->revision == 0x8002) {
486173a64cbSPatrick Boettcher 		tmp = dib8000_read_word(state, 903);
487173a64cbSPatrick Boettcher 		dib8000_write_word(state, 903, tmp & ~(1 << 3));
488173a64cbSPatrick Boettcher 		msleep(30);
489173a64cbSPatrick Boettcher 		dib8000_write_word(state, 903, tmp | (1 << 3));
490173a64cbSPatrick Boettcher 	}
4919a0bf528SMauro Carvalho Chehab 	return 0;
4929a0bf528SMauro Carvalho Chehab }
4939a0bf528SMauro Carvalho Chehab 
4949a0bf528SMauro Carvalho Chehab static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
4959a0bf528SMauro Carvalho Chehab {
4969a0bf528SMauro Carvalho Chehab 	/* by default everything is going to be powered off */
4979a0bf528SMauro Carvalho Chehab 	u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
4989a0bf528SMauro Carvalho Chehab 		reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
4999a0bf528SMauro Carvalho Chehab 		reg_1280;
5009a0bf528SMauro Carvalho Chehab 
5019a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
5029a0bf528SMauro Carvalho Chehab 		reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
5039a0bf528SMauro Carvalho Chehab 	else
5049a0bf528SMauro Carvalho Chehab 		reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80;
5059a0bf528SMauro Carvalho Chehab 
5069a0bf528SMauro Carvalho Chehab 	/* now, depending on the requested mode, we power on */
5079a0bf528SMauro Carvalho Chehab 	switch (mode) {
5089a0bf528SMauro Carvalho Chehab 		/* power up everything in the demod */
5099a0bf528SMauro Carvalho Chehab 	case DIB8000_POWER_ALL:
5109a0bf528SMauro Carvalho Chehab 		reg_774 = 0x0000;
5119a0bf528SMauro Carvalho Chehab 		reg_775 = 0x0000;
5129a0bf528SMauro Carvalho Chehab 		reg_776 = 0x0000;
5139a0bf528SMauro Carvalho Chehab 		reg_900 &= 0xfffc;
5149a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090)
5159a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x00ff;
5169a0bf528SMauro Carvalho Chehab 		else
5179a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x707f;
5189a0bf528SMauro Carvalho Chehab 		break;
5199a0bf528SMauro Carvalho Chehab 	case DIB8000_POWER_INTERFACE_ONLY:
5209a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090)
5219a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x00ff;
5229a0bf528SMauro Carvalho Chehab 		else
5239a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0xfa7b;
5249a0bf528SMauro Carvalho Chehab 		break;
5259a0bf528SMauro Carvalho Chehab 	}
5269a0bf528SMauro Carvalho Chehab 
5279a0bf528SMauro Carvalho Chehab 	dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280);
5289a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 774, reg_774);
5299a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 775, reg_775);
5309a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 776, reg_776);
5319a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 900, reg_900);
5329a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1280, reg_1280);
5339a0bf528SMauro Carvalho Chehab }
5349a0bf528SMauro Carvalho Chehab 
5359a0bf528SMauro Carvalho Chehab static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
5369a0bf528SMauro Carvalho Chehab {
5379a0bf528SMauro Carvalho Chehab 	int ret = 0;
5389a0bf528SMauro Carvalho Chehab 	u16 reg, reg_907 = dib8000_read_word(state, 907);
5399a0bf528SMauro Carvalho Chehab 	u16 reg_908 = dib8000_read_word(state, 908);
5409a0bf528SMauro Carvalho Chehab 
5419a0bf528SMauro Carvalho Chehab 	switch (no) {
5429a0bf528SMauro Carvalho Chehab 	case DIBX000_SLOW_ADC_ON:
5439a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090) {
5449a0bf528SMauro Carvalho Chehab 			reg_908 |= (1 << 1) | (1 << 0);
5459a0bf528SMauro Carvalho Chehab 			ret |= dib8000_write_word(state, 908, reg_908);
5469a0bf528SMauro Carvalho Chehab 			reg_908 &= ~(1 << 1);
5479a0bf528SMauro Carvalho Chehab 		} else {
5489a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1925);
5499a0bf528SMauro Carvalho Chehab 			/* en_slowAdc = 1 & reset_sladc = 1 */
5509a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1925, reg |
5519a0bf528SMauro Carvalho Chehab 					(1<<4) | (1<<2));
5529a0bf528SMauro Carvalho Chehab 
5539a0bf528SMauro Carvalho Chehab 			/* read acces to make it works... strange ... */
5549a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1925);
5559a0bf528SMauro Carvalho Chehab 			msleep(20);
5569a0bf528SMauro Carvalho Chehab 			/* en_slowAdc = 1 & reset_sladc = 0 */
5579a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1925, reg & ~(1<<4));
5589a0bf528SMauro Carvalho Chehab 
5599a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 921) & ~((0x3 << 14)
5609a0bf528SMauro Carvalho Chehab 					| (0x3 << 12));
5619a0bf528SMauro Carvalho Chehab 			/* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ;
5629a0bf528SMauro Carvalho Chehab 			   (Vin2 = Vcm) */
5639a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 921, reg | (1 << 14)
5649a0bf528SMauro Carvalho Chehab 					| (3 << 12));
5659a0bf528SMauro Carvalho Chehab 		}
5669a0bf528SMauro Carvalho Chehab 		break;
5679a0bf528SMauro Carvalho Chehab 
5689a0bf528SMauro Carvalho Chehab 	case DIBX000_SLOW_ADC_OFF:
5699a0bf528SMauro Carvalho Chehab 		if (state->revision == 0x8090) {
5709a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1925);
5719a0bf528SMauro Carvalho Chehab 			/* reset_sladc = 1 en_slowAdc = 0 */
5729a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1925,
5739a0bf528SMauro Carvalho Chehab 					(reg & ~(1<<2)) | (1<<4));
5749a0bf528SMauro Carvalho Chehab 		}
5759a0bf528SMauro Carvalho Chehab 		reg_908 |= (1 << 1) | (1 << 0);
5769a0bf528SMauro Carvalho Chehab 		break;
5779a0bf528SMauro Carvalho Chehab 
5789a0bf528SMauro Carvalho Chehab 	case DIBX000_ADC_ON:
5799a0bf528SMauro Carvalho Chehab 		reg_907 &= 0x0fff;
5809a0bf528SMauro Carvalho Chehab 		reg_908 &= 0x0003;
5819a0bf528SMauro Carvalho Chehab 		break;
5829a0bf528SMauro Carvalho Chehab 
5839a0bf528SMauro Carvalho Chehab 	case DIBX000_ADC_OFF:	// leave the VBG voltage on
5849a0bf528SMauro Carvalho Chehab 		reg_907 |= (1 << 14) | (1 << 13) | (1 << 12);
5859a0bf528SMauro Carvalho Chehab 		reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
5869a0bf528SMauro Carvalho Chehab 		break;
5879a0bf528SMauro Carvalho Chehab 
5889a0bf528SMauro Carvalho Chehab 	case DIBX000_VBG_ENABLE:
5899a0bf528SMauro Carvalho Chehab 		reg_907 &= ~(1 << 15);
5909a0bf528SMauro Carvalho Chehab 		break;
5919a0bf528SMauro Carvalho Chehab 
5929a0bf528SMauro Carvalho Chehab 	case DIBX000_VBG_DISABLE:
5939a0bf528SMauro Carvalho Chehab 		reg_907 |= (1 << 15);
5949a0bf528SMauro Carvalho Chehab 		break;
5959a0bf528SMauro Carvalho Chehab 
5969a0bf528SMauro Carvalho Chehab 	default:
5979a0bf528SMauro Carvalho Chehab 		break;
5989a0bf528SMauro Carvalho Chehab 	}
5999a0bf528SMauro Carvalho Chehab 
6009a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 907, reg_907);
6019a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 908, reg_908);
6029a0bf528SMauro Carvalho Chehab 
6039a0bf528SMauro Carvalho Chehab 	return ret;
6049a0bf528SMauro Carvalho Chehab }
6059a0bf528SMauro Carvalho Chehab 
6069a0bf528SMauro Carvalho Chehab static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
6079a0bf528SMauro Carvalho Chehab {
6089a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
6099a0bf528SMauro Carvalho Chehab 	u32 timf;
6109a0bf528SMauro Carvalho Chehab 
6119a0bf528SMauro Carvalho Chehab 	if (bw == 0)
6129a0bf528SMauro Carvalho Chehab 		bw = 6000;
6139a0bf528SMauro Carvalho Chehab 
6149a0bf528SMauro Carvalho Chehab 	if (state->timf == 0) {
6159a0bf528SMauro Carvalho Chehab 		dprintk("using default timf");
6169a0bf528SMauro Carvalho Chehab 		timf = state->timf_default;
6179a0bf528SMauro Carvalho Chehab 	} else {
6189a0bf528SMauro Carvalho Chehab 		dprintk("using updated timf");
6199a0bf528SMauro Carvalho Chehab 		timf = state->timf;
6209a0bf528SMauro Carvalho Chehab 	}
6219a0bf528SMauro Carvalho Chehab 
6229a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
6239a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
6249a0bf528SMauro Carvalho Chehab 
6259a0bf528SMauro Carvalho Chehab 	return 0;
6269a0bf528SMauro Carvalho Chehab }
6279a0bf528SMauro Carvalho Chehab 
6289a0bf528SMauro Carvalho Chehab static int dib8000_sad_calib(struct dib8000_state *state)
6299a0bf528SMauro Carvalho Chehab {
630173a64cbSPatrick Boettcher 	u8 sad_sel = 3;
631173a64cbSPatrick Boettcher 
6329a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090) {
633173a64cbSPatrick Boettcher 		dib8000_write_word(state, 922, (sad_sel << 2));
634173a64cbSPatrick Boettcher 		dib8000_write_word(state, 923, 2048);
635173a64cbSPatrick Boettcher 
636173a64cbSPatrick Boettcher 		dib8000_write_word(state, 922, (sad_sel << 2) | 0x1);
637173a64cbSPatrick Boettcher 		dib8000_write_word(state, 922, (sad_sel << 2));
638173a64cbSPatrick Boettcher 	} else {
6399a0bf528SMauro Carvalho Chehab 		/* internal */
6409a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
641173a64cbSPatrick Boettcher 		dib8000_write_word(state, 924, 776);
6429a0bf528SMauro Carvalho Chehab 
6439a0bf528SMauro Carvalho Chehab 		/* do the calibration */
6449a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923, (1 << 0));
6459a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923, (0 << 0));
646173a64cbSPatrick Boettcher 	}
6479a0bf528SMauro Carvalho Chehab 
6489a0bf528SMauro Carvalho Chehab 	msleep(1);
6499a0bf528SMauro Carvalho Chehab 	return 0;
6509a0bf528SMauro Carvalho Chehab }
6519a0bf528SMauro Carvalho Chehab 
6529a0bf528SMauro Carvalho Chehab int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
6539a0bf528SMauro Carvalho Chehab {
6549a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
6559a0bf528SMauro Carvalho Chehab 	if (value > 4095)
6569a0bf528SMauro Carvalho Chehab 		value = 4095;
6579a0bf528SMauro Carvalho Chehab 	state->wbd_ref = value;
6589a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(state, 106, value);
6599a0bf528SMauro Carvalho Chehab }
6609a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_set_wbd_ref);
661173a64cbSPatrick Boettcher 
6629a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
6639a0bf528SMauro Carvalho Chehab {
6649a0bf528SMauro Carvalho Chehab 	dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
6659a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
6669a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23,
6679a0bf528SMauro Carvalho Chehab 				(u16) (((bw->internal * 1000) >> 16) & 0xffff));
6689a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24,
6699a0bf528SMauro Carvalho Chehab 				(u16) ((bw->internal * 1000) & 0xffff));
6709a0bf528SMauro Carvalho Chehab 	} else {
6719a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff));
6729a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24,
6739a0bf528SMauro Carvalho Chehab 				(u16) ((bw->internal  / 2 * 1000) & 0xffff));
6749a0bf528SMauro Carvalho Chehab 	}
6759a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
6769a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
6779a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
6789a0bf528SMauro Carvalho Chehab 
6799a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
6809a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 922, bw->sad_cfg);
6819a0bf528SMauro Carvalho Chehab }
6829a0bf528SMauro Carvalho Chehab 
6839a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll(struct dib8000_state *state)
6849a0bf528SMauro Carvalho Chehab {
6859a0bf528SMauro Carvalho Chehab 	const struct dibx000_bandwidth_config *pll = state->cfg.pll;
6869a0bf528SMauro Carvalho Chehab 	u16 clk_cfg1, reg;
6879a0bf528SMauro Carvalho Chehab 
6889a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
6899a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 901,
6909a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv << 8) | (pll->pll_ratio << 0));
6919a0bf528SMauro Carvalho Chehab 
6929a0bf528SMauro Carvalho Chehab 		clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
6939a0bf528SMauro Carvalho Chehab 			(pll->bypclk_div << 5) | (pll->enable_refdiv << 4) |
6949a0bf528SMauro Carvalho Chehab 			(1 << 3) | (pll->pll_range << 1) |
6959a0bf528SMauro Carvalho Chehab 			(pll->pll_reset << 0);
6969a0bf528SMauro Carvalho Chehab 
6979a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 902, clk_cfg1);
6989a0bf528SMauro Carvalho Chehab 		clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
6999a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 902, clk_cfg1);
7009a0bf528SMauro Carvalho Chehab 
7019a0bf528SMauro Carvalho Chehab 		dprintk("clk_cfg1: 0x%04x", clk_cfg1);
7029a0bf528SMauro Carvalho Chehab 
7039a0bf528SMauro Carvalho Chehab 		/* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
7049a0bf528SMauro Carvalho Chehab 		if (state->cfg.pll->ADClkSrc == 0)
7059a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904,
7069a0bf528SMauro Carvalho Chehab 					(0 << 15) | (0 << 12) | (0 << 10) |
7079a0bf528SMauro Carvalho Chehab 					(pll->modulo << 8) |
7089a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
7099a0bf528SMauro Carvalho Chehab 		else if (state->cfg.refclksel != 0)
7109a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
7119a0bf528SMauro Carvalho Chehab 					((state->cfg.refclksel & 0x3) << 10) |
7129a0bf528SMauro Carvalho Chehab 					(pll->modulo << 8) |
7139a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
7149a0bf528SMauro Carvalho Chehab 		else
7159a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
7169a0bf528SMauro Carvalho Chehab 					(3 << 10) | (pll->modulo << 8) |
7179a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
7189a0bf528SMauro Carvalho Chehab 	} else {
7199a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1856, (!pll->pll_reset<<13) |
7209a0bf528SMauro Carvalho Chehab 				(pll->pll_range<<12) | (pll->pll_ratio<<6) |
7219a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv));
7229a0bf528SMauro Carvalho Chehab 
7239a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 1857);
7249a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15));
7259a0bf528SMauro Carvalho Chehab 
7269a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */
7279a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1858, reg | 1);
7289a0bf528SMauro Carvalho Chehab 
7299a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 904, (pll->modulo << 8));
7309a0bf528SMauro Carvalho Chehab 	}
7319a0bf528SMauro Carvalho Chehab 
7329a0bf528SMauro Carvalho Chehab 	dib8000_reset_pll_common(state, pll);
7339a0bf528SMauro Carvalho Chehab }
7349a0bf528SMauro Carvalho Chehab 
7359a0bf528SMauro Carvalho Chehab int dib8000_update_pll(struct dvb_frontend *fe,
736173a64cbSPatrick Boettcher 		struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
7379a0bf528SMauro Carvalho Chehab {
7389a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
7399a0bf528SMauro Carvalho Chehab 	u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
740173a64cbSPatrick Boettcher 	u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ;
7419a0bf528SMauro Carvalho Chehab 	u32 internal, xtal;
7429a0bf528SMauro Carvalho Chehab 
7439a0bf528SMauro Carvalho Chehab 	/* get back old values */
7449a0bf528SMauro Carvalho Chehab 	prediv = reg_1856 & 0x3f;
7459a0bf528SMauro Carvalho Chehab 	loopdiv = (reg_1856 >> 6) & 0x3f;
7469a0bf528SMauro Carvalho Chehab 
747173a64cbSPatrick Boettcher 	if ((pll == NULL) || (pll->pll_prediv == prediv &&
748173a64cbSPatrick Boettcher 				pll->pll_ratio == loopdiv))
749173a64cbSPatrick Boettcher 		return -EINVAL;
750173a64cbSPatrick Boettcher 
7519a0bf528SMauro Carvalho Chehab 	dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
752173a64cbSPatrick Boettcher 	if (state->revision == 0x8090) {
7539a0bf528SMauro Carvalho Chehab 		reg_1856 &= 0xf000;
7549a0bf528SMauro Carvalho Chehab 		reg_1857 = dib8000_read_word(state, 1857);
7559a0bf528SMauro Carvalho Chehab 		/* disable PLL */
7569a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15));
7579a0bf528SMauro Carvalho Chehab 
7589a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1856, reg_1856 |
7599a0bf528SMauro Carvalho Chehab 				((pll->pll_ratio & 0x3f) << 6) |
7609a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv & 0x3f));
7619a0bf528SMauro Carvalho Chehab 
7629a0bf528SMauro Carvalho Chehab 		/* write new system clk into P_sec_len */
7639a0bf528SMauro Carvalho Chehab 		internal = dib8000_read32(state, 23) / 1000;
7649a0bf528SMauro Carvalho Chehab 		dprintk("Old Internal = %d", internal);
7659a0bf528SMauro Carvalho Chehab 		xtal = 2 * (internal / loopdiv) * prediv;
7669a0bf528SMauro Carvalho Chehab 		internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio;
7679a0bf528SMauro Carvalho Chehab 		dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d", xtal, internal/1000, internal/2000, internal/8000);
7689a0bf528SMauro Carvalho Chehab 		dprintk("New Internal = %d", internal);
7699a0bf528SMauro Carvalho Chehab 
7709a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23,
7719a0bf528SMauro Carvalho Chehab 				(u16) (((internal / 2) >> 16) & 0xffff));
7729a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff));
7739a0bf528SMauro Carvalho Chehab 		/* enable PLL */
7749a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg_1857 | (1 << 15));
7759a0bf528SMauro Carvalho Chehab 
7769a0bf528SMauro Carvalho Chehab 		while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1)
7779a0bf528SMauro Carvalho Chehab 			dprintk("Waiting for PLL to lock");
7789a0bf528SMauro Carvalho Chehab 
7799a0bf528SMauro Carvalho Chehab 		/* verify */
7809a0bf528SMauro Carvalho Chehab 		reg_1856 = dib8000_read_word(state, 1856);
7819a0bf528SMauro Carvalho Chehab 		dprintk("PLL Updated with prediv = %d and loopdiv = %d",
7829a0bf528SMauro Carvalho Chehab 				reg_1856&0x3f, (reg_1856>>6)&0x3f);
783173a64cbSPatrick Boettcher 	} else {
784173a64cbSPatrick Boettcher 		if (bw != state->current_demod_bw) {
785173a64cbSPatrick Boettcher 			/** Bandwidth change => force PLL update **/
786173a64cbSPatrick Boettcher 			dprintk("PLL: Bandwidth Change %d MHz -> %d MHz (prediv: %d->%d)", state->current_demod_bw / 1000, bw / 1000, oldprediv, state->cfg.pll->pll_prediv);
787173a64cbSPatrick Boettcher 
788173a64cbSPatrick Boettcher 			if (state->cfg.pll->pll_prediv != oldprediv) {
789173a64cbSPatrick Boettcher 				/** Full PLL change only if prediv is changed **/
790173a64cbSPatrick Boettcher 
791173a64cbSPatrick Boettcher 				/** full update => bypass and reconfigure **/
792173a64cbSPatrick Boettcher 				dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio);
793173a64cbSPatrick Boettcher 				dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */
794173a64cbSPatrick Boettcher 				dib8000_reset_pll(state);
795173a64cbSPatrick Boettcher 				dib8000_write_word(state, 898, 0x0004); /* sad */
796173a64cbSPatrick Boettcher 			} else
797173a64cbSPatrick Boettcher 				ratio = state->cfg.pll->pll_ratio;
798173a64cbSPatrick Boettcher 
799173a64cbSPatrick Boettcher 			state->current_demod_bw = bw;
800173a64cbSPatrick Boettcher 		}
801173a64cbSPatrick Boettcher 
802173a64cbSPatrick Boettcher 		if (ratio != 0) {
803173a64cbSPatrick Boettcher 			/** ratio update => only change ratio **/
804173a64cbSPatrick Boettcher 			dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio);
805173a64cbSPatrick Boettcher 			dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
806173a64cbSPatrick Boettcher 		}
807173a64cbSPatrick Boettcher }
8089a0bf528SMauro Carvalho Chehab 
8099a0bf528SMauro Carvalho Chehab 	return 0;
8109a0bf528SMauro Carvalho Chehab }
8119a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_update_pll);
8129a0bf528SMauro Carvalho Chehab 
8139a0bf528SMauro Carvalho Chehab 
8149a0bf528SMauro Carvalho Chehab static int dib8000_reset_gpio(struct dib8000_state *st)
8159a0bf528SMauro Carvalho Chehab {
8169a0bf528SMauro Carvalho Chehab 	/* reset the GPIOs */
8179a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
8189a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1030, st->cfg.gpio_val);
8199a0bf528SMauro Carvalho Chehab 
8209a0bf528SMauro Carvalho Chehab 	/* TODO 782 is P_gpio_od */
8219a0bf528SMauro Carvalho Chehab 
8229a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
8239a0bf528SMauro Carvalho Chehab 
8249a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
8259a0bf528SMauro Carvalho Chehab 	return 0;
8269a0bf528SMauro Carvalho Chehab }
8279a0bf528SMauro Carvalho Chehab 
8289a0bf528SMauro Carvalho Chehab static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
8299a0bf528SMauro Carvalho Chehab {
8309a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir = dib8000_read_word(st, 1029);
8319a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir &= ~(1 << num);	/* reset the direction bit */
8329a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
8339a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
8349a0bf528SMauro Carvalho Chehab 
8359a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val = dib8000_read_word(st, 1030);
8369a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val &= ~(1 << num);	/* reset the direction bit */
8379a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val |= (val & 0x01) << num;	/* set the new value */
8389a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1030, st->cfg.gpio_val);
8399a0bf528SMauro Carvalho Chehab 
8409a0bf528SMauro Carvalho Chehab 	dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val);
8419a0bf528SMauro Carvalho Chehab 
8429a0bf528SMauro Carvalho Chehab 	return 0;
8439a0bf528SMauro Carvalho Chehab }
8449a0bf528SMauro Carvalho Chehab 
8459a0bf528SMauro Carvalho Chehab int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
8469a0bf528SMauro Carvalho Chehab {
8479a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
8489a0bf528SMauro Carvalho Chehab 	return dib8000_cfg_gpio(state, num, dir, val);
8499a0bf528SMauro Carvalho Chehab }
8509a0bf528SMauro Carvalho Chehab 
8519a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_set_gpio);
8529a0bf528SMauro Carvalho Chehab static const u16 dib8000_defaults[] = {
8539a0bf528SMauro Carvalho Chehab 	/* auto search configuration - lock0 by default waiting
8549a0bf528SMauro Carvalho Chehab 	 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
8559a0bf528SMauro Carvalho Chehab 	3, 7,
8569a0bf528SMauro Carvalho Chehab 	0x0004,
8579a0bf528SMauro Carvalho Chehab 	0x0400,
8589a0bf528SMauro Carvalho Chehab 	0x0814,
8599a0bf528SMauro Carvalho Chehab 
8609a0bf528SMauro Carvalho Chehab 	12, 11,
8619a0bf528SMauro Carvalho Chehab 	0x001b,
8629a0bf528SMauro Carvalho Chehab 	0x7740,
8639a0bf528SMauro Carvalho Chehab 	0x005b,
8649a0bf528SMauro Carvalho Chehab 	0x8d80,
8659a0bf528SMauro Carvalho Chehab 	0x01c9,
8669a0bf528SMauro Carvalho Chehab 	0xc380,
8679a0bf528SMauro Carvalho Chehab 	0x0000,
8689a0bf528SMauro Carvalho Chehab 	0x0080,
8699a0bf528SMauro Carvalho Chehab 	0x0000,
8709a0bf528SMauro Carvalho Chehab 	0x0090,
8719a0bf528SMauro Carvalho Chehab 	0x0001,
8729a0bf528SMauro Carvalho Chehab 	0xd4c0,
8739a0bf528SMauro Carvalho Chehab 
8749a0bf528SMauro Carvalho Chehab 	/*1, 32,
8759a0bf528SMauro Carvalho Chehab 		0x6680 // P_corm_thres Lock algorithms configuration */
8769a0bf528SMauro Carvalho Chehab 
8779a0bf528SMauro Carvalho Chehab 	11, 80,			/* set ADC level to -16 */
8789a0bf528SMauro Carvalho Chehab 	(1 << 13) - 825 - 117,
8799a0bf528SMauro Carvalho Chehab 	(1 << 13) - 837 - 117,
8809a0bf528SMauro Carvalho Chehab 	(1 << 13) - 811 - 117,
8819a0bf528SMauro Carvalho Chehab 	(1 << 13) - 766 - 117,
8829a0bf528SMauro Carvalho Chehab 	(1 << 13) - 737 - 117,
8839a0bf528SMauro Carvalho Chehab 	(1 << 13) - 693 - 117,
8849a0bf528SMauro Carvalho Chehab 	(1 << 13) - 648 - 117,
8859a0bf528SMauro Carvalho Chehab 	(1 << 13) - 619 - 117,
8869a0bf528SMauro Carvalho Chehab 	(1 << 13) - 575 - 117,
8879a0bf528SMauro Carvalho Chehab 	(1 << 13) - 531 - 117,
8889a0bf528SMauro Carvalho Chehab 	(1 << 13) - 501 - 117,
8899a0bf528SMauro Carvalho Chehab 
8909a0bf528SMauro Carvalho Chehab 	4, 108,
8919a0bf528SMauro Carvalho Chehab 	0,
8929a0bf528SMauro Carvalho Chehab 	0,
8939a0bf528SMauro Carvalho Chehab 	0,
8949a0bf528SMauro Carvalho Chehab 	0,
8959a0bf528SMauro Carvalho Chehab 
8969a0bf528SMauro Carvalho Chehab 	1, 175,
8979a0bf528SMauro Carvalho Chehab 	0x0410,
8989a0bf528SMauro Carvalho Chehab 	1, 179,
8999a0bf528SMauro Carvalho Chehab 	8192,			// P_fft_nb_to_cut
9009a0bf528SMauro Carvalho Chehab 
9019a0bf528SMauro Carvalho Chehab 	6, 181,
9029a0bf528SMauro Carvalho Chehab 	0x2800,			// P_coff_corthres_ ( 2k 4k 8k ) 0x2800
9039a0bf528SMauro Carvalho Chehab 	0x2800,
9049a0bf528SMauro Carvalho Chehab 	0x2800,
9059a0bf528SMauro Carvalho Chehab 	0x2800,			// P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
9069a0bf528SMauro Carvalho Chehab 	0x2800,
9079a0bf528SMauro Carvalho Chehab 	0x2800,
9089a0bf528SMauro Carvalho Chehab 
9099a0bf528SMauro Carvalho Chehab 	2, 193,
9109a0bf528SMauro Carvalho Chehab 	0x0666,			// P_pha3_thres
9119a0bf528SMauro Carvalho Chehab 	0x0000,			// P_cti_use_cpe, P_cti_use_prog
9129a0bf528SMauro Carvalho Chehab 
9139a0bf528SMauro Carvalho Chehab 	2, 205,
9149a0bf528SMauro Carvalho Chehab 	0x200f,			// P_cspu_regul, P_cspu_win_cut
9159a0bf528SMauro Carvalho Chehab 	0x000f,			// P_des_shift_work
9169a0bf528SMauro Carvalho Chehab 
9179a0bf528SMauro Carvalho Chehab 	5, 215,
9189a0bf528SMauro Carvalho Chehab 	0x023d,			// P_adp_regul_cnt
9199a0bf528SMauro Carvalho Chehab 	0x00a4,			// P_adp_noise_cnt
9209a0bf528SMauro Carvalho Chehab 	0x00a4,			// P_adp_regul_ext
9219a0bf528SMauro Carvalho Chehab 	0x7ff0,			// P_adp_noise_ext
9229a0bf528SMauro Carvalho Chehab 	0x3ccc,			// P_adp_fil
9239a0bf528SMauro Carvalho Chehab 
9249a0bf528SMauro Carvalho Chehab 	1, 230,
9259a0bf528SMauro Carvalho Chehab 	0x0000,			// P_2d_byp_ti_num
9269a0bf528SMauro Carvalho Chehab 
9279a0bf528SMauro Carvalho Chehab 	1, 263,
9289a0bf528SMauro Carvalho Chehab 	0x800,			//P_equal_thres_wgn
9299a0bf528SMauro Carvalho Chehab 
9309a0bf528SMauro Carvalho Chehab 	1, 268,
9319a0bf528SMauro Carvalho Chehab 	(2 << 9) | 39,		// P_equal_ctrl_synchro, P_equal_speedmode
9329a0bf528SMauro Carvalho Chehab 
9339a0bf528SMauro Carvalho Chehab 	1, 270,
9349a0bf528SMauro Carvalho Chehab 	0x0001,			// P_div_lock0_wait
9359a0bf528SMauro Carvalho Chehab 	1, 285,
9369a0bf528SMauro Carvalho Chehab 	0x0020,			//p_fec_
9379a0bf528SMauro Carvalho Chehab 	1, 299,
9389a0bf528SMauro Carvalho Chehab 	0x0062,			/* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */
9399a0bf528SMauro Carvalho Chehab 
9409a0bf528SMauro Carvalho Chehab 	1, 338,
9419a0bf528SMauro Carvalho Chehab 	(1 << 12) |		// P_ctrl_corm_thres4pre_freq_inh=1
9429a0bf528SMauro Carvalho Chehab 		(1 << 10) |
9439a0bf528SMauro Carvalho Chehab 		(0 << 9) |		/* P_ctrl_pre_freq_inh=0 */
9449a0bf528SMauro Carvalho Chehab 		(3 << 5) |		/* P_ctrl_pre_freq_step=3 */
9459a0bf528SMauro Carvalho Chehab 		(1 << 0),		/* P_pre_freq_win_len=1 */
9469a0bf528SMauro Carvalho Chehab 
9479a0bf528SMauro Carvalho Chehab 	0,
9489a0bf528SMauro Carvalho Chehab };
9499a0bf528SMauro Carvalho Chehab 
9509a0bf528SMauro Carvalho Chehab static u16 dib8000_identify(struct i2c_device *client)
9519a0bf528SMauro Carvalho Chehab {
9529a0bf528SMauro Carvalho Chehab 	u16 value;
9539a0bf528SMauro Carvalho Chehab 
9549a0bf528SMauro Carvalho Chehab 	//because of glitches sometimes
9559a0bf528SMauro Carvalho Chehab 	value = dib8000_i2c_read16(client, 896);
9569a0bf528SMauro Carvalho Chehab 
9579a0bf528SMauro Carvalho Chehab 	if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
9589a0bf528SMauro Carvalho Chehab 		dprintk("wrong Vendor ID (read=0x%x)", value);
9599a0bf528SMauro Carvalho Chehab 		return 0;
9609a0bf528SMauro Carvalho Chehab 	}
9619a0bf528SMauro Carvalho Chehab 
9629a0bf528SMauro Carvalho Chehab 	value = dib8000_i2c_read16(client, 897);
9639a0bf528SMauro Carvalho Chehab 	if (value != 0x8000 && value != 0x8001 &&
9649a0bf528SMauro Carvalho Chehab 			value != 0x8002 && value != 0x8090) {
9659a0bf528SMauro Carvalho Chehab 		dprintk("wrong Device ID (%x)", value);
9669a0bf528SMauro Carvalho Chehab 		return 0;
9679a0bf528SMauro Carvalho Chehab 	}
9689a0bf528SMauro Carvalho Chehab 
9699a0bf528SMauro Carvalho Chehab 	switch (value) {
9709a0bf528SMauro Carvalho Chehab 	case 0x8000:
9719a0bf528SMauro Carvalho Chehab 		dprintk("found DiB8000A");
9729a0bf528SMauro Carvalho Chehab 		break;
9739a0bf528SMauro Carvalho Chehab 	case 0x8001:
9749a0bf528SMauro Carvalho Chehab 		dprintk("found DiB8000B");
9759a0bf528SMauro Carvalho Chehab 		break;
9769a0bf528SMauro Carvalho Chehab 	case 0x8002:
9779a0bf528SMauro Carvalho Chehab 		dprintk("found DiB8000C");
9789a0bf528SMauro Carvalho Chehab 		break;
9799a0bf528SMauro Carvalho Chehab 	case 0x8090:
9809a0bf528SMauro Carvalho Chehab 		dprintk("found DiB8096P");
9819a0bf528SMauro Carvalho Chehab 		break;
9829a0bf528SMauro Carvalho Chehab 	}
9839a0bf528SMauro Carvalho Chehab 	return value;
9849a0bf528SMauro Carvalho Chehab }
9859a0bf528SMauro Carvalho Chehab 
9869a0bf528SMauro Carvalho Chehab static int dib8000_reset(struct dvb_frontend *fe)
9879a0bf528SMauro Carvalho Chehab {
9889a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
9899a0bf528SMauro Carvalho Chehab 
9909a0bf528SMauro Carvalho Chehab 	if ((state->revision = dib8000_identify(&state->i2c)) == 0)
9919a0bf528SMauro Carvalho Chehab 		return -EINVAL;
9929a0bf528SMauro Carvalho Chehab 
9939a0bf528SMauro Carvalho Chehab 	/* sram lead in, rdy */
9949a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
9959a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1287, 0x0003);
9969a0bf528SMauro Carvalho Chehab 
9979a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8000)
9989a0bf528SMauro Carvalho Chehab 		dprintk("error : dib8000 MA not supported");
9999a0bf528SMauro Carvalho Chehab 
10009a0bf528SMauro Carvalho Chehab 	dibx000_reset_i2c_master(&state->i2c_master);
10019a0bf528SMauro Carvalho Chehab 
10029a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
10039a0bf528SMauro Carvalho Chehab 
10049a0bf528SMauro Carvalho Chehab 	/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
1005173a64cbSPatrick Boettcher 	dib8000_set_adc_state(state, DIBX000_ADC_OFF);
10069a0bf528SMauro Carvalho Chehab 
10079a0bf528SMauro Carvalho Chehab 	/* restart all parts */
10089a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0xffff);
10099a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 771, 0xffff);
10109a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 772, 0xfffc);
10119a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
10129a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1280, 0x0045);
10139a0bf528SMauro Carvalho Chehab 	else
10149a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1280, 0x004d);
10159a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1281, 0x000c);
10169a0bf528SMauro Carvalho Chehab 
10179a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0000);
10189a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 771, 0x0000);
10199a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 772, 0x0000);
10209a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 898, 0x0004);	// sad
10219a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1280, 0x0000);
10229a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1281, 0x0000);
10239a0bf528SMauro Carvalho Chehab 
10249a0bf528SMauro Carvalho Chehab 	/* drives */
10259a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
10269a0bf528SMauro Carvalho Chehab 		if (state->cfg.drives)
10279a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 906, state->cfg.drives);
10289a0bf528SMauro Carvalho Chehab 		else {
10299a0bf528SMauro Carvalho Chehab 			dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
10309a0bf528SMauro Carvalho Chehab 			/* min drive SDRAM - not optimal - adjust */
10319a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 906, 0x2d98);
10329a0bf528SMauro Carvalho Chehab 		}
10339a0bf528SMauro Carvalho Chehab 	}
10349a0bf528SMauro Carvalho Chehab 
10359a0bf528SMauro Carvalho Chehab 	dib8000_reset_pll(state);
10369a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
10379a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 898, 0x0004);
10389a0bf528SMauro Carvalho Chehab 
10399a0bf528SMauro Carvalho Chehab 	if (dib8000_reset_gpio(state) != 0)
10409a0bf528SMauro Carvalho Chehab 		dprintk("GPIO reset was not successful.");
10419a0bf528SMauro Carvalho Chehab 
10429a0bf528SMauro Carvalho Chehab 	if ((state->revision != 0x8090) &&
10439a0bf528SMauro Carvalho Chehab 			(dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
10449a0bf528SMauro Carvalho Chehab 		dprintk("OUTPUT_MODE could not be resetted.");
10459a0bf528SMauro Carvalho Chehab 
10469a0bf528SMauro Carvalho Chehab 	state->current_agc = NULL;
10479a0bf528SMauro Carvalho Chehab 
10489a0bf528SMauro Carvalho Chehab 	// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
10499a0bf528SMauro Carvalho Chehab 	/* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
10509a0bf528SMauro Carvalho Chehab 	if (state->cfg.pll->ifreq == 0)
10519a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 40, 0x0755);	/* P_iqc_corr_inh = 0 enable IQcorr block */
10529a0bf528SMauro Carvalho Chehab 	else
10539a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 40, 0x1f55);	/* P_iqc_corr_inh = 1 disable IQcorr block */
10549a0bf528SMauro Carvalho Chehab 
10559a0bf528SMauro Carvalho Chehab 	{
10569a0bf528SMauro Carvalho Chehab 		u16 l = 0, r;
10579a0bf528SMauro Carvalho Chehab 		const u16 *n;
10589a0bf528SMauro Carvalho Chehab 		n = dib8000_defaults;
10599a0bf528SMauro Carvalho Chehab 		l = *n++;
10609a0bf528SMauro Carvalho Chehab 		while (l) {
10619a0bf528SMauro Carvalho Chehab 			r = *n++;
10629a0bf528SMauro Carvalho Chehab 			do {
10639a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, r, *n++);
10649a0bf528SMauro Carvalho Chehab 				r++;
10659a0bf528SMauro Carvalho Chehab 			} while (--l);
10669a0bf528SMauro Carvalho Chehab 			l = *n++;
10679a0bf528SMauro Carvalho Chehab 		}
10689a0bf528SMauro Carvalho Chehab 	}
1069173a64cbSPatrick Boettcher 
10709a0bf528SMauro Carvalho Chehab 	state->isdbt_cfg_loaded = 0;
10719a0bf528SMauro Carvalho Chehab 
10729a0bf528SMauro Carvalho Chehab 	//div_cfg override for special configs
1073173a64cbSPatrick Boettcher 	if ((state->revision != 8090) && (state->cfg.div_cfg != 0))
10749a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 903, state->cfg.div_cfg);
10759a0bf528SMauro Carvalho Chehab 
10769a0bf528SMauro Carvalho Chehab 	/* unforce divstr regardless whether i2c enumeration was done or not */
10779a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
10789a0bf528SMauro Carvalho Chehab 
10799a0bf528SMauro Carvalho Chehab 	dib8000_set_bandwidth(fe, 6000);
10809a0bf528SMauro Carvalho Chehab 
10819a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
10829a0bf528SMauro Carvalho Chehab 	dib8000_sad_calib(state);
1083173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
10849a0bf528SMauro Carvalho Chehab 		dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
1085173a64cbSPatrick Boettcher 
1086173a64cbSPatrick Boettcher 	/* ber_rs_len = 3 */
1087173a64cbSPatrick Boettcher 	dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));
10889a0bf528SMauro Carvalho Chehab 
10899a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
10909a0bf528SMauro Carvalho Chehab 
10919a0bf528SMauro Carvalho Chehab 	return 0;
10929a0bf528SMauro Carvalho Chehab }
10939a0bf528SMauro Carvalho Chehab 
10949a0bf528SMauro Carvalho Chehab static void dib8000_restart_agc(struct dib8000_state *state)
10959a0bf528SMauro Carvalho Chehab {
10969a0bf528SMauro Carvalho Chehab 	// P_restart_iqc & P_restart_agc
10979a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0a00);
10989a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0000);
10999a0bf528SMauro Carvalho Chehab }
11009a0bf528SMauro Carvalho Chehab 
11019a0bf528SMauro Carvalho Chehab static int dib8000_update_lna(struct dib8000_state *state)
11029a0bf528SMauro Carvalho Chehab {
11039a0bf528SMauro Carvalho Chehab 	u16 dyn_gain;
11049a0bf528SMauro Carvalho Chehab 
11059a0bf528SMauro Carvalho Chehab 	if (state->cfg.update_lna) {
11069a0bf528SMauro Carvalho Chehab 		// read dyn_gain here (because it is demod-dependent and not tuner)
11079a0bf528SMauro Carvalho Chehab 		dyn_gain = dib8000_read_word(state, 390);
11089a0bf528SMauro Carvalho Chehab 
11099a0bf528SMauro Carvalho Chehab 		if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
11109a0bf528SMauro Carvalho Chehab 			dib8000_restart_agc(state);
11119a0bf528SMauro Carvalho Chehab 			return 1;
11129a0bf528SMauro Carvalho Chehab 		}
11139a0bf528SMauro Carvalho Chehab 	}
11149a0bf528SMauro Carvalho Chehab 	return 0;
11159a0bf528SMauro Carvalho Chehab }
11169a0bf528SMauro Carvalho Chehab 
11179a0bf528SMauro Carvalho Chehab static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
11189a0bf528SMauro Carvalho Chehab {
11199a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *agc = NULL;
11209a0bf528SMauro Carvalho Chehab 	int i;
11219a0bf528SMauro Carvalho Chehab 	u16 reg;
11229a0bf528SMauro Carvalho Chehab 
11239a0bf528SMauro Carvalho Chehab 	if (state->current_band == band && state->current_agc != NULL)
11249a0bf528SMauro Carvalho Chehab 		return 0;
11259a0bf528SMauro Carvalho Chehab 	state->current_band = band;
11269a0bf528SMauro Carvalho Chehab 
11279a0bf528SMauro Carvalho Chehab 	for (i = 0; i < state->cfg.agc_config_count; i++)
11289a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc[i].band_caps & band) {
11299a0bf528SMauro Carvalho Chehab 			agc = &state->cfg.agc[i];
11309a0bf528SMauro Carvalho Chehab 			break;
11319a0bf528SMauro Carvalho Chehab 		}
11329a0bf528SMauro Carvalho Chehab 
11339a0bf528SMauro Carvalho Chehab 	if (agc == NULL) {
11349a0bf528SMauro Carvalho Chehab 		dprintk("no valid AGC configuration found for band 0x%02x", band);
11359a0bf528SMauro Carvalho Chehab 		return -EINVAL;
11369a0bf528SMauro Carvalho Chehab 	}
11379a0bf528SMauro Carvalho Chehab 
11389a0bf528SMauro Carvalho Chehab 	state->current_agc = agc;
11399a0bf528SMauro Carvalho Chehab 
11409a0bf528SMauro Carvalho Chehab 	/* AGC */
11419a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 76, agc->setup);
11429a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 77, agc->inv_gain);
11439a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 78, agc->time_stabiliz);
11449a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
11459a0bf528SMauro Carvalho Chehab 
11469a0bf528SMauro Carvalho Chehab 	// Demod AGC loop configuration
11479a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
11489a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
11499a0bf528SMauro Carvalho Chehab 
11509a0bf528SMauro Carvalho Chehab 	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
11519a0bf528SMauro Carvalho Chehab 		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
11529a0bf528SMauro Carvalho Chehab 
11539a0bf528SMauro Carvalho Chehab 	/* AGC continued */
11549a0bf528SMauro Carvalho Chehab 	if (state->wbd_ref != 0)
11559a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 106, state->wbd_ref);
11569a0bf528SMauro Carvalho Chehab 	else			// use default
11579a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 106, agc->wbd_ref);
11589a0bf528SMauro Carvalho Chehab 
11599a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090) {
11609a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 922) & (0x3 << 2);
11619a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
11629a0bf528SMauro Carvalho Chehab 	}
11639a0bf528SMauro Carvalho Chehab 
11649a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
11659a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 108, agc->agc1_max);
11669a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 109, agc->agc1_min);
11679a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 110, agc->agc2_max);
11689a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 111, agc->agc2_min);
11699a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
11709a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
11719a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
11729a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
11739a0bf528SMauro Carvalho Chehab 
11749a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 75, agc->agc1_pt3);
11759a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
11769a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923,
11779a0bf528SMauro Carvalho Chehab 				(dib8000_read_word(state, 923) & 0xffe3) |
11789a0bf528SMauro Carvalho Chehab 				(agc->wbd_inv << 4) | (agc->wbd_sel << 2));
11799a0bf528SMauro Carvalho Chehab 
11809a0bf528SMauro Carvalho Chehab 	return 0;
11819a0bf528SMauro Carvalho Chehab }
11829a0bf528SMauro Carvalho Chehab 
11839a0bf528SMauro Carvalho Chehab void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
11849a0bf528SMauro Carvalho Chehab {
11859a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
11869a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_ADC_ON);
11879a0bf528SMauro Carvalho Chehab 	dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
11889a0bf528SMauro Carvalho Chehab }
11899a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_pwm_agc_reset);
11909a0bf528SMauro Carvalho Chehab 
11919a0bf528SMauro Carvalho Chehab static int dib8000_agc_soft_split(struct dib8000_state *state)
11929a0bf528SMauro Carvalho Chehab {
11939a0bf528SMauro Carvalho Chehab 	u16 agc, split_offset;
11949a0bf528SMauro Carvalho Chehab 
11959a0bf528SMauro Carvalho Chehab 	if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
11969a0bf528SMauro Carvalho Chehab 		return FE_CALLBACK_TIME_NEVER;
11979a0bf528SMauro Carvalho Chehab 
11989a0bf528SMauro Carvalho Chehab 	// n_agc_global
11999a0bf528SMauro Carvalho Chehab 	agc = dib8000_read_word(state, 390);
12009a0bf528SMauro Carvalho Chehab 
12019a0bf528SMauro Carvalho Chehab 	if (agc > state->current_agc->split.min_thres)
12029a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.min;
12039a0bf528SMauro Carvalho Chehab 	else if (agc < state->current_agc->split.max_thres)
12049a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.max;
12059a0bf528SMauro Carvalho Chehab 	else
12069a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.max *
12079a0bf528SMauro Carvalho Chehab 			(agc - state->current_agc->split.min_thres) /
12089a0bf528SMauro Carvalho Chehab 			(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
12099a0bf528SMauro Carvalho Chehab 
12109a0bf528SMauro Carvalho Chehab 	dprintk("AGC split_offset: %d", split_offset);
12119a0bf528SMauro Carvalho Chehab 
12129a0bf528SMauro Carvalho Chehab 	// P_agc_force_split and P_agc_split_offset
12139a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
12149a0bf528SMauro Carvalho Chehab 	return 5000;
12159a0bf528SMauro Carvalho Chehab }
12169a0bf528SMauro Carvalho Chehab 
12179a0bf528SMauro Carvalho Chehab static int dib8000_agc_startup(struct dvb_frontend *fe)
12189a0bf528SMauro Carvalho Chehab {
12199a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
12209a0bf528SMauro Carvalho Chehab 	enum frontend_tune_state *tune_state = &state->tune_state;
12219a0bf528SMauro Carvalho Chehab 	int ret = 0;
12229a0bf528SMauro Carvalho Chehab 	u16 reg, upd_demod_gain_period = 0x8000;
12239a0bf528SMauro Carvalho Chehab 
12249a0bf528SMauro Carvalho Chehab 	switch (*tune_state) {
12259a0bf528SMauro Carvalho Chehab 	case CT_AGC_START:
12269a0bf528SMauro Carvalho Chehab 		// set power-up level: interf+analog+AGC
12279a0bf528SMauro Carvalho Chehab 
12289a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090)
12299a0bf528SMauro Carvalho Chehab 			dib8000_set_adc_state(state, DIBX000_ADC_ON);
12309a0bf528SMauro Carvalho Chehab 		else {
12319a0bf528SMauro Carvalho Chehab 			dib8000_set_power_mode(state, DIB8000_POWER_ALL);
12329a0bf528SMauro Carvalho Chehab 
12339a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1947)&0xff00;
12349a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1946,
12359a0bf528SMauro Carvalho Chehab 					upd_demod_gain_period & 0xFFFF);
12369a0bf528SMauro Carvalho Chehab 			/* bit 14 = enDemodGain */
12379a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1947, reg | (1<<14) |
12389a0bf528SMauro Carvalho Chehab 					((upd_demod_gain_period >> 16) & 0xFF));
12399a0bf528SMauro Carvalho Chehab 
12409a0bf528SMauro Carvalho Chehab 			/* enable adc i & q */
12419a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1920);
12429a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1920, (reg | 0x3) &
12439a0bf528SMauro Carvalho Chehab 					(~(1 << 7)));
12449a0bf528SMauro Carvalho Chehab 		}
12459a0bf528SMauro Carvalho Chehab 
12469a0bf528SMauro Carvalho Chehab 		if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
12479a0bf528SMauro Carvalho Chehab 			*tune_state = CT_AGC_STOP;
12489a0bf528SMauro Carvalho Chehab 			state->status = FE_STATUS_TUNE_FAILED;
12499a0bf528SMauro Carvalho Chehab 			break;
12509a0bf528SMauro Carvalho Chehab 		}
12519a0bf528SMauro Carvalho Chehab 
12529a0bf528SMauro Carvalho Chehab 		ret = 70;
12539a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STEP_0;
12549a0bf528SMauro Carvalho Chehab 		break;
12559a0bf528SMauro Carvalho Chehab 
12569a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_0:
12579a0bf528SMauro Carvalho Chehab 		//AGC initialization
12589a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
12599a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(fe, 1);
12609a0bf528SMauro Carvalho Chehab 
12619a0bf528SMauro Carvalho Chehab 		dib8000_restart_agc(state);
12629a0bf528SMauro Carvalho Chehab 
12639a0bf528SMauro Carvalho Chehab 		// wait AGC rough lock time
12649a0bf528SMauro Carvalho Chehab 		ret = 50;
12659a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STEP_1;
12669a0bf528SMauro Carvalho Chehab 		break;
12679a0bf528SMauro Carvalho Chehab 
12689a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_1:
12699a0bf528SMauro Carvalho Chehab 		// wait AGC accurate lock time
12709a0bf528SMauro Carvalho Chehab 		ret = 70;
12719a0bf528SMauro Carvalho Chehab 
12729a0bf528SMauro Carvalho Chehab 		if (dib8000_update_lna(state))
12739a0bf528SMauro Carvalho Chehab 			// wait only AGC rough lock time
12749a0bf528SMauro Carvalho Chehab 			ret = 50;
12759a0bf528SMauro Carvalho Chehab 		else
12769a0bf528SMauro Carvalho Chehab 			*tune_state = CT_AGC_STEP_2;
12779a0bf528SMauro Carvalho Chehab 		break;
12789a0bf528SMauro Carvalho Chehab 
12799a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_2:
12809a0bf528SMauro Carvalho Chehab 		dib8000_agc_soft_split(state);
12819a0bf528SMauro Carvalho Chehab 
12829a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
12839a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(fe, 0);
12849a0bf528SMauro Carvalho Chehab 
12859a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STOP;
12869a0bf528SMauro Carvalho Chehab 		break;
12879a0bf528SMauro Carvalho Chehab 	default:
12889a0bf528SMauro Carvalho Chehab 		ret = dib8000_agc_soft_split(state);
12899a0bf528SMauro Carvalho Chehab 		break;
12909a0bf528SMauro Carvalho Chehab 	}
12919a0bf528SMauro Carvalho Chehab 	return ret;
12929a0bf528SMauro Carvalho Chehab 
12939a0bf528SMauro Carvalho Chehab }
12949a0bf528SMauro Carvalho Chehab 
12959a0bf528SMauro Carvalho Chehab static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
12969a0bf528SMauro Carvalho Chehab {
12979a0bf528SMauro Carvalho Chehab 	u16 reg;
12989a0bf528SMauro Carvalho Chehab 
12999a0bf528SMauro Carvalho Chehab 	drive &= 0x7;
13009a0bf528SMauro Carvalho Chehab 
13019a0bf528SMauro Carvalho Chehab 	/* drive host bus 2, 3, 4 */
13029a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1798) &
13039a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
13049a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
13059a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1798, reg);
13069a0bf528SMauro Carvalho Chehab 
13079a0bf528SMauro Carvalho Chehab 	/* drive host bus 5,6 */
13089a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
13099a0bf528SMauro Carvalho Chehab 	reg |= (drive<<8) | (drive<<2);
13109a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1799, reg);
13119a0bf528SMauro Carvalho Chehab 
13129a0bf528SMauro Carvalho Chehab 	/* drive host bus 7, 8, 9 */
13139a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1800) &
13149a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
13159a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
13169a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1800, reg);
13179a0bf528SMauro Carvalho Chehab 
13189a0bf528SMauro Carvalho Chehab 	/* drive host bus 10, 11 */
13199a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
13209a0bf528SMauro Carvalho Chehab 	reg |= (drive<<8) | (drive<<2);
13219a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1801, reg);
13229a0bf528SMauro Carvalho Chehab 
13239a0bf528SMauro Carvalho Chehab 	/* drive host bus 12, 13, 14 */
13249a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1802) &
13259a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
13269a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
13279a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1802, reg);
13289a0bf528SMauro Carvalho Chehab }
13299a0bf528SMauro Carvalho Chehab 
13309a0bf528SMauro Carvalho Chehab static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
13319a0bf528SMauro Carvalho Chehab 		u32 insertExtSynchro, u32 syncSize)
13329a0bf528SMauro Carvalho Chehab {
13339a0bf528SMauro Carvalho Chehab 	u32 quantif = 3;
13349a0bf528SMauro Carvalho Chehab 	u32 nom = (insertExtSynchro * P_Kin+syncSize);
13359a0bf528SMauro Carvalho Chehab 	u32 denom = P_Kout;
13369a0bf528SMauro Carvalho Chehab 	u32 syncFreq = ((nom << quantif) / denom);
13379a0bf528SMauro Carvalho Chehab 
13389a0bf528SMauro Carvalho Chehab 	if ((syncFreq & ((1 << quantif) - 1)) != 0)
13399a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif) + 1;
13409a0bf528SMauro Carvalho Chehab 	else
13419a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif);
13429a0bf528SMauro Carvalho Chehab 
13439a0bf528SMauro Carvalho Chehab 	if (syncFreq != 0)
13449a0bf528SMauro Carvalho Chehab 		syncFreq = syncFreq - 1;
13459a0bf528SMauro Carvalho Chehab 
13469a0bf528SMauro Carvalho Chehab 	return syncFreq;
13479a0bf528SMauro Carvalho Chehab }
13489a0bf528SMauro Carvalho Chehab 
13499a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
13509a0bf528SMauro Carvalho Chehab 		u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
13519a0bf528SMauro Carvalho Chehab 		u32 syncWord, u32 syncSize)
13529a0bf528SMauro Carvalho Chehab {
13539a0bf528SMauro Carvalho Chehab 	dprintk("Configure DibStream Tx");
13549a0bf528SMauro Carvalho Chehab 
13559a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1615, 1);
13569a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1603, P_Kin);
13579a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1605, P_Kout);
13589a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1606, insertExtSynchro);
13599a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1608, synchroMode);
13609a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
13619a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1610, syncWord & 0xffff);
13629a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1612, syncSize);
13639a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1615, 0);
13649a0bf528SMauro Carvalho Chehab }
13659a0bf528SMauro Carvalho Chehab 
13669a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
13679a0bf528SMauro Carvalho Chehab 		u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
13689a0bf528SMauro Carvalho Chehab 		u32 syncWord, u32 syncSize, u32 dataOutRate)
13699a0bf528SMauro Carvalho Chehab {
13709a0bf528SMauro Carvalho Chehab 	u32 syncFreq;
13719a0bf528SMauro Carvalho Chehab 
13729a0bf528SMauro Carvalho Chehab 	dprintk("Configure DibStream Rx synchroMode = %d", synchroMode);
13739a0bf528SMauro Carvalho Chehab 
13749a0bf528SMauro Carvalho Chehab 	if ((P_Kin != 0) && (P_Kout != 0)) {
13759a0bf528SMauro Carvalho Chehab 		syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
13769a0bf528SMauro Carvalho Chehab 				insertExtSynchro, syncSize);
13779a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1542, syncFreq);
13789a0bf528SMauro Carvalho Chehab 	}
13799a0bf528SMauro Carvalho Chehab 
13809a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1554, 1);
13819a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1536, P_Kin);
13829a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1537, P_Kout);
13839a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1539, synchroMode);
13849a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
13859a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1541, syncWord & 0xffff);
13869a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1543, syncSize);
13879a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1544, dataOutRate);
13889a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1554, 0);
13899a0bf528SMauro Carvalho Chehab }
13909a0bf528SMauro Carvalho Chehab 
13919a0bf528SMauro Carvalho Chehab static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
13929a0bf528SMauro Carvalho Chehab {
13939a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
13949a0bf528SMauro Carvalho Chehab 
13959a0bf528SMauro Carvalho Chehab 	reg_1287 = dib8000_read_word(state, 1287);
13969a0bf528SMauro Carvalho Chehab 
13979a0bf528SMauro Carvalho Chehab 	switch (onoff) {
13989a0bf528SMauro Carvalho Chehab 	case 1:
13999a0bf528SMauro Carvalho Chehab 			reg_1287 &= ~(1 << 8);
14009a0bf528SMauro Carvalho Chehab 			break;
14019a0bf528SMauro Carvalho Chehab 	case 0:
14029a0bf528SMauro Carvalho Chehab 			reg_1287 |= (1 << 8);
14039a0bf528SMauro Carvalho Chehab 			break;
14049a0bf528SMauro Carvalho Chehab 	}
14059a0bf528SMauro Carvalho Chehab 
14069a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1287, reg_1287);
14079a0bf528SMauro Carvalho Chehab }
14089a0bf528SMauro Carvalho Chehab 
14099a0bf528SMauro Carvalho Chehab static void dib8096p_configMpegMux(struct dib8000_state *state,
14109a0bf528SMauro Carvalho Chehab 		u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
14119a0bf528SMauro Carvalho Chehab {
14129a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
14139a0bf528SMauro Carvalho Chehab 
14149a0bf528SMauro Carvalho Chehab 	dprintk("Enable Mpeg mux");
14159a0bf528SMauro Carvalho Chehab 
14169a0bf528SMauro Carvalho Chehab 	dib8096p_enMpegMux(state, 0);
14179a0bf528SMauro Carvalho Chehab 
14189a0bf528SMauro Carvalho Chehab 	/* If the input mode is MPEG do not divide the serial clock */
14199a0bf528SMauro Carvalho Chehab 	if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
14209a0bf528SMauro Carvalho Chehab 		enSerialClkDiv2 = 0;
14219a0bf528SMauro Carvalho Chehab 
14229a0bf528SMauro Carvalho Chehab 	reg_1287 = ((pulseWidth & 0x1f) << 3) |
14239a0bf528SMauro Carvalho Chehab 		((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
14249a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1287, reg_1287);
14259a0bf528SMauro Carvalho Chehab 
14269a0bf528SMauro Carvalho Chehab 	dib8096p_enMpegMux(state, 1);
14279a0bf528SMauro Carvalho Chehab }
14289a0bf528SMauro Carvalho Chehab 
14299a0bf528SMauro Carvalho Chehab static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
14309a0bf528SMauro Carvalho Chehab {
14319a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
14329a0bf528SMauro Carvalho Chehab 
14339a0bf528SMauro Carvalho Chehab 	switch (mode) {
14349a0bf528SMauro Carvalho Chehab 	case MPEG_ON_DIBTX:
14359a0bf528SMauro Carvalho Chehab 			dprintk("SET MPEG ON DIBSTREAM TX");
14369a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
14379a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 9); break;
14389a0bf528SMauro Carvalho Chehab 	case DIV_ON_DIBTX:
14399a0bf528SMauro Carvalho Chehab 			dprintk("SET DIV_OUT ON DIBSTREAM TX");
14409a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
14419a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 8); break;
14429a0bf528SMauro Carvalho Chehab 	case ADC_ON_DIBTX:
14439a0bf528SMauro Carvalho Chehab 			dprintk("SET ADC_OUT ON DIBSTREAM TX");
14449a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
14459a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 7); break;
14469a0bf528SMauro Carvalho Chehab 	default:
14479a0bf528SMauro Carvalho Chehab 			break;
14489a0bf528SMauro Carvalho Chehab 	}
14499a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1288, reg_1288);
14509a0bf528SMauro Carvalho Chehab }
14519a0bf528SMauro Carvalho Chehab 
14529a0bf528SMauro Carvalho Chehab static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
14539a0bf528SMauro Carvalho Chehab {
14549a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
14559a0bf528SMauro Carvalho Chehab 
14569a0bf528SMauro Carvalho Chehab 	switch (mode) {
14579a0bf528SMauro Carvalho Chehab 	case DEMOUT_ON_HOSTBUS:
14589a0bf528SMauro Carvalho Chehab 			dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
14599a0bf528SMauro Carvalho Chehab 			dib8096p_enMpegMux(state, 0);
14609a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 6);
14619a0bf528SMauro Carvalho Chehab 			break;
14629a0bf528SMauro Carvalho Chehab 	case DIBTX_ON_HOSTBUS:
14639a0bf528SMauro Carvalho Chehab 			dprintk("SET DIBSTREAM TX ON HOST BUS");
14649a0bf528SMauro Carvalho Chehab 			dib8096p_enMpegMux(state, 0);
14659a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 5);
14669a0bf528SMauro Carvalho Chehab 			break;
14679a0bf528SMauro Carvalho Chehab 	case MPEG_ON_HOSTBUS:
14689a0bf528SMauro Carvalho Chehab 			dprintk("SET MPEG MUX ON HOST BUS");
14699a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 4);
14709a0bf528SMauro Carvalho Chehab 			break;
14719a0bf528SMauro Carvalho Chehab 	default:
14729a0bf528SMauro Carvalho Chehab 			break;
14739a0bf528SMauro Carvalho Chehab 	}
14749a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1288, reg_1288);
14759a0bf528SMauro Carvalho Chehab }
14769a0bf528SMauro Carvalho Chehab 
14779a0bf528SMauro Carvalho Chehab static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
14789a0bf528SMauro Carvalho Chehab {
14799a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
14809a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
14819a0bf528SMauro Carvalho Chehab 
14829a0bf528SMauro Carvalho Chehab 	switch (onoff) {
14839a0bf528SMauro Carvalho Chehab 	case 0: /* only use the internal way - not the diversity input */
14849a0bf528SMauro Carvalho Chehab 			dprintk("%s mode OFF : by default Enable Mpeg INPUT",
14859a0bf528SMauro Carvalho Chehab 					__func__);
14869a0bf528SMauro Carvalho Chehab 			/* outputRate = 8 */
14879a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
14889a0bf528SMauro Carvalho Chehab 
14899a0bf528SMauro Carvalho Chehab 			/* Do not divide the serial clock of MPEG MUX in
14909a0bf528SMauro Carvalho Chehab 			   SERIAL MODE in case input mode MPEG is used */
14919a0bf528SMauro Carvalho Chehab 			reg_1287 = dib8000_read_word(state, 1287);
14929a0bf528SMauro Carvalho Chehab 			/* enSerialClkDiv2 == 1 ? */
14939a0bf528SMauro Carvalho Chehab 			if ((reg_1287 & 0x1) == 1) {
14949a0bf528SMauro Carvalho Chehab 				/* force enSerialClkDiv2 = 0 */
14959a0bf528SMauro Carvalho Chehab 				reg_1287 &= ~0x1;
14969a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, 1287, reg_1287);
14979a0bf528SMauro Carvalho Chehab 			}
14989a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 1;
14999a0bf528SMauro Carvalho Chehab 			break;
15009a0bf528SMauro Carvalho Chehab 	case 1: /* both ways */
15019a0bf528SMauro Carvalho Chehab 	case 2: /* only the diversity input */
15029a0bf528SMauro Carvalho Chehab 			dprintk("%s ON : Enable diversity INPUT", __func__);
15039a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
15049a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 0;
15059a0bf528SMauro Carvalho Chehab 			break;
15069a0bf528SMauro Carvalho Chehab 	}
15079a0bf528SMauro Carvalho Chehab 
15089a0bf528SMauro Carvalho Chehab 	dib8000_set_diversity_in(state->fe[0], onoff);
15099a0bf528SMauro Carvalho Chehab 	return 0;
15109a0bf528SMauro Carvalho Chehab }
15119a0bf528SMauro Carvalho Chehab 
15129a0bf528SMauro Carvalho Chehab static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
15139a0bf528SMauro Carvalho Chehab {
15149a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
15159a0bf528SMauro Carvalho Chehab 	u16 outreg, smo_mode, fifo_threshold;
15169a0bf528SMauro Carvalho Chehab 	u8 prefer_mpeg_mux_use = 1;
15179a0bf528SMauro Carvalho Chehab 	int ret = 0;
15189a0bf528SMauro Carvalho Chehab 
1519173a64cbSPatrick Boettcher 	state->output_mode = mode;
15209a0bf528SMauro Carvalho Chehab 	dib8096p_host_bus_drive(state, 1);
15219a0bf528SMauro Carvalho Chehab 
15229a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
15239a0bf528SMauro Carvalho Chehab 	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
15249a0bf528SMauro Carvalho Chehab 	outreg   = dib8000_read_word(state, 1286) &
15259a0bf528SMauro Carvalho Chehab 		~((1 << 10) | (0x7 << 6) | (1 << 1));
15269a0bf528SMauro Carvalho Chehab 
15279a0bf528SMauro Carvalho Chehab 	switch (mode) {
15289a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:
15299a0bf528SMauro Carvalho Chehab 			outreg = 0;
15309a0bf528SMauro Carvalho Chehab 			break;
15319a0bf528SMauro Carvalho Chehab 
15329a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:
15339a0bf528SMauro Carvalho Chehab 			if (prefer_mpeg_mux_use) {
15349a0bf528SMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux");
15359a0bf528SMauro Carvalho Chehab 				dib8096p_configMpegMux(state, 3, 1, 1);
15369a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
15379a0bf528SMauro Carvalho Chehab 			} else {/* Use Smooth block */
15389a0bf528SMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc");
15399a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state,
15409a0bf528SMauro Carvalho Chehab 						DEMOUT_ON_HOSTBUS);
15419a0bf528SMauro Carvalho Chehab 				outreg |= (2 << 6) | (0 << 1);
15429a0bf528SMauro Carvalho Chehab 			}
15439a0bf528SMauro Carvalho Chehab 			break;
15449a0bf528SMauro Carvalho Chehab 
15459a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:
15469a0bf528SMauro Carvalho Chehab 			if (prefer_mpeg_mux_use) {
15479a0bf528SMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
15489a0bf528SMauro Carvalho Chehab 				dib8096p_configMpegMux(state, 2, 0, 0);
15499a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
15509a0bf528SMauro Carvalho Chehab 			} else { /* Use Smooth block */
15519a0bf528SMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block");
15529a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state,
15539a0bf528SMauro Carvalho Chehab 						DEMOUT_ON_HOSTBUS);
15549a0bf528SMauro Carvalho Chehab 				outreg |= (0 << 6);
15559a0bf528SMauro Carvalho Chehab 			}
15569a0bf528SMauro Carvalho Chehab 			break;
15579a0bf528SMauro Carvalho Chehab 
15589a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
15599a0bf528SMauro Carvalho Chehab 			dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block");
15609a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
15619a0bf528SMauro Carvalho Chehab 			outreg |= (1 << 6);
15629a0bf528SMauro Carvalho Chehab 			break;
15639a0bf528SMauro Carvalho Chehab 
15649a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:
15659a0bf528SMauro Carvalho Chehab 			/* Using Smooth block because not supported
15669a0bf528SMauro Carvalho Chehab 			   by new Mpeg Mux bloc */
15679a0bf528SMauro Carvalho Chehab 			dprintk("dib8096P setting output mode TS_FIFO using Smooth block");
15689a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
15699a0bf528SMauro Carvalho Chehab 			outreg |= (5 << 6);
15709a0bf528SMauro Carvalho Chehab 			smo_mode |= (3 << 1);
15719a0bf528SMauro Carvalho Chehab 			fifo_threshold = 512;
15729a0bf528SMauro Carvalho Chehab 			break;
15739a0bf528SMauro Carvalho Chehab 
15749a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
15759a0bf528SMauro Carvalho Chehab 			dprintk("dib8096P setting output mode MODE_DIVERSITY");
15769a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
15779a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
15789a0bf528SMauro Carvalho Chehab 			break;
15799a0bf528SMauro Carvalho Chehab 
15809a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
15819a0bf528SMauro Carvalho Chehab 			dprintk("dib8096P setting output mode MODE_ANALOG_ADC");
15829a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
15839a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
15849a0bf528SMauro Carvalho Chehab 			break;
15859a0bf528SMauro Carvalho Chehab 	}
15869a0bf528SMauro Carvalho Chehab 
15879a0bf528SMauro Carvalho Chehab 	if (mode != OUTMODE_HIGH_Z)
15889a0bf528SMauro Carvalho Chehab 		outreg |= (1<<10);
15899a0bf528SMauro Carvalho Chehab 
15909a0bf528SMauro Carvalho Chehab 	dprintk("output_mpeg2_in_188_bytes = %d",
15919a0bf528SMauro Carvalho Chehab 			state->cfg.output_mpeg2_in_188_bytes);
15929a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
15939a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
15949a0bf528SMauro Carvalho Chehab 
15959a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 299, smo_mode);
15969a0bf528SMauro Carvalho Chehab 	/* synchronous fread */
15979a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
15989a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 1286, outreg);
15999a0bf528SMauro Carvalho Chehab 
16009a0bf528SMauro Carvalho Chehab 	return ret;
16019a0bf528SMauro Carvalho Chehab }
16029a0bf528SMauro Carvalho Chehab 
16039a0bf528SMauro Carvalho Chehab static int map_addr_to_serpar_number(struct i2c_msg *msg)
16049a0bf528SMauro Carvalho Chehab {
16059a0bf528SMauro Carvalho Chehab 	if (msg->buf[0] <= 15)
16069a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 1;
16079a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 17)
16089a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 15;
16099a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 16)
16109a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 17;
16119a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 19)
16129a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 16;
16139a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
16149a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 3;
16159a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 28)
16169a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 23;
16179a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 99)
16189a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 99;
16199a0bf528SMauro Carvalho Chehab 	else
16209a0bf528SMauro Carvalho Chehab 		return -EINVAL;
16219a0bf528SMauro Carvalho Chehab 	return 0;
16229a0bf528SMauro Carvalho Chehab }
16239a0bf528SMauro Carvalho Chehab 
16249a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
16259a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
16269a0bf528SMauro Carvalho Chehab {
16279a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
16289a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1;
16299a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
16309a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
16319a0bf528SMauro Carvalho Chehab 
16329a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
16339a0bf528SMauro Carvalho Chehab 		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
16349a0bf528SMauro Carvalho Chehab 		i--;
16359a0bf528SMauro Carvalho Chehab 		if (i == 0)
16369a0bf528SMauro Carvalho Chehab 			dprintk("Tuner ITF: write busy (overflow)");
16379a0bf528SMauro Carvalho Chehab 	}
16389a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
16399a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
16409a0bf528SMauro Carvalho Chehab 
16419a0bf528SMauro Carvalho Chehab 	return num;
16429a0bf528SMauro Carvalho Chehab }
16439a0bf528SMauro Carvalho Chehab 
16449a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
16459a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
16469a0bf528SMauro Carvalho Chehab {
16479a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
16489a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1, n_empty = 1;
16499a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
16509a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
16519a0bf528SMauro Carvalho Chehab 	u16 read_word;
16529a0bf528SMauro Carvalho Chehab 
16539a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
16549a0bf528SMauro Carvalho Chehab 		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
16559a0bf528SMauro Carvalho Chehab 		i--;
16569a0bf528SMauro Carvalho Chehab 		if (i == 0)
16579a0bf528SMauro Carvalho Chehab 			dprintk("TunerITF: read busy (overflow)");
16589a0bf528SMauro Carvalho Chehab 	}
16599a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
16609a0bf528SMauro Carvalho Chehab 
16619a0bf528SMauro Carvalho Chehab 	i = 1000;
16629a0bf528SMauro Carvalho Chehab 	while (n_empty == 1 && i) {
16639a0bf528SMauro Carvalho Chehab 		n_empty = dib8000_read_word(state, 1984)&0x1;
16649a0bf528SMauro Carvalho Chehab 		i--;
16659a0bf528SMauro Carvalho Chehab 		if (i == 0)
16669a0bf528SMauro Carvalho Chehab 			dprintk("TunerITF: read busy (empty)");
16679a0bf528SMauro Carvalho Chehab 	}
16689a0bf528SMauro Carvalho Chehab 
16699a0bf528SMauro Carvalho Chehab 	read_word = dib8000_read_word(state, 1987);
16709a0bf528SMauro Carvalho Chehab 	msg[1].buf[0] = (read_word >> 8) & 0xff;
16719a0bf528SMauro Carvalho Chehab 	msg[1].buf[1] = (read_word) & 0xff;
16729a0bf528SMauro Carvalho Chehab 
16739a0bf528SMauro Carvalho Chehab 	return num;
16749a0bf528SMauro Carvalho Chehab }
16759a0bf528SMauro Carvalho Chehab 
16769a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
16779a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
16789a0bf528SMauro Carvalho Chehab {
16799a0bf528SMauro Carvalho Chehab 	if (map_addr_to_serpar_number(&msg[0]) == 0) {
16809a0bf528SMauro Carvalho Chehab 		if (num == 1) /* write */
16819a0bf528SMauro Carvalho Chehab 			return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
16829a0bf528SMauro Carvalho Chehab 		else /* read */
16839a0bf528SMauro Carvalho Chehab 			return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
16849a0bf528SMauro Carvalho Chehab 	}
16859a0bf528SMauro Carvalho Chehab 	return num;
16869a0bf528SMauro Carvalho Chehab }
16879a0bf528SMauro Carvalho Chehab 
16889a0bf528SMauro Carvalho Chehab static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
16899a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num, u16 apb_address)
16909a0bf528SMauro Carvalho Chehab {
16919a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
16929a0bf528SMauro Carvalho Chehab 	u16 word;
16939a0bf528SMauro Carvalho Chehab 
16949a0bf528SMauro Carvalho Chehab 	if (num == 1) {		/* write */
16959a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, apb_address,
16969a0bf528SMauro Carvalho Chehab 				((msg[0].buf[1] << 8) | (msg[0].buf[2])));
16979a0bf528SMauro Carvalho Chehab 	} else {
16989a0bf528SMauro Carvalho Chehab 		word = dib8000_read_word(state, apb_address);
16999a0bf528SMauro Carvalho Chehab 		msg[1].buf[0] = (word >> 8) & 0xff;
17009a0bf528SMauro Carvalho Chehab 		msg[1].buf[1] = (word) & 0xff;
17019a0bf528SMauro Carvalho Chehab 	}
17029a0bf528SMauro Carvalho Chehab 	return num;
17039a0bf528SMauro Carvalho Chehab }
17049a0bf528SMauro Carvalho Chehab 
17059a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
17069a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
17079a0bf528SMauro Carvalho Chehab {
17089a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
17099a0bf528SMauro Carvalho Chehab 	u16 apb_address = 0, word;
17109a0bf528SMauro Carvalho Chehab 	int i = 0;
17119a0bf528SMauro Carvalho Chehab 
17129a0bf528SMauro Carvalho Chehab 	switch (msg[0].buf[0]) {
17139a0bf528SMauro Carvalho Chehab 	case 0x12:
17149a0bf528SMauro Carvalho Chehab 			apb_address = 1920;
17159a0bf528SMauro Carvalho Chehab 			break;
17169a0bf528SMauro Carvalho Chehab 	case 0x14:
17179a0bf528SMauro Carvalho Chehab 			apb_address = 1921;
17189a0bf528SMauro Carvalho Chehab 			break;
17199a0bf528SMauro Carvalho Chehab 	case 0x24:
17209a0bf528SMauro Carvalho Chehab 			apb_address = 1922;
17219a0bf528SMauro Carvalho Chehab 			break;
17229a0bf528SMauro Carvalho Chehab 	case 0x1a:
17239a0bf528SMauro Carvalho Chehab 			apb_address = 1923;
17249a0bf528SMauro Carvalho Chehab 			break;
17259a0bf528SMauro Carvalho Chehab 	case 0x22:
17269a0bf528SMauro Carvalho Chehab 			apb_address = 1924;
17279a0bf528SMauro Carvalho Chehab 			break;
17289a0bf528SMauro Carvalho Chehab 	case 0x33:
17299a0bf528SMauro Carvalho Chehab 			apb_address = 1926;
17309a0bf528SMauro Carvalho Chehab 			break;
17319a0bf528SMauro Carvalho Chehab 	case 0x34:
17329a0bf528SMauro Carvalho Chehab 			apb_address = 1927;
17339a0bf528SMauro Carvalho Chehab 			break;
17349a0bf528SMauro Carvalho Chehab 	case 0x35:
17359a0bf528SMauro Carvalho Chehab 			apb_address = 1928;
17369a0bf528SMauro Carvalho Chehab 			break;
17379a0bf528SMauro Carvalho Chehab 	case 0x36:
17389a0bf528SMauro Carvalho Chehab 			apb_address = 1929;
17399a0bf528SMauro Carvalho Chehab 			break;
17409a0bf528SMauro Carvalho Chehab 	case 0x37:
17419a0bf528SMauro Carvalho Chehab 			apb_address = 1930;
17429a0bf528SMauro Carvalho Chehab 			break;
17439a0bf528SMauro Carvalho Chehab 	case 0x38:
17449a0bf528SMauro Carvalho Chehab 			apb_address = 1931;
17459a0bf528SMauro Carvalho Chehab 			break;
17469a0bf528SMauro Carvalho Chehab 	case 0x39:
17479a0bf528SMauro Carvalho Chehab 			apb_address = 1932;
17489a0bf528SMauro Carvalho Chehab 			break;
17499a0bf528SMauro Carvalho Chehab 	case 0x2a:
17509a0bf528SMauro Carvalho Chehab 			apb_address = 1935;
17519a0bf528SMauro Carvalho Chehab 			break;
17529a0bf528SMauro Carvalho Chehab 	case 0x2b:
17539a0bf528SMauro Carvalho Chehab 			apb_address = 1936;
17549a0bf528SMauro Carvalho Chehab 			break;
17559a0bf528SMauro Carvalho Chehab 	case 0x2c:
17569a0bf528SMauro Carvalho Chehab 			apb_address = 1937;
17579a0bf528SMauro Carvalho Chehab 			break;
17589a0bf528SMauro Carvalho Chehab 	case 0x2d:
17599a0bf528SMauro Carvalho Chehab 			apb_address = 1938;
17609a0bf528SMauro Carvalho Chehab 			break;
17619a0bf528SMauro Carvalho Chehab 	case 0x2e:
17629a0bf528SMauro Carvalho Chehab 			apb_address = 1939;
17639a0bf528SMauro Carvalho Chehab 			break;
17649a0bf528SMauro Carvalho Chehab 	case 0x2f:
17659a0bf528SMauro Carvalho Chehab 			apb_address = 1940;
17669a0bf528SMauro Carvalho Chehab 			break;
17679a0bf528SMauro Carvalho Chehab 	case 0x30:
17689a0bf528SMauro Carvalho Chehab 			apb_address = 1941;
17699a0bf528SMauro Carvalho Chehab 			break;
17709a0bf528SMauro Carvalho Chehab 	case 0x31:
17719a0bf528SMauro Carvalho Chehab 			apb_address = 1942;
17729a0bf528SMauro Carvalho Chehab 			break;
17739a0bf528SMauro Carvalho Chehab 	case 0x32:
17749a0bf528SMauro Carvalho Chehab 			apb_address = 1943;
17759a0bf528SMauro Carvalho Chehab 			break;
17769a0bf528SMauro Carvalho Chehab 	case 0x3e:
17779a0bf528SMauro Carvalho Chehab 			apb_address = 1944;
17789a0bf528SMauro Carvalho Chehab 			break;
17799a0bf528SMauro Carvalho Chehab 	case 0x3f:
17809a0bf528SMauro Carvalho Chehab 			apb_address = 1945;
17819a0bf528SMauro Carvalho Chehab 			break;
17829a0bf528SMauro Carvalho Chehab 	case 0x40:
17839a0bf528SMauro Carvalho Chehab 			apb_address = 1948;
17849a0bf528SMauro Carvalho Chehab 			break;
17859a0bf528SMauro Carvalho Chehab 	case 0x25:
17869a0bf528SMauro Carvalho Chehab 			apb_address = 936;
17879a0bf528SMauro Carvalho Chehab 			break;
17889a0bf528SMauro Carvalho Chehab 	case 0x26:
17899a0bf528SMauro Carvalho Chehab 			apb_address = 937;
17909a0bf528SMauro Carvalho Chehab 			break;
17919a0bf528SMauro Carvalho Chehab 	case 0x27:
17929a0bf528SMauro Carvalho Chehab 			apb_address = 938;
17939a0bf528SMauro Carvalho Chehab 			break;
17949a0bf528SMauro Carvalho Chehab 	case 0x28:
17959a0bf528SMauro Carvalho Chehab 			apb_address = 939;
17969a0bf528SMauro Carvalho Chehab 			break;
17979a0bf528SMauro Carvalho Chehab 	case 0x1d:
17989a0bf528SMauro Carvalho Chehab 			/* get sad sel request */
17999a0bf528SMauro Carvalho Chehab 			i = ((dib8000_read_word(state, 921) >> 12)&0x3);
18009a0bf528SMauro Carvalho Chehab 			word = dib8000_read_word(state, 924+i);
18019a0bf528SMauro Carvalho Chehab 			msg[1].buf[0] = (word >> 8) & 0xff;
18029a0bf528SMauro Carvalho Chehab 			msg[1].buf[1] = (word) & 0xff;
18039a0bf528SMauro Carvalho Chehab 			return num;
18049a0bf528SMauro Carvalho Chehab 	case 0x1f:
18059a0bf528SMauro Carvalho Chehab 			if (num == 1) {	/* write */
18069a0bf528SMauro Carvalho Chehab 				word = (u16) ((msg[0].buf[1] << 8) |
18079a0bf528SMauro Carvalho Chehab 						msg[0].buf[2]);
18089a0bf528SMauro Carvalho Chehab 				/* in the VGAMODE Sel are located on bit 0/1 */
18099a0bf528SMauro Carvalho Chehab 				word &= 0x3;
18109a0bf528SMauro Carvalho Chehab 				word = (dib8000_read_word(state, 921) &
18119a0bf528SMauro Carvalho Chehab 						~(3<<12)) | (word<<12);
18129a0bf528SMauro Carvalho Chehab 				/* Set the proper input */
18139a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, 921, word);
18149a0bf528SMauro Carvalho Chehab 				return num;
18159a0bf528SMauro Carvalho Chehab 			}
18169a0bf528SMauro Carvalho Chehab 	}
18179a0bf528SMauro Carvalho Chehab 
18189a0bf528SMauro Carvalho Chehab 	if (apb_address != 0) /* R/W acces via APB */
18199a0bf528SMauro Carvalho Chehab 		return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
18209a0bf528SMauro Carvalho Chehab 	else  /* R/W access via SERPAR  */
18219a0bf528SMauro Carvalho Chehab 		return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
18229a0bf528SMauro Carvalho Chehab 
18239a0bf528SMauro Carvalho Chehab 	return 0;
18249a0bf528SMauro Carvalho Chehab }
18259a0bf528SMauro Carvalho Chehab 
18269a0bf528SMauro Carvalho Chehab static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
18279a0bf528SMauro Carvalho Chehab {
18289a0bf528SMauro Carvalho Chehab 	return I2C_FUNC_I2C;
18299a0bf528SMauro Carvalho Chehab }
18309a0bf528SMauro Carvalho Chehab 
18319a0bf528SMauro Carvalho Chehab static struct i2c_algorithm dib8096p_tuner_xfer_algo = {
18329a0bf528SMauro Carvalho Chehab 	.master_xfer = dib8096p_tuner_xfer,
18339a0bf528SMauro Carvalho Chehab 	.functionality = dib8096p_i2c_func,
18349a0bf528SMauro Carvalho Chehab };
18359a0bf528SMauro Carvalho Chehab 
18369a0bf528SMauro Carvalho Chehab struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
18379a0bf528SMauro Carvalho Chehab {
18389a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
18399a0bf528SMauro Carvalho Chehab 	return &st->dib8096p_tuner_adap;
18409a0bf528SMauro Carvalho Chehab }
18419a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8096p_get_i2c_tuner);
18429a0bf528SMauro Carvalho Chehab 
18439a0bf528SMauro Carvalho Chehab int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
18449a0bf528SMauro Carvalho Chehab {
18459a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
18469a0bf528SMauro Carvalho Chehab 	u16 en_cur_state;
18479a0bf528SMauro Carvalho Chehab 
18489a0bf528SMauro Carvalho Chehab 	dprintk("sleep dib8096p: %d", onoff);
18499a0bf528SMauro Carvalho Chehab 
18509a0bf528SMauro Carvalho Chehab 	en_cur_state = dib8000_read_word(state, 1922);
18519a0bf528SMauro Carvalho Chehab 
18529a0bf528SMauro Carvalho Chehab 	/* LNAs and MIX are ON and therefore it is a valid configuration */
18539a0bf528SMauro Carvalho Chehab 	if (en_cur_state > 0xff)
18549a0bf528SMauro Carvalho Chehab 		state->tuner_enable = en_cur_state ;
18559a0bf528SMauro Carvalho Chehab 
18569a0bf528SMauro Carvalho Chehab 	if (onoff)
18579a0bf528SMauro Carvalho Chehab 		en_cur_state &= 0x00ff;
18589a0bf528SMauro Carvalho Chehab 	else {
18599a0bf528SMauro Carvalho Chehab 		if (state->tuner_enable != 0)
18609a0bf528SMauro Carvalho Chehab 			en_cur_state = state->tuner_enable;
18619a0bf528SMauro Carvalho Chehab 	}
18629a0bf528SMauro Carvalho Chehab 
18639a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1922, en_cur_state);
18649a0bf528SMauro Carvalho Chehab 
18659a0bf528SMauro Carvalho Chehab 	return 0;
18669a0bf528SMauro Carvalho Chehab }
18679a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8096p_tuner_sleep);
18689a0bf528SMauro Carvalho Chehab 
18699a0bf528SMauro Carvalho Chehab static const s32 lut_1000ln_mant[] =
18709a0bf528SMauro Carvalho Chehab {
18719a0bf528SMauro Carvalho Chehab 	908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
18729a0bf528SMauro Carvalho Chehab };
18739a0bf528SMauro Carvalho Chehab 
18749a0bf528SMauro Carvalho Chehab s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
18759a0bf528SMauro Carvalho Chehab {
18769a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
18779a0bf528SMauro Carvalho Chehab 	u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
18789a0bf528SMauro Carvalho Chehab 	s32 val;
18799a0bf528SMauro Carvalho Chehab 
18809a0bf528SMauro Carvalho Chehab 	val = dib8000_read32(state, 384);
18819a0bf528SMauro Carvalho Chehab 	if (mode) {
18829a0bf528SMauro Carvalho Chehab 		tmp_val = val;
18839a0bf528SMauro Carvalho Chehab 		while (tmp_val >>= 1)
18849a0bf528SMauro Carvalho Chehab 			exp++;
18859a0bf528SMauro Carvalho Chehab 		mant = (val * 1000 / (1<<exp));
18869a0bf528SMauro Carvalho Chehab 		ix = (u8)((mant-1000)/100); /* index of the LUT */
18879a0bf528SMauro Carvalho Chehab 		val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
18889a0bf528SMauro Carvalho Chehab 		val = (val*256)/1000;
18899a0bf528SMauro Carvalho Chehab 	}
18909a0bf528SMauro Carvalho Chehab 	return val;
18919a0bf528SMauro Carvalho Chehab }
18929a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_get_adc_power);
18939a0bf528SMauro Carvalho Chehab 
18949a0bf528SMauro Carvalho Chehab int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
18959a0bf528SMauro Carvalho Chehab {
18969a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
18979a0bf528SMauro Carvalho Chehab 	int val = 0;
18989a0bf528SMauro Carvalho Chehab 
18999a0bf528SMauro Carvalho Chehab 	switch (IQ) {
19009a0bf528SMauro Carvalho Chehab 	case 1:
19019a0bf528SMauro Carvalho Chehab 			val = dib8000_read_word(state, 403);
19029a0bf528SMauro Carvalho Chehab 			break;
19039a0bf528SMauro Carvalho Chehab 	case 0:
19049a0bf528SMauro Carvalho Chehab 			val = dib8000_read_word(state, 404);
19059a0bf528SMauro Carvalho Chehab 			break;
19069a0bf528SMauro Carvalho Chehab 	}
19079a0bf528SMauro Carvalho Chehab 	if (val  & 0x200)
19089a0bf528SMauro Carvalho Chehab 		val -= 1024;
19099a0bf528SMauro Carvalho Chehab 
19109a0bf528SMauro Carvalho Chehab 	return val;
19119a0bf528SMauro Carvalho Chehab }
19129a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8090p_get_dc_power);
19139a0bf528SMauro Carvalho Chehab 
19149a0bf528SMauro Carvalho Chehab static void dib8000_update_timf(struct dib8000_state *state)
19159a0bf528SMauro Carvalho Chehab {
19169a0bf528SMauro Carvalho Chehab 	u32 timf = state->timf = dib8000_read32(state, 435);
19179a0bf528SMauro Carvalho Chehab 
19189a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 29, (u16) (timf >> 16));
19199a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 30, (u16) (timf & 0xffff));
19209a0bf528SMauro Carvalho Chehab 	dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
19219a0bf528SMauro Carvalho Chehab }
19229a0bf528SMauro Carvalho Chehab 
19239a0bf528SMauro Carvalho Chehab u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
19249a0bf528SMauro Carvalho Chehab {
19259a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
19269a0bf528SMauro Carvalho Chehab 
19279a0bf528SMauro Carvalho Chehab 	switch (op) {
19289a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_SET:
19299a0bf528SMauro Carvalho Chehab 			state->timf = timf;
19309a0bf528SMauro Carvalho Chehab 			break;
19319a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_UPDATE:
19329a0bf528SMauro Carvalho Chehab 			dib8000_update_timf(state);
19339a0bf528SMauro Carvalho Chehab 			break;
19349a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_GET:
19359a0bf528SMauro Carvalho Chehab 			break;
19369a0bf528SMauro Carvalho Chehab 	}
19379a0bf528SMauro Carvalho Chehab 	dib8000_set_bandwidth(state->fe[0], 6000);
19389a0bf528SMauro Carvalho Chehab 
19399a0bf528SMauro Carvalho Chehab 	return state->timf;
19409a0bf528SMauro Carvalho Chehab }
19419a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_ctrl_timf);
19429a0bf528SMauro Carvalho Chehab 
19439a0bf528SMauro Carvalho Chehab static const u16 adc_target_16dB[11] = {
19449a0bf528SMauro Carvalho Chehab 	(1 << 13) - 825 - 117,
19459a0bf528SMauro Carvalho Chehab 	(1 << 13) - 837 - 117,
19469a0bf528SMauro Carvalho Chehab 	(1 << 13) - 811 - 117,
19479a0bf528SMauro Carvalho Chehab 	(1 << 13) - 766 - 117,
19489a0bf528SMauro Carvalho Chehab 	(1 << 13) - 737 - 117,
19499a0bf528SMauro Carvalho Chehab 	(1 << 13) - 693 - 117,
19509a0bf528SMauro Carvalho Chehab 	(1 << 13) - 648 - 117,
19519a0bf528SMauro Carvalho Chehab 	(1 << 13) - 619 - 117,
19529a0bf528SMauro Carvalho Chehab 	(1 << 13) - 575 - 117,
19539a0bf528SMauro Carvalho Chehab 	(1 << 13) - 531 - 117,
19549a0bf528SMauro Carvalho Chehab 	(1 << 13) - 501 - 117
19559a0bf528SMauro Carvalho Chehab };
19569a0bf528SMauro Carvalho Chehab static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
19579a0bf528SMauro Carvalho Chehab 
1958173a64cbSPatrick Boettcher static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
19599a0bf528SMauro Carvalho Chehab {
1960173a64cbSPatrick Boettcher 	u8  cr, constellation, time_intlv;
1961c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
19629a0bf528SMauro Carvalho Chehab 
1963c82056d0SMauro Carvalho Chehab 	switch (c->layer[layer_index].modulation) {
19649a0bf528SMauro Carvalho Chehab 	case DQPSK:
19659a0bf528SMauro Carvalho Chehab 			constellation = 0;
19669a0bf528SMauro Carvalho Chehab 			break;
19679a0bf528SMauro Carvalho Chehab 	case  QPSK:
19689a0bf528SMauro Carvalho Chehab 			constellation = 1;
19699a0bf528SMauro Carvalho Chehab 			break;
19709a0bf528SMauro Carvalho Chehab 	case QAM_16:
19719a0bf528SMauro Carvalho Chehab 			constellation = 2;
19729a0bf528SMauro Carvalho Chehab 			break;
19739a0bf528SMauro Carvalho Chehab 	case QAM_64:
19749a0bf528SMauro Carvalho Chehab 	default:
19759a0bf528SMauro Carvalho Chehab 			constellation = 3;
19769a0bf528SMauro Carvalho Chehab 			break;
19779a0bf528SMauro Carvalho Chehab 	}
19789a0bf528SMauro Carvalho Chehab 
1979c82056d0SMauro Carvalho Chehab 	switch (c->layer[layer_index].fec) {
19809a0bf528SMauro Carvalho Chehab 	case FEC_1_2:
1981173a64cbSPatrick Boettcher 			cr = 1;
19829a0bf528SMauro Carvalho Chehab 			break;
19839a0bf528SMauro Carvalho Chehab 	case FEC_2_3:
1984173a64cbSPatrick Boettcher 			cr = 2;
19859a0bf528SMauro Carvalho Chehab 			break;
19869a0bf528SMauro Carvalho Chehab 	case FEC_3_4:
1987173a64cbSPatrick Boettcher 			cr = 3;
19889a0bf528SMauro Carvalho Chehab 			break;
19899a0bf528SMauro Carvalho Chehab 	case FEC_5_6:
1990173a64cbSPatrick Boettcher 			cr = 5;
19919a0bf528SMauro Carvalho Chehab 			break;
19929a0bf528SMauro Carvalho Chehab 	case FEC_7_8:
19939a0bf528SMauro Carvalho Chehab 	default:
1994173a64cbSPatrick Boettcher 			cr = 7;
19959a0bf528SMauro Carvalho Chehab 			break;
19969a0bf528SMauro Carvalho Chehab 	}
19979a0bf528SMauro Carvalho Chehab 
1998c82056d0SMauro Carvalho Chehab 	if ((c->layer[layer_index].interleaving > 0) && ((c->layer[layer_index].interleaving <= 3) || (c->layer[layer_index].interleaving == 4 && c->isdbt_sb_mode == 1)))
1999c82056d0SMauro Carvalho Chehab 		time_intlv = c->layer[layer_index].interleaving;
20009a0bf528SMauro Carvalho Chehab 	else
2001173a64cbSPatrick Boettcher 		time_intlv = 0;
2002173a64cbSPatrick Boettcher 
2003c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
2004c82056d0SMauro Carvalho Chehab 	if (c->layer[layer_index].segment_count > 0) {
20059a0bf528SMauro Carvalho Chehab 		switch (max_constellation) {
20069a0bf528SMauro Carvalho Chehab 		case DQPSK:
20079a0bf528SMauro Carvalho Chehab 		case QPSK:
2008c82056d0SMauro Carvalho Chehab 				if (c->layer[layer_index].modulation == QAM_16 || c->layer[layer_index].modulation == QAM_64)
2009c82056d0SMauro Carvalho Chehab 					max_constellation = c->layer[layer_index].modulation;
20109a0bf528SMauro Carvalho Chehab 				break;
20119a0bf528SMauro Carvalho Chehab 		case QAM_16:
2012c82056d0SMauro Carvalho Chehab 				if (c->layer[layer_index].modulation == QAM_64)
2013c82056d0SMauro Carvalho Chehab 					max_constellation = c->layer[layer_index].modulation;
20149a0bf528SMauro Carvalho Chehab 				break;
20159a0bf528SMauro Carvalho Chehab 		}
20169a0bf528SMauro Carvalho Chehab 	}
2017173a64cbSPatrick Boettcher 
2018173a64cbSPatrick Boettcher 	return  max_constellation;
20199a0bf528SMauro Carvalho Chehab }
20209a0bf528SMauro Carvalho Chehab 
2021173a64cbSPatrick Boettcher 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 */
2022173a64cbSPatrick Boettcher 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 */
2023173a64cbSPatrick Boettcher 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 */
2024173a64cbSPatrick Boettcher static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation)
2025173a64cbSPatrick Boettcher {
2026173a64cbSPatrick Boettcher 	u16 i, ana_gain = 0;
2027173a64cbSPatrick Boettcher 	const u16 *adp;
20289a0bf528SMauro Carvalho Chehab 
2029173a64cbSPatrick Boettcher 	/* channel estimation fine configuration */
2030173a64cbSPatrick Boettcher 	switch (max_constellation) {
2031173a64cbSPatrick Boettcher 	case QAM_64:
2032173a64cbSPatrick Boettcher 			ana_gain = 0x7;
2033173a64cbSPatrick Boettcher 			adp = &adp_Q64[0];
2034173a64cbSPatrick Boettcher 			break;
2035173a64cbSPatrick Boettcher 	case QAM_16:
2036173a64cbSPatrick Boettcher 			ana_gain = 0x7;
2037173a64cbSPatrick Boettcher 			adp = &adp_Q16[0];
2038173a64cbSPatrick Boettcher 			break;
2039173a64cbSPatrick Boettcher 	default:
2040173a64cbSPatrick Boettcher 			ana_gain = 0;
2041173a64cbSPatrick Boettcher 			adp = &adp_Qdefault[0];
2042173a64cbSPatrick Boettcher 			break;
20439a0bf528SMauro Carvalho Chehab 	}
20449a0bf528SMauro Carvalho Chehab 
2045173a64cbSPatrick Boettcher 	for (i = 0; i < 4; i++)
2046173a64cbSPatrick Boettcher 		dib8000_write_word(state, 215 + i, adp[i]);
20479a0bf528SMauro Carvalho Chehab 
2048173a64cbSPatrick Boettcher 	return ana_gain;
2049173a64cbSPatrick Boettcher }
20509a0bf528SMauro Carvalho Chehab 
2051173a64cbSPatrick Boettcher static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain)
2052173a64cbSPatrick Boettcher {
2053173a64cbSPatrick Boettcher 	u16 i;
20549a0bf528SMauro Carvalho Chehab 
2055173a64cbSPatrick Boettcher 	dib8000_write_word(state, 116, ana_gain);
20569a0bf528SMauro Carvalho Chehab 
2057173a64cbSPatrick Boettcher 	/* update ADC target depending on ana_gain */
2058173a64cbSPatrick Boettcher 	if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */
2059173a64cbSPatrick Boettcher 		for (i = 0; i < 10; i++)
2060173a64cbSPatrick Boettcher 			dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
2061173a64cbSPatrick Boettcher 	} else { /* set -22dB ADC target for ana_gain=0 */
2062173a64cbSPatrick Boettcher 		for (i = 0; i < 10; i++)
2063173a64cbSPatrick Boettcher 			dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
2064173a64cbSPatrick Boettcher 	}
2065173a64cbSPatrick Boettcher }
20669a0bf528SMauro Carvalho Chehab 
2067173a64cbSPatrick Boettcher static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
2068173a64cbSPatrick Boettcher {
2069173a64cbSPatrick Boettcher 	u16 mode = 0;
20709a0bf528SMauro Carvalho Chehab 
2071173a64cbSPatrick Boettcher 	if (state->isdbt_cfg_loaded == 0)
2072173a64cbSPatrick Boettcher 		for (mode = 0; mode < 24; mode++)
2073173a64cbSPatrick Boettcher 			dib8000_write_word(state, 117 + mode, ana_fe[mode]);
2074173a64cbSPatrick Boettcher }
20759a0bf528SMauro Carvalho Chehab 
2076173a64cbSPatrick Boettcher static const u16 lut_prbs_2k[14] = {
2077173a64cbSPatrick Boettcher 	0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213
2078173a64cbSPatrick Boettcher };
2079173a64cbSPatrick Boettcher static const u16 lut_prbs_4k[14] = {
2080173a64cbSPatrick Boettcher 	0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E
2081173a64cbSPatrick Boettcher };
2082173a64cbSPatrick Boettcher static const u16 lut_prbs_8k[14] = {
2083173a64cbSPatrick Boettcher 	0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684
2084173a64cbSPatrick Boettcher };
2085173a64cbSPatrick Boettcher 
2086173a64cbSPatrick Boettcher static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
2087173a64cbSPatrick Boettcher {
2088173a64cbSPatrick Boettcher 	int sub_channel_prbs_group = 0;
2089173a64cbSPatrick Boettcher 
2090173a64cbSPatrick Boettcher 	sub_channel_prbs_group = (subchannel / 3) + 1;
2091173a64cbSPatrick Boettcher 	dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]);
2092173a64cbSPatrick Boettcher 
20939a0bf528SMauro Carvalho Chehab 	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
20949a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
2095173a64cbSPatrick Boettcher 			return lut_prbs_2k[sub_channel_prbs_group];
20969a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
2097173a64cbSPatrick Boettcher 			return lut_prbs_4k[sub_channel_prbs_group];
20989a0bf528SMauro Carvalho Chehab 	default:
2099173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2100173a64cbSPatrick Boettcher 			return lut_prbs_8k[sub_channel_prbs_group];
21019a0bf528SMauro Carvalho Chehab 	}
21029a0bf528SMauro Carvalho Chehab }
21039a0bf528SMauro Carvalho Chehab 
2104173a64cbSPatrick Boettcher static void dib8000_set_13seg_channel(struct dib8000_state *state)
2105173a64cbSPatrick Boettcher {
2106173a64cbSPatrick Boettcher 	u16 i;
2107173a64cbSPatrick Boettcher 	u16 coff_pow = 0x2800;
21089a0bf528SMauro Carvalho Chehab 
2109173a64cbSPatrick Boettcher 	state->seg_mask = 0x1fff; /* All 13 segments enabled */
21109a0bf528SMauro Carvalho Chehab 
2111173a64cbSPatrick Boettcher 	/* ---- COFF ---- Carloff, the most robust --- */
2112173a64cbSPatrick Boettcher 	if (state->isdbt_cfg_loaded == 0) {  /* if not Sound Broadcasting mode : put default values for 13 segments */
21139a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 180, (16 << 6) | 9);
21149a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
21159a0bf528SMauro Carvalho Chehab 		coff_pow = 0x2800;
21169a0bf528SMauro Carvalho Chehab 		for (i = 0; i < 6; i++)
21179a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 181+i, coff_pow);
21189a0bf528SMauro Carvalho Chehab 
2119173a64cbSPatrick Boettcher 		/* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */
2120173a64cbSPatrick Boettcher 		/* 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 */
21219a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
21229a0bf528SMauro Carvalho Chehab 
2123173a64cbSPatrick Boettcher 		/* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */
21249a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
2125173a64cbSPatrick Boettcher 		/* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */
21269a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
21279a0bf528SMauro Carvalho Chehab 
2128173a64cbSPatrick Boettcher 		dib8000_write_word(state, 228, 0);  /* default value */
2129173a64cbSPatrick Boettcher 		dib8000_write_word(state, 265, 31); /* default value */
2130173a64cbSPatrick Boettcher 		dib8000_write_word(state, 205, 0x200f); /* init value */
2131173a64cbSPatrick Boettcher 	}
2132173a64cbSPatrick Boettcher 
2133173a64cbSPatrick Boettcher 	/*
2134173a64cbSPatrick Boettcher 	 * make the cpil_coff_lock more robust but slower p_coff_winlen
21359a0bf528SMauro Carvalho Chehab 	 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
21369a0bf528SMauro Carvalho Chehab 	 */
21379a0bf528SMauro Carvalho Chehab 
2138173a64cbSPatrick Boettcher 	if (state->cfg.pll->ifreq == 0)
2139173a64cbSPatrick Boettcher 		dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
21409a0bf528SMauro Carvalho Chehab 
2141173a64cbSPatrick Boettcher 	dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg);
2142173a64cbSPatrick Boettcher }
21439a0bf528SMauro Carvalho Chehab 
2144173a64cbSPatrick Boettcher static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs)
2145173a64cbSPatrick Boettcher {
2146173a64cbSPatrick Boettcher 	u16 reg_1;
21479a0bf528SMauro Carvalho Chehab 
2148173a64cbSPatrick Boettcher 	reg_1 = dib8000_read_word(state, 1);
2149173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */
2150173a64cbSPatrick Boettcher }
21519a0bf528SMauro Carvalho Chehab 
2152173a64cbSPatrick Boettcher static void dib8000_small_fine_tune(struct dib8000_state *state)
2153173a64cbSPatrick Boettcher {
2154173a64cbSPatrick Boettcher 	u16 i;
2155173a64cbSPatrick Boettcher 	const s16 *ncoeff;
2156c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
21579a0bf528SMauro Carvalho Chehab 
2158173a64cbSPatrick Boettcher 	dib8000_write_word(state, 352, state->seg_diff_mask);
2159173a64cbSPatrick Boettcher 	dib8000_write_word(state, 353, state->seg_mask);
21609a0bf528SMauro Carvalho Chehab 
2161173a64cbSPatrick Boettcher 	/* P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 */
2162c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 351, (c->isdbt_sb_mode << 9) | (c->isdbt_sb_mode << 8) | (13 << 4) | 5);
2163173a64cbSPatrick Boettcher 
2164c82056d0SMauro Carvalho Chehab 	if (c->isdbt_sb_mode) {
2165173a64cbSPatrick Boettcher 		/* ---- SMALL ---- */
2166c82056d0SMauro Carvalho Chehab 		switch (c->transmission_mode) {
2167173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_2K:
2168c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2169c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2170173a64cbSPatrick Boettcher 						ncoeff = coeff_2k_sb_1seg_dqpsk;
2171173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2172173a64cbSPatrick Boettcher 						ncoeff = coeff_2k_sb_1seg;
2173173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2174c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2175c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2176173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
2177173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2178173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg_0dqpsk;
2179173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2180c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2181173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg_1dqpsk;
2182173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2183173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg;
2184173a64cbSPatrick Boettcher 					}
2185173a64cbSPatrick Boettcher 				}
21869a0bf528SMauro Carvalho Chehab 				break;
21879a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_4K:
2188c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2189c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2190173a64cbSPatrick Boettcher 						ncoeff = coeff_4k_sb_1seg_dqpsk;
2191173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2192173a64cbSPatrick Boettcher 						ncoeff = coeff_4k_sb_1seg;
2193173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2194c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2195c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2196173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
2197173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2198173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_0dqpsk;
2199173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2200c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2201173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_1dqpsk;
2202173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2203173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg;
2204173a64cbSPatrick Boettcher 					}
2205173a64cbSPatrick Boettcher 				}
22069a0bf528SMauro Carvalho Chehab 				break;
2207173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_AUTO:
2208173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_8K:
22099a0bf528SMauro Carvalho Chehab 		default:
2210c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2211c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2212173a64cbSPatrick Boettcher 						ncoeff = coeff_8k_sb_1seg_dqpsk;
2213173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2214173a64cbSPatrick Boettcher 						ncoeff = coeff_8k_sb_1seg;
2215173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2216c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2217c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2218173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
2219173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2220173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_0dqpsk;
2221173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2222c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2223173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_1dqpsk;
2224173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2225173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg;
2226173a64cbSPatrick Boettcher 					}
2227173a64cbSPatrick Boettcher 				}
22289a0bf528SMauro Carvalho Chehab 				break;
22299a0bf528SMauro Carvalho Chehab 		}
2230173a64cbSPatrick Boettcher 
2231173a64cbSPatrick Boettcher 		for (i = 0; i < 8; i++)
2232173a64cbSPatrick Boettcher 			dib8000_write_word(state, 343 + i, ncoeff[i]);
2233173a64cbSPatrick Boettcher 	}
2234173a64cbSPatrick Boettcher }
2235173a64cbSPatrick Boettcher 
2236173a64cbSPatrick Boettcher static const u16 coff_thres_1seg[3] = {300, 150, 80};
2237173a64cbSPatrick Boettcher static const u16 coff_thres_3seg[3] = {350, 300, 250};
2238173a64cbSPatrick Boettcher static void dib8000_set_sb_channel(struct dib8000_state *state)
2239173a64cbSPatrick Boettcher {
2240c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2241173a64cbSPatrick Boettcher 	const u16 *coff;
2242173a64cbSPatrick Boettcher 	u16 i;
2243173a64cbSPatrick Boettcher 
2244c82056d0SMauro Carvalho Chehab 	if (c->transmission_mode == TRANSMISSION_MODE_2K || c->transmission_mode == TRANSMISSION_MODE_4K) {
2245173a64cbSPatrick Boettcher 		dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */
2246173a64cbSPatrick Boettcher 		dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */
2247173a64cbSPatrick Boettcher 	} else {
2248173a64cbSPatrick Boettcher 		dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */
2249173a64cbSPatrick Boettcher 		dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */
2250173a64cbSPatrick Boettcher 	}
2251173a64cbSPatrick Boettcher 
2252c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 1) /* 3-segments */
2253173a64cbSPatrick Boettcher 		state->seg_mask = 0x00E0;
2254173a64cbSPatrick Boettcher 	else /* 1-segment */
2255173a64cbSPatrick Boettcher 		state->seg_mask = 0x0040;
2256173a64cbSPatrick Boettcher 
2257173a64cbSPatrick Boettcher 	dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2258173a64cbSPatrick Boettcher 
2259173a64cbSPatrick Boettcher 	/* ---- COFF ---- Carloff, the most robust --- */
2260173a64cbSPatrick Boettcher 	/* 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 */
2261c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 187, (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~c->isdbt_partial_reception & 1) << 2) | 0x3);
2262173a64cbSPatrick Boettcher 
2263173a64cbSPatrick Boettcher 	dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */
2264173a64cbSPatrick Boettcher 	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 */
2265173a64cbSPatrick Boettcher 
2266173a64cbSPatrick Boettcher 	/* Sound Broadcasting mode 1 seg */
2267c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 0) {
2268173a64cbSPatrick Boettcher 		/* 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) */
2269173a64cbSPatrick Boettcher 		if (state->mode == 3)
2270173a64cbSPatrick Boettcher 			dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14));
22719a0bf528SMauro Carvalho Chehab 		else
2272173a64cbSPatrick Boettcher 			dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14));
2273173a64cbSPatrick Boettcher 
2274173a64cbSPatrick Boettcher 		/* 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 */
2275173a64cbSPatrick Boettcher 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
2276173a64cbSPatrick Boettcher 		coff = &coff_thres_1seg[0];
2277173a64cbSPatrick Boettcher 	} else {   /* Sound Broadcasting mode 3 seg */
2278173a64cbSPatrick Boettcher 		dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
2279173a64cbSPatrick Boettcher 		/* 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 */
2280173a64cbSPatrick Boettcher 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
2281173a64cbSPatrick Boettcher 		coff = &coff_thres_3seg[0];
2282173a64cbSPatrick Boettcher 	}
2283173a64cbSPatrick Boettcher 
2284173a64cbSPatrick Boettcher 	dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */
2285173a64cbSPatrick Boettcher 	dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */
2286173a64cbSPatrick Boettcher 
2287c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 0 && c->transmission_mode == TRANSMISSION_MODE_2K)
2288173a64cbSPatrick Boettcher 		dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */
2289173a64cbSPatrick Boettcher 
2290173a64cbSPatrick Boettcher 	/* Write COFF thres */
2291173a64cbSPatrick Boettcher 	for (i = 0 ; i < 3; i++) {
2292173a64cbSPatrick Boettcher 		dib8000_write_word(state, 181+i, coff[i]);
2293173a64cbSPatrick Boettcher 		dib8000_write_word(state, 184+i, coff[i]);
2294173a64cbSPatrick Boettcher 	}
2295173a64cbSPatrick Boettcher 
2296173a64cbSPatrick Boettcher 	/*
2297173a64cbSPatrick Boettcher 	 * make the cpil_coff_lock more robust but slower p_coff_winlen
2298173a64cbSPatrick Boettcher 	 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2299173a64cbSPatrick Boettcher 	 */
2300173a64cbSPatrick Boettcher 
2301173a64cbSPatrick Boettcher 	dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */
2302173a64cbSPatrick Boettcher 
2303c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 0)
2304173a64cbSPatrick Boettcher 		dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */
2305173a64cbSPatrick Boettcher 	else
2306173a64cbSPatrick Boettcher 		dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2307173a64cbSPatrick Boettcher }
2308173a64cbSPatrick Boettcher 
2309173a64cbSPatrick Boettcher static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
2310173a64cbSPatrick Boettcher {
2311173a64cbSPatrick Boettcher 	u16 p_cfr_left_edge  = 0, p_cfr_right_edge = 0;
2312173a64cbSPatrick Boettcher 	u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ;
2313173a64cbSPatrick Boettcher 	u16 max_constellation = DQPSK;
2314173a64cbSPatrick Boettcher 	int init_prbs;
2315c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2316173a64cbSPatrick Boettcher 
2317173a64cbSPatrick Boettcher 	/* P_mode */
2318173a64cbSPatrick Boettcher 	dib8000_write_word(state, 10, (seq << 4));
2319173a64cbSPatrick Boettcher 
2320173a64cbSPatrick Boettcher 	/* init mode */
2321173a64cbSPatrick Boettcher 	state->mode = fft_to_mode(state);
2322173a64cbSPatrick Boettcher 
2323173a64cbSPatrick Boettcher 	/* set guard */
2324173a64cbSPatrick Boettcher 	tmp = dib8000_read_word(state, 1);
2325c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3));
2326173a64cbSPatrick Boettcher 
2327c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) | ((c->isdbt_partial_reception & 1) << 5) | ((c->isdbt_sb_mode & 1) << 4));
2328173a64cbSPatrick Boettcher 
2329173a64cbSPatrick Boettcher 	/* signal optimization parameter */
2330c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception) {
2331c82056d0SMauro Carvalho Chehab 		state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0];
2332173a64cbSPatrick Boettcher 		for (i = 1; i < 3; i++)
2333c82056d0SMauro Carvalho Chehab 			nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
2334173a64cbSPatrick Boettcher 		for (i = 0; i < nbseg_diff; i++)
2335173a64cbSPatrick Boettcher 			state->seg_diff_mask |= 1 << permu_seg[i+1];
2336173a64cbSPatrick Boettcher 	} else {
2337173a64cbSPatrick Boettcher 		for (i = 0; i < 3; i++)
2338c82056d0SMauro Carvalho Chehab 			nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
2339173a64cbSPatrick Boettcher 		for (i = 0; i < nbseg_diff; i++)
2340173a64cbSPatrick Boettcher 			state->seg_diff_mask |= 1 << permu_seg[i];
2341173a64cbSPatrick Boettcher 	}
2342173a64cbSPatrick Boettcher 
2343173a64cbSPatrick Boettcher 	if (state->seg_diff_mask)
2344173a64cbSPatrick Boettcher 		dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2345173a64cbSPatrick Boettcher 	else
2346173a64cbSPatrick Boettcher 		dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */
2347173a64cbSPatrick Boettcher 
2348173a64cbSPatrick Boettcher 	for (i = 0; i < 3; i++)
2349173a64cbSPatrick Boettcher 		max_constellation = dib8000_set_layer(state, i, max_constellation);
2350173a64cbSPatrick Boettcher 	if (autosearching == 0) {
2351c82056d0SMauro Carvalho Chehab 		state->layer_b_nb_seg = c->layer[1].segment_count;
2352c82056d0SMauro Carvalho Chehab 		state->layer_c_nb_seg = c->layer[2].segment_count;
2353173a64cbSPatrick Boettcher 	}
2354173a64cbSPatrick Boettcher 
2355173a64cbSPatrick Boettcher 	/* WRITE: Mode & Diff mask */
2356173a64cbSPatrick Boettcher 	dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask);
2357173a64cbSPatrick Boettcher 
2358173a64cbSPatrick Boettcher 	state->differential_constellation = (state->seg_diff_mask != 0);
23599a0bf528SMauro Carvalho Chehab 
23609a0bf528SMauro Carvalho Chehab 	/* channel estimation fine configuration */
2361173a64cbSPatrick Boettcher 	ana_gain = dib8000_adp_fine_tune(state, max_constellation);
23629a0bf528SMauro Carvalho Chehab 
2363173a64cbSPatrick Boettcher 	/* update ana_gain depending on max constellation */
2364173a64cbSPatrick Boettcher 	dib8000_update_ana_gain(state, ana_gain);
23659a0bf528SMauro Carvalho Chehab 
2366173a64cbSPatrick Boettcher 	/* ---- ANA_FE ---- */
2367c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception) /* 3-segments */
2368173a64cbSPatrick Boettcher 		dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg);
2369173a64cbSPatrick Boettcher 	else
2370173a64cbSPatrick Boettcher 		dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */
2371173a64cbSPatrick Boettcher 
2372173a64cbSPatrick Boettcher 	/* TSB or ISDBT ? apply it now */
2373c82056d0SMauro Carvalho Chehab 	if (c->isdbt_sb_mode) {
2374173a64cbSPatrick Boettcher 		dib8000_set_sb_channel(state);
2375746f7ae0SMauro Carvalho Chehab 		if (c->isdbt_sb_subchannel < 14)
2376c82056d0SMauro Carvalho Chehab 			init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel);
2377173a64cbSPatrick Boettcher 		else
2378173a64cbSPatrick Boettcher 			init_prbs = 0;
2379173a64cbSPatrick Boettcher 	} else {
2380173a64cbSPatrick Boettcher 		dib8000_set_13seg_channel(state);
2381173a64cbSPatrick Boettcher 		init_prbs = 0xfff;
2382173a64cbSPatrick Boettcher 	}
23839a0bf528SMauro Carvalho Chehab 
2384173a64cbSPatrick Boettcher 	/* SMALL */
2385173a64cbSPatrick Boettcher 	dib8000_small_fine_tune(state);
23869a0bf528SMauro Carvalho Chehab 
2387173a64cbSPatrick Boettcher 	dib8000_set_subchannel_prbs(state, init_prbs);
2388173a64cbSPatrick Boettcher 
2389173a64cbSPatrick Boettcher 	/* ---- CHAN_BLK ---- */
23909a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 13; i++) {
2391173a64cbSPatrick Boettcher 		if ((((~state->seg_diff_mask) >> i) & 1) == 1) {
2392173a64cbSPatrick Boettcher 			p_cfr_left_edge  += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0));
2393173a64cbSPatrick Boettcher 			p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0));
23949a0bf528SMauro Carvalho Chehab 		}
23959a0bf528SMauro Carvalho Chehab 	}
2396173a64cbSPatrick Boettcher 	dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */
2397173a64cbSPatrick Boettcher 	dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */
2398173a64cbSPatrick Boettcher 	/* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */
23999a0bf528SMauro Carvalho Chehab 
2400173a64cbSPatrick Boettcher 	dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */
2401173a64cbSPatrick Boettcher 	dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */
2402173a64cbSPatrick Boettcher 	dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */
2403173a64cbSPatrick Boettcher 
2404173a64cbSPatrick Boettcher 	if (!autosearching)
2405173a64cbSPatrick Boettcher 		dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
2406173a64cbSPatrick Boettcher 	else
2407173a64cbSPatrick Boettcher 		dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */
2408173a64cbSPatrick Boettcher 
2409173a64cbSPatrick Boettcher 	dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */
2410173a64cbSPatrick Boettcher 	dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */
2411173a64cbSPatrick Boettcher 
2412173a64cbSPatrick Boettcher 	dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2413173a64cbSPatrick Boettcher 
2414173a64cbSPatrick Boettcher 	/* ---- TMCC ---- */
24159a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 3; i++)
2416c82056d0SMauro Carvalho Chehab 		tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ;
2417173a64cbSPatrick Boettcher 
2418173a64cbSPatrick Boettcher 	/* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */
2419173a64cbSPatrick Boettcher 	/* Threshold is set at 1/4 of max power. */
24209a0bf528SMauro Carvalho Chehab 	tmcc_pow *= (1 << (9-2));
2421173a64cbSPatrick Boettcher 	dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */
2422173a64cbSPatrick Boettcher 	dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */
2423173a64cbSPatrick Boettcher 	dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */
2424173a64cbSPatrick Boettcher 	/*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */
24259a0bf528SMauro Carvalho Chehab 
2426173a64cbSPatrick Boettcher 	/* ---- PHA3 ---- */
24279a0bf528SMauro Carvalho Chehab 	if (state->isdbt_cfg_loaded == 0)
24289a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */
24299a0bf528SMauro Carvalho Chehab 
24309a0bf528SMauro Carvalho Chehab 	state->isdbt_cfg_loaded = 0;
2431173a64cbSPatrick Boettcher }
24329a0bf528SMauro Carvalho Chehab 
24336f7ee06fSMauro Carvalho Chehab static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal,
24346f7ee06fSMauro Carvalho Chehab 			     u32 wait0_ms, u32 wait1_ms, u32 wait2_ms)
2435173a64cbSPatrick Boettcher {
243613122f98SMauro Carvalho Chehab 	u32 value = 0;	/* P_search_end0 wait time */
2437173a64cbSPatrick Boettcher 	u16 reg = 11;	/* P_search_end0 start addr */
2438173a64cbSPatrick Boettcher 
2439173a64cbSPatrick Boettcher 	for (reg = 11; reg < 16; reg += 2) {
2440173a64cbSPatrick Boettcher 		if (reg == 11) {
2441173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
244213122f98SMauro Carvalho Chehab 				value = internal * wait1_ms;
2443173a64cbSPatrick Boettcher 			else
244413122f98SMauro Carvalho Chehab 				value = internal * wait0_ms;
2445173a64cbSPatrick Boettcher 		} else if (reg == 13)
244613122f98SMauro Carvalho Chehab 			value = internal * wait1_ms;
2447173a64cbSPatrick Boettcher 		else if (reg == 15)
244813122f98SMauro Carvalho Chehab 			value = internal * wait2_ms;
2449173a64cbSPatrick Boettcher 		dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff));
2450173a64cbSPatrick Boettcher 		dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff));
2451173a64cbSPatrick Boettcher 	}
2452173a64cbSPatrick Boettcher 	return value;
24539a0bf528SMauro Carvalho Chehab }
24549a0bf528SMauro Carvalho Chehab 
24559a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_start(struct dvb_frontend *fe)
24569a0bf528SMauro Carvalho Chehab {
24579a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
2458c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2459173a64cbSPatrick Boettcher 	u8 slist = 0;
2460173a64cbSPatrick Boettcher 	u32 value, internal = state->cfg.pll->internal;
24619a0bf528SMauro Carvalho Chehab 
2462173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
2463173a64cbSPatrick Boettcher 		internal = dib8000_read32(state, 23) / 1000;
24649a0bf528SMauro Carvalho Chehab 
2465d67350f8SOlivier Grenie 	if ((state->revision >= 0x8002) &&
2466d67350f8SOlivier Grenie 	    (state->autosearch_state == AS_SEARCHING_FFT)) {
2467173a64cbSPatrick Boettcher 		dib8000_write_word(state,  37, 0x0065); /* P_ctrl_pha_off_max default values */
2468173a64cbSPatrick Boettcher 		dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
2469173a64cbSPatrick Boettcher 
2470173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */
2471173a64cbSPatrick Boettcher 		dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */
2472173a64cbSPatrick Boettcher 		dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */
2473173a64cbSPatrick Boettcher 		dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */
2474173a64cbSPatrick Boettcher 		dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */
2475173a64cbSPatrick Boettcher 		dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */
2476173a64cbSPatrick Boettcher 
2477173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2478173a64cbSPatrick Boettcher 			value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2479173a64cbSPatrick Boettcher 		else
2480173a64cbSPatrick Boettcher 			value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2481173a64cbSPatrick Boettcher 
2482173a64cbSPatrick Boettcher 		dib8000_write_word(state, 17, 0);
2483173a64cbSPatrick Boettcher 		dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */
2484173a64cbSPatrick Boettcher 		dib8000_write_word(state, 19, 0);
2485173a64cbSPatrick Boettcher 		dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */
2486173a64cbSPatrick Boettcher 		dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */
2487173a64cbSPatrick Boettcher 		dib8000_write_word(state, 22, value & 0xffff);
2488173a64cbSPatrick Boettcher 
2489173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2490173a64cbSPatrick Boettcher 			dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */
2491173a64cbSPatrick Boettcher 		else
2492173a64cbSPatrick Boettcher 			dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */
2493173a64cbSPatrick Boettcher 		dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */
2494173a64cbSPatrick Boettcher 
2495173a64cbSPatrick Boettcher 		/* P_search_param_select = (1 | 1<<4 | 1 << 8) */
2496173a64cbSPatrick Boettcher 		dib8000_write_word(state, 356, 0);
2497173a64cbSPatrick Boettcher 		dib8000_write_word(state, 357, 0x111);
2498173a64cbSPatrick Boettcher 
2499173a64cbSPatrick Boettcher 		dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
2500173a64cbSPatrick Boettcher 		dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
2501173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */
2502d67350f8SOlivier Grenie 	} else if ((state->revision >= 0x8002) &&
2503d67350f8SOlivier Grenie 		   (state->autosearch_state == AS_SEARCHING_GUARD)) {
2504c82056d0SMauro Carvalho Chehab 		c->transmission_mode = TRANSMISSION_MODE_8K;
2505c82056d0SMauro Carvalho Chehab 		c->guard_interval = GUARD_INTERVAL_1_8;
2506c82056d0SMauro Carvalho Chehab 		c->inversion = 0;
2507c82056d0SMauro Carvalho Chehab 		c->layer[0].modulation = QAM_64;
2508c82056d0SMauro Carvalho Chehab 		c->layer[0].fec = FEC_2_3;
2509c82056d0SMauro Carvalho Chehab 		c->layer[0].interleaving = 0;
2510c82056d0SMauro Carvalho Chehab 		c->layer[0].segment_count = 13;
25119a0bf528SMauro Carvalho Chehab 
2512173a64cbSPatrick Boettcher 		slist = 16;
2513c82056d0SMauro Carvalho Chehab 		c->transmission_mode = state->found_nfft;
2514173a64cbSPatrick Boettcher 
2515173a64cbSPatrick Boettcher 		dib8000_set_isdbt_common_channel(state, slist, 1);
2516173a64cbSPatrick Boettcher 
2517173a64cbSPatrick Boettcher 		/* set lock_mask values */
2518173a64cbSPatrick Boettcher 		dib8000_write_word(state, 6, 0x4);
2519173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2520173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */
2521173a64cbSPatrick Boettcher 		else
2522173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, 0x8);
2523173a64cbSPatrick Boettcher 		dib8000_write_word(state, 8, 0x1000);
2524173a64cbSPatrick Boettcher 
2525173a64cbSPatrick Boettcher 		/* set lock_mask wait time values */
2526173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2527173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2528173a64cbSPatrick Boettcher 		else
2529173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2530173a64cbSPatrick Boettcher 
2531173a64cbSPatrick Boettcher 		dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */
2532173a64cbSPatrick Boettcher 
2533173a64cbSPatrick Boettcher 		/* P_search_param_select = 0xf; look for the 4 different guard intervals */
2534173a64cbSPatrick Boettcher 		dib8000_write_word(state, 356, 0);
2535173a64cbSPatrick Boettcher 		dib8000_write_word(state, 357, 0xf);
2536173a64cbSPatrick Boettcher 
2537173a64cbSPatrick Boettcher 		value = dib8000_read_word(state, 0);
2538173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2539173a64cbSPatrick Boettcher 		dib8000_read_word(state, 1284);  /* reset the INT. n_irq_pending */
2540173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (u16)value);
2541173a64cbSPatrick Boettcher 	} else {
2542c82056d0SMauro Carvalho Chehab 		c->inversion = 0;
2543c82056d0SMauro Carvalho Chehab 		c->layer[0].modulation = QAM_64;
2544c82056d0SMauro Carvalho Chehab 		c->layer[0].fec = FEC_2_3;
2545c82056d0SMauro Carvalho Chehab 		c->layer[0].interleaving = 0;
2546c82056d0SMauro Carvalho Chehab 		c->layer[0].segment_count = 13;
2547c82056d0SMauro Carvalho Chehab 		if (!c->isdbt_sb_mode)
2548c82056d0SMauro Carvalho Chehab 			c->layer[0].segment_count = 13;
2549173a64cbSPatrick Boettcher 
2550173a64cbSPatrick Boettcher 		/* choose the right list, in sb, always do everything */
2551c82056d0SMauro Carvalho Chehab 		if (c->isdbt_sb_mode) {
25529a0bf528SMauro Carvalho Chehab 			slist = 7;
25539a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
25549a0bf528SMauro Carvalho Chehab 		} else {
2555c82056d0SMauro Carvalho Chehab 			if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2556c82056d0SMauro Carvalho Chehab 				if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2557c82056d0SMauro Carvalho Chehab 					c->transmission_mode = TRANSMISSION_MODE_8K;
2558c82056d0SMauro Carvalho Chehab 					c->guard_interval = GUARD_INTERVAL_1_8;
25599a0bf528SMauro Carvalho Chehab 					slist = 7;
2560173a64cbSPatrick Boettcher 					dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));  /* P_mode = 1 to have autosearch start ok with mode2 */
2561173a64cbSPatrick Boettcher 				} else {
2562c82056d0SMauro Carvalho Chehab 					c->guard_interval = GUARD_INTERVAL_1_8;
25639a0bf528SMauro Carvalho Chehab 					slist = 3;
2564173a64cbSPatrick Boettcher 				}
25659a0bf528SMauro Carvalho Chehab 			} else {
2566c82056d0SMauro Carvalho Chehab 				if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2567c82056d0SMauro Carvalho Chehab 					c->transmission_mode = TRANSMISSION_MODE_8K;
25689a0bf528SMauro Carvalho Chehab 					slist = 2;
2569173a64cbSPatrick Boettcher 					dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));  /* P_mode = 1 */
25709a0bf528SMauro Carvalho Chehab 				} else
25719a0bf528SMauro Carvalho Chehab 					slist = 0;
25729a0bf528SMauro Carvalho Chehab 			}
2573173a64cbSPatrick Boettcher 		}
2574173a64cbSPatrick Boettcher 		dprintk("Using list for autosearch : %d", slist);
25759a0bf528SMauro Carvalho Chehab 
2576173a64cbSPatrick Boettcher 		dib8000_set_isdbt_common_channel(state, slist, 1);
25779a0bf528SMauro Carvalho Chehab 
2578173a64cbSPatrick Boettcher 		/* set lock_mask values */
25799a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 6, 0x4);
2580173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2581173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10));
2582173a64cbSPatrick Boettcher 		else
25839a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 7, 0x8);
25849a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 8, 0x1000);
25859a0bf528SMauro Carvalho Chehab 
2586173a64cbSPatrick Boettcher 		/* set lock_mask wait time values */
2587173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2588173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2589173a64cbSPatrick Boettcher 		else
2590173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
25919a0bf528SMauro Carvalho Chehab 
25929a0bf528SMauro Carvalho Chehab 		value = dib8000_read_word(state, 0);
25939a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2594173a64cbSPatrick Boettcher 		dib8000_read_word(state, 1284);  /* reset the INT. n_irq_pending */
25959a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 0, (u16)value);
25969a0bf528SMauro Carvalho Chehab 	}
25979a0bf528SMauro Carvalho Chehab 	return 0;
25989a0bf528SMauro Carvalho Chehab }
25999a0bf528SMauro Carvalho Chehab 
26009a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_irq(struct dvb_frontend *fe)
26019a0bf528SMauro Carvalho Chehab {
26029a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
26039a0bf528SMauro Carvalho Chehab 	u16 irq_pending = dib8000_read_word(state, 1284);
26049a0bf528SMauro Carvalho Chehab 
2605d67350f8SOlivier Grenie 	if ((state->revision >= 0x8002) &&
2606d67350f8SOlivier Grenie 	    (state->autosearch_state == AS_SEARCHING_FFT)) {
2607173a64cbSPatrick Boettcher 		if (irq_pending & 0x1) {
2608173a64cbSPatrick Boettcher 			dprintk("dib8000_autosearch_irq: max correlation result available");
2609173a64cbSPatrick Boettcher 			return 3;
2610173a64cbSPatrick Boettcher 		}
2611173a64cbSPatrick Boettcher 	} else {
2612173a64cbSPatrick Boettcher 		if (irq_pending & 0x1) {	/* failed */
26139a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_autosearch_irq failed");
26149a0bf528SMauro Carvalho Chehab 			return 1;
26159a0bf528SMauro Carvalho Chehab 		}
26169a0bf528SMauro Carvalho Chehab 
2617173a64cbSPatrick Boettcher 		if (irq_pending & 0x2) {	/* succeeded */
26189a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_autosearch_irq succeeded");
26199a0bf528SMauro Carvalho Chehab 			return 2;
26209a0bf528SMauro Carvalho Chehab 		}
2621173a64cbSPatrick Boettcher 	}
26229a0bf528SMauro Carvalho Chehab 
26239a0bf528SMauro Carvalho Chehab 	return 0;		// still pending
26249a0bf528SMauro Carvalho Chehab }
26259a0bf528SMauro Carvalho Chehab 
2626173a64cbSPatrick Boettcher static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
2627173a64cbSPatrick Boettcher {
2628173a64cbSPatrick Boettcher 	u16 tmp;
2629173a64cbSPatrick Boettcher 
2630173a64cbSPatrick Boettcher 	tmp = dib8000_read_word(state, 771);
2631173a64cbSPatrick Boettcher 	if (onoff) /* start P_restart_chd : channel_decoder */
2632173a64cbSPatrick Boettcher 		dib8000_write_word(state, 771, tmp & 0xfffd);
2633173a64cbSPatrick Boettcher 	else /* stop P_restart_chd : channel_decoder */
2634173a64cbSPatrick Boettcher 		dib8000_write_word(state, 771, tmp | (1<<1));
2635173a64cbSPatrick Boettcher }
2636173a64cbSPatrick Boettcher 
2637173a64cbSPatrick Boettcher static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
2638173a64cbSPatrick Boettcher {
2639173a64cbSPatrick Boettcher 	s16 unit_khz_dds_val;
2640173a64cbSPatrick Boettcher 	u32 abs_offset_khz = ABS(offset_khz);
2641173a64cbSPatrick Boettcher 	u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
2642173a64cbSPatrick Boettcher 	u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
2643173a64cbSPatrick Boettcher 	u8 ratio;
2644173a64cbSPatrick Boettcher 
2645173a64cbSPatrick Boettcher 	if (state->revision == 0x8090) {
2646173a64cbSPatrick Boettcher 		ratio = 4;
2647173a64cbSPatrick Boettcher 		unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000);
2648173a64cbSPatrick Boettcher 		if (offset_khz < 0)
2649173a64cbSPatrick Boettcher 			dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
2650173a64cbSPatrick Boettcher 		else
2651173a64cbSPatrick Boettcher 			dds = (abs_offset_khz * unit_khz_dds_val);
2652173a64cbSPatrick Boettcher 
2653173a64cbSPatrick Boettcher 		if (invert)
2654173a64cbSPatrick Boettcher 			dds = (1<<26) - dds;
2655173a64cbSPatrick Boettcher 	} else {
2656173a64cbSPatrick Boettcher 		ratio = 2;
2657173a64cbSPatrick Boettcher 		unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
2658173a64cbSPatrick Boettcher 
2659173a64cbSPatrick Boettcher 		if (offset_khz < 0)
2660173a64cbSPatrick Boettcher 			unit_khz_dds_val *= -1;
2661173a64cbSPatrick Boettcher 
2662173a64cbSPatrick Boettcher 		/* IF tuner */
2663173a64cbSPatrick Boettcher 		if (invert)
2664173a64cbSPatrick Boettcher 			dds -= abs_offset_khz * unit_khz_dds_val;
2665173a64cbSPatrick Boettcher 		else
2666173a64cbSPatrick Boettcher 			dds += abs_offset_khz * unit_khz_dds_val;
2667173a64cbSPatrick Boettcher 	}
2668173a64cbSPatrick Boettcher 
2669173a64cbSPatrick Boettcher 	dprintk("setting a DDS frequency offset of %c%dkHz", invert ? '-' : ' ', dds / unit_khz_dds_val);
2670173a64cbSPatrick Boettcher 
2671173a64cbSPatrick Boettcher 	if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) {
2672173a64cbSPatrick Boettcher 		/* Max dds offset is the half of the demod freq */
2673173a64cbSPatrick Boettcher 		dib8000_write_word(state, 26, invert);
2674173a64cbSPatrick Boettcher 		dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff);
2675173a64cbSPatrick Boettcher 		dib8000_write_word(state, 28, (u16)(dds & 0xffff));
2676173a64cbSPatrick Boettcher 	}
2677173a64cbSPatrick Boettcher }
2678173a64cbSPatrick Boettcher 
2679173a64cbSPatrick Boettcher static void dib8000_set_frequency_offset(struct dib8000_state *state)
2680173a64cbSPatrick Boettcher {
2681c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2682173a64cbSPatrick Boettcher 	int i;
2683173a64cbSPatrick Boettcher 	u32 current_rf;
2684173a64cbSPatrick Boettcher 	int total_dds_offset_khz;
2685173a64cbSPatrick Boettcher 
2686173a64cbSPatrick Boettcher 	if (state->fe[0]->ops.tuner_ops.get_frequency)
2687173a64cbSPatrick Boettcher 		state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], &current_rf);
2688173a64cbSPatrick Boettcher 	else
2689c82056d0SMauro Carvalho Chehab 		current_rf = c->frequency;
2690173a64cbSPatrick Boettcher 	current_rf /= 1000;
2691c82056d0SMauro Carvalho Chehab 	total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000;
2692173a64cbSPatrick Boettcher 
2693c82056d0SMauro Carvalho Chehab 	if (c->isdbt_sb_mode) {
2694c82056d0SMauro Carvalho Chehab 		state->subchannel = c->isdbt_sb_subchannel;
2695173a64cbSPatrick Boettcher 
2696173a64cbSPatrick Boettcher 		i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */
2697c82056d0SMauro Carvalho Chehab 		dib8000_write_word(state, 26, c->inversion ^ i);
2698173a64cbSPatrick Boettcher 
2699173a64cbSPatrick Boettcher 		if (state->cfg.pll->ifreq == 0) { /* low if tuner */
2700c82056d0SMauro Carvalho Chehab 			if ((c->inversion ^ i) == 0)
2701173a64cbSPatrick Boettcher 				dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
2702173a64cbSPatrick Boettcher 		} else {
2703c82056d0SMauro Carvalho Chehab 			if ((c->inversion ^ i) == 0)
2704173a64cbSPatrick Boettcher 				total_dds_offset_khz *= -1;
2705173a64cbSPatrick Boettcher 		}
2706173a64cbSPatrick Boettcher 	}
2707173a64cbSPatrick Boettcher 
2708c82056d0SMauro Carvalho Chehab 	dprintk("%dkhz tuner offset (frequency = %dHz & current_rf = %dHz) total_dds_offset_hz = %d", c->frequency - current_rf, c->frequency, current_rf, total_dds_offset_khz);
2709173a64cbSPatrick Boettcher 
2710173a64cbSPatrick Boettcher 	/* apply dds offset now */
2711173a64cbSPatrick Boettcher 	dib8000_set_dds(state, total_dds_offset_khz);
2712173a64cbSPatrick Boettcher }
2713173a64cbSPatrick Boettcher 
2714173a64cbSPatrick Boettcher static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 };
27156f7ee06fSMauro Carvalho Chehab 
27166f7ee06fSMauro Carvalho Chehab static u32 dib8000_get_symbol_duration(struct dib8000_state *state)
2717173a64cbSPatrick Boettcher {
2718c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2719173a64cbSPatrick Boettcher 	u16 i;
2720173a64cbSPatrick Boettcher 
2721c82056d0SMauro Carvalho Chehab 	switch (c->transmission_mode) {
2722173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_2K:
2723173a64cbSPatrick Boettcher 			i = 0;
2724173a64cbSPatrick Boettcher 			break;
2725173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_4K:
2726173a64cbSPatrick Boettcher 			i = 2;
2727173a64cbSPatrick Boettcher 			break;
2728173a64cbSPatrick Boettcher 	default:
2729173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_AUTO:
2730173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2731173a64cbSPatrick Boettcher 			i = 1;
2732173a64cbSPatrick Boettcher 			break;
2733173a64cbSPatrick Boettcher 	}
2734173a64cbSPatrick Boettcher 
2735c82056d0SMauro Carvalho Chehab 	return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1;
2736173a64cbSPatrick Boettcher }
2737173a64cbSPatrick Boettcher 
2738173a64cbSPatrick Boettcher static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step)
2739173a64cbSPatrick Boettcher {
2740c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2741173a64cbSPatrick Boettcher 	u16 reg_32 = 0, reg_37 = 0;
2742173a64cbSPatrick Boettcher 
2743173a64cbSPatrick Boettcher 	switch (loop_step) {
2744173a64cbSPatrick Boettcher 	case LOOP_TUNE_1:
2745c82056d0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode)  {
2746c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) {
2747173a64cbSPatrick Boettcher 					reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */
2748173a64cbSPatrick Boettcher 					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)  */
2749173a64cbSPatrick Boettcher 				} else { /* Sound Broadcasting mode 3 seg */
2750173a64cbSPatrick Boettcher 					reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */
2751173a64cbSPatrick Boettcher 					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)  */
2752173a64cbSPatrick Boettcher 				}
2753173a64cbSPatrick Boettcher 			} else { /* 13-seg start conf offset loop parameters */
2754173a64cbSPatrick Boettcher 				reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
2755173a64cbSPatrick Boettcher 				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  */
2756173a64cbSPatrick Boettcher 			}
2757173a64cbSPatrick Boettcher 			break;
2758173a64cbSPatrick Boettcher 	case LOOP_TUNE_2:
2759c82056d0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode)  {
2760c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) {  /* Sound Broadcasting mode 1 seg */
2761173a64cbSPatrick Boettcher 					reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/
2762173a64cbSPatrick Boettcher 					reg_37 = (12-state->mode) | ((5 + state->mode) << 5);
2763173a64cbSPatrick Boettcher 				} else {  /* Sound Broadcasting mode 3 seg */
2764173a64cbSPatrick Boettcher 					reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */
2765173a64cbSPatrick Boettcher 					reg_37 = (11-state->mode) | ((5 + state->mode) << 5);
2766173a64cbSPatrick Boettcher 				}
2767173a64cbSPatrick Boettcher 			} else {  /* 13 seg */
2768173a64cbSPatrick Boettcher 				reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */
2769173a64cbSPatrick Boettcher 				reg_37 = ((5+state->mode) << 5) | (10 - state->mode);
2770173a64cbSPatrick Boettcher 			}
2771173a64cbSPatrick Boettcher 			break;
2772173a64cbSPatrick Boettcher 	}
2773173a64cbSPatrick Boettcher 	dib8000_write_word(state, 32, reg_32);
2774173a64cbSPatrick Boettcher 	dib8000_write_word(state, 37, reg_37);
2775173a64cbSPatrick Boettcher }
2776173a64cbSPatrick Boettcher 
2777173a64cbSPatrick Boettcher static void dib8000_demod_restart(struct dib8000_state *state)
2778173a64cbSPatrick Boettcher {
2779173a64cbSPatrick Boettcher 	dib8000_write_word(state, 770, 0x4000);
2780173a64cbSPatrick Boettcher 	dib8000_write_word(state, 770, 0x0000);
2781173a64cbSPatrick Boettcher 	return;
2782173a64cbSPatrick Boettcher }
2783173a64cbSPatrick Boettcher 
2784173a64cbSPatrick Boettcher static void dib8000_set_sync_wait(struct dib8000_state *state)
2785173a64cbSPatrick Boettcher {
2786c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2787173a64cbSPatrick Boettcher 	u16 sync_wait = 64;
2788173a64cbSPatrick Boettcher 
2789173a64cbSPatrick Boettcher 	/* P_dvsy_sync_wait - reuse mode */
2790c82056d0SMauro Carvalho Chehab 	switch (c->transmission_mode) {
2791173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2792173a64cbSPatrick Boettcher 			sync_wait = 256;
2793173a64cbSPatrick Boettcher 			break;
2794173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_4K:
2795173a64cbSPatrick Boettcher 			sync_wait = 128;
2796173a64cbSPatrick Boettcher 			break;
2797173a64cbSPatrick Boettcher 	default:
2798173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_2K:
2799173a64cbSPatrick Boettcher 			sync_wait =  64;
2800173a64cbSPatrick Boettcher 			break;
2801173a64cbSPatrick Boettcher 	}
2802173a64cbSPatrick Boettcher 
2803173a64cbSPatrick Boettcher 	if (state->cfg.diversity_delay == 0)
2804c82056d0SMauro Carvalho Chehab 		sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */
2805173a64cbSPatrick Boettcher 	else
2806c82056d0SMauro Carvalho Chehab 		sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */
2807173a64cbSPatrick Boettcher 
2808173a64cbSPatrick Boettcher 	dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
2809173a64cbSPatrick Boettcher }
2810173a64cbSPatrick Boettcher 
2811173a64cbSPatrick Boettcher static u32 dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
2812173a64cbSPatrick Boettcher {
2813173a64cbSPatrick Boettcher 	if (mode == SYMBOL_DEPENDENT_ON)
2814173a64cbSPatrick Boettcher 		return systime() + (delay * state->symbol_duration);
2815173a64cbSPatrick Boettcher 	else
2816173a64cbSPatrick Boettcher 		return systime() + delay;
2817173a64cbSPatrick Boettcher }
2818173a64cbSPatrick Boettcher 
2819173a64cbSPatrick Boettcher static s32 dib8000_get_status(struct dvb_frontend *fe)
2820173a64cbSPatrick Boettcher {
2821173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2822173a64cbSPatrick Boettcher 	return state->status;
2823173a64cbSPatrick Boettcher }
2824173a64cbSPatrick Boettcher 
2825173a64cbSPatrick Boettcher enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
2826173a64cbSPatrick Boettcher {
2827173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2828173a64cbSPatrick Boettcher 	return state->tune_state;
2829173a64cbSPatrick Boettcher }
2830173a64cbSPatrick Boettcher EXPORT_SYMBOL(dib8000_get_tune_state);
2831173a64cbSPatrick Boettcher 
2832173a64cbSPatrick Boettcher int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2833173a64cbSPatrick Boettcher {
2834173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2835173a64cbSPatrick Boettcher 
2836173a64cbSPatrick Boettcher 	state->tune_state = tune_state;
2837173a64cbSPatrick Boettcher 	return 0;
2838173a64cbSPatrick Boettcher }
2839173a64cbSPatrick Boettcher EXPORT_SYMBOL(dib8000_set_tune_state);
2840173a64cbSPatrick Boettcher 
2841173a64cbSPatrick Boettcher static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
2842173a64cbSPatrick Boettcher {
2843173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2844173a64cbSPatrick Boettcher 
2845173a64cbSPatrick Boettcher 	state->status = FE_STATUS_TUNE_PENDING;
2846173a64cbSPatrick Boettcher 	state->tune_state = CT_DEMOD_START;
2847173a64cbSPatrick Boettcher 	return 0;
2848173a64cbSPatrick Boettcher }
2849173a64cbSPatrick Boettcher 
2850173a64cbSPatrick Boettcher static u16 dib8000_read_lock(struct dvb_frontend *fe)
2851173a64cbSPatrick Boettcher {
2852173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2853173a64cbSPatrick Boettcher 
2854173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
2855173a64cbSPatrick Boettcher 		return dib8000_read_word(state, 570);
2856173a64cbSPatrick Boettcher 	return dib8000_read_word(state, 568);
2857173a64cbSPatrick Boettcher }
2858173a64cbSPatrick Boettcher 
2859173a64cbSPatrick Boettcher static int dib8090p_init_sdram(struct dib8000_state *state)
2860173a64cbSPatrick Boettcher {
2861173a64cbSPatrick Boettcher 	u16 reg = 0;
2862173a64cbSPatrick Boettcher 	dprintk("init sdram");
2863173a64cbSPatrick Boettcher 
2864173a64cbSPatrick Boettcher 	reg = dib8000_read_word(state, 274) & 0xfff0;
2865173a64cbSPatrick Boettcher 	dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */
2866173a64cbSPatrick Boettcher 
2867173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1803, (7 << 2));
2868173a64cbSPatrick Boettcher 
2869173a64cbSPatrick Boettcher 	reg = dib8000_read_word(state, 1280);
2870173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1280,  reg | (1 << 2)); /* force restart P_restart_sdram */
2871173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1280,  reg); /* release restart P_restart_sdram */
2872173a64cbSPatrick Boettcher 
2873173a64cbSPatrick Boettcher 	return 0;
2874173a64cbSPatrick Boettcher }
2875173a64cbSPatrick Boettcher 
28769a0bf528SMauro Carvalho Chehab static int dib8000_tune(struct dvb_frontend *fe)
28779a0bf528SMauro Carvalho Chehab {
28789a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
2879c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2880173a64cbSPatrick Boettcher 	enum frontend_tune_state *tune_state = &state->tune_state;
28819a0bf528SMauro Carvalho Chehab 
2882173a64cbSPatrick Boettcher 	u16 locks, deeper_interleaver = 0, i;
2883173a64cbSPatrick Boettcher 	int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
28849a0bf528SMauro Carvalho Chehab 
2885173a64cbSPatrick Boettcher 	u32 *timeout = &state->timeout;
2886173a64cbSPatrick Boettcher 	u32 now = systime();
2887173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
2888173a64cbSPatrick Boettcher 	u16 agc1, agc2;
2889173a64cbSPatrick Boettcher #endif
28909a0bf528SMauro Carvalho Chehab 
2891173a64cbSPatrick Boettcher 	u32 corm[4] = {0, 0, 0, 0};
2892173a64cbSPatrick Boettcher 	u8 find_index, max_value;
28939a0bf528SMauro Carvalho Chehab 
2894173a64cbSPatrick Boettcher #if 0
2895173a64cbSPatrick Boettcher 	if (*tune_state < CT_DEMOD_STOP)
2896173a64cbSPatrick Boettcher 		dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u systime = %u", state->channel_parameters_set, *tune_state, state->autosearch_state, now);
2897173a64cbSPatrick Boettcher #endif
28989a0bf528SMauro Carvalho Chehab 
2899173a64cbSPatrick Boettcher 	switch (*tune_state) {
2900173a64cbSPatrick Boettcher 	case CT_DEMOD_START: /* 30 */
2901173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
2902173a64cbSPatrick Boettcher 				dib8090p_init_sdram(state);
2903173a64cbSPatrick Boettcher 			state->status = FE_STATUS_TUNE_PENDING;
2904c82056d0SMauro Carvalho Chehab 			if ((c->delivery_system != SYS_ISDBT) ||
2905c82056d0SMauro Carvalho Chehab 					(c->inversion == INVERSION_AUTO) ||
2906c82056d0SMauro Carvalho Chehab 					(c->transmission_mode == TRANSMISSION_MODE_AUTO) ||
2907c82056d0SMauro Carvalho Chehab 					(c->guard_interval == GUARD_INTERVAL_AUTO) ||
2908c82056d0SMauro Carvalho Chehab 					(((c->isdbt_layer_enabled & (1 << 0)) != 0) &&
2909c82056d0SMauro Carvalho Chehab 					 (c->layer[0].segment_count != 0xff) &&
2910c82056d0SMauro Carvalho Chehab 					 (c->layer[0].segment_count != 0) &&
2911c82056d0SMauro Carvalho Chehab 					 ((c->layer[0].modulation == QAM_AUTO) ||
2912c82056d0SMauro Carvalho Chehab 					  (c->layer[0].fec == FEC_AUTO))) ||
2913c82056d0SMauro Carvalho Chehab 					(((c->isdbt_layer_enabled & (1 << 1)) != 0) &&
2914c82056d0SMauro Carvalho Chehab 					 (c->layer[1].segment_count != 0xff) &&
2915c82056d0SMauro Carvalho Chehab 					 (c->layer[1].segment_count != 0) &&
2916c82056d0SMauro Carvalho Chehab 					 ((c->layer[1].modulation == QAM_AUTO) ||
2917c82056d0SMauro Carvalho Chehab 					  (c->layer[1].fec == FEC_AUTO))) ||
2918c82056d0SMauro Carvalho Chehab 					(((c->isdbt_layer_enabled & (1 << 2)) != 0) &&
2919c82056d0SMauro Carvalho Chehab 					 (c->layer[2].segment_count != 0xff) &&
2920c82056d0SMauro Carvalho Chehab 					 (c->layer[2].segment_count != 0) &&
2921c82056d0SMauro Carvalho Chehab 					 ((c->layer[2].modulation == QAM_AUTO) ||
2922c82056d0SMauro Carvalho Chehab 					  (c->layer[2].fec == FEC_AUTO))) ||
2923c82056d0SMauro Carvalho Chehab 					(((c->layer[0].segment_count == 0) ||
2924c82056d0SMauro Carvalho Chehab 					  ((c->isdbt_layer_enabled & (1 << 0)) == 0)) &&
2925c82056d0SMauro Carvalho Chehab 					 ((c->layer[1].segment_count == 0) ||
2926c82056d0SMauro Carvalho Chehab 					  ((c->isdbt_layer_enabled & (2 << 0)) == 0)) &&
2927c82056d0SMauro Carvalho Chehab 					 ((c->layer[2].segment_count == 0) || ((c->isdbt_layer_enabled & (3 << 0)) == 0))))
2928173a64cbSPatrick Boettcher 				state->channel_parameters_set = 0; /* auto search */
29299a0bf528SMauro Carvalho Chehab 			else
2930173a64cbSPatrick Boettcher 				state->channel_parameters_set = 1; /* channel parameters are known */
29319a0bf528SMauro Carvalho Chehab 
2932173a64cbSPatrick Boettcher 			dib8000_viterbi_state(state, 0); /* force chan dec in restart */
29339a0bf528SMauro Carvalho Chehab 
2934173a64cbSPatrick Boettcher 			/* Layer monit */
2935173a64cbSPatrick Boettcher 			dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
2936173a64cbSPatrick Boettcher 
2937173a64cbSPatrick Boettcher 			dib8000_set_frequency_offset(state);
2938c82056d0SMauro Carvalho Chehab 			dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
2939173a64cbSPatrick Boettcher 
2940173a64cbSPatrick Boettcher 			if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
2941173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
2942173a64cbSPatrick Boettcher 				if (state->revision != 0x8090) {
2943173a64cbSPatrick Boettcher 					state->agc1_max = dib8000_read_word(state, 108);
2944173a64cbSPatrick Boettcher 					state->agc1_min = dib8000_read_word(state, 109);
2945173a64cbSPatrick Boettcher 					state->agc2_max = dib8000_read_word(state, 110);
2946173a64cbSPatrick Boettcher 					state->agc2_min = dib8000_read_word(state, 111);
2947173a64cbSPatrick Boettcher 					agc1 = dib8000_read_word(state, 388);
2948173a64cbSPatrick Boettcher 					agc2 = dib8000_read_word(state, 389);
2949173a64cbSPatrick Boettcher 					dib8000_write_word(state, 108, agc1);
2950173a64cbSPatrick Boettcher 					dib8000_write_word(state, 109, agc1);
2951173a64cbSPatrick Boettcher 					dib8000_write_word(state, 110, agc2);
2952173a64cbSPatrick Boettcher 					dib8000_write_word(state, 111, agc2);
2953173a64cbSPatrick Boettcher 				}
2954173a64cbSPatrick Boettcher #endif
2955173a64cbSPatrick Boettcher 				state->autosearch_state = AS_SEARCHING_FFT;
2956173a64cbSPatrick Boettcher 				state->found_nfft = TRANSMISSION_MODE_AUTO;
2957173a64cbSPatrick Boettcher 				state->found_guard = GUARD_INTERVAL_AUTO;
2958173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_SEARCH_NEXT;
2959173a64cbSPatrick Boettcher 			} else { /* we already know the channel struct so TUNE only ! */
2960173a64cbSPatrick Boettcher 				state->autosearch_state = AS_DONE;
2961173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_3;
2962173a64cbSPatrick Boettcher 			}
2963173a64cbSPatrick Boettcher 			state->symbol_duration = dib8000_get_symbol_duration(state);
2964173a64cbSPatrick Boettcher 			break;
2965173a64cbSPatrick Boettcher 
2966173a64cbSPatrick Boettcher 	case CT_DEMOD_SEARCH_NEXT: /* 51 */
2967173a64cbSPatrick Boettcher 			dib8000_autosearch_start(fe);
2968173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
2969173a64cbSPatrick Boettcher 				ret = 50;
2970173a64cbSPatrick Boettcher 			else
2971173a64cbSPatrick Boettcher 				ret = 15;
2972173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_1;
2973173a64cbSPatrick Boettcher 			break;
2974173a64cbSPatrick Boettcher 
2975173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_1: /* 31 */
2976173a64cbSPatrick Boettcher 			switch (dib8000_autosearch_irq(fe)) {
2977173a64cbSPatrick Boettcher 			case 1: /* fail */
2978173a64cbSPatrick Boettcher 					state->status = FE_STATUS_TUNE_FAILED;
2979173a64cbSPatrick Boettcher 					state->autosearch_state = AS_DONE;
2980173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STOP; /* else we are done here */
2981173a64cbSPatrick Boettcher 					break;
2982173a64cbSPatrick Boettcher 			case 2: /* Succes */
2983173a64cbSPatrick Boettcher 					state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
2984173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_3;
2985173a64cbSPatrick Boettcher 					if (state->autosearch_state == AS_SEARCHING_GUARD)
2986173a64cbSPatrick Boettcher 						*tune_state = CT_DEMOD_STEP_2;
2987173a64cbSPatrick Boettcher 					else
2988173a64cbSPatrick Boettcher 						state->autosearch_state = AS_DONE;
2989173a64cbSPatrick Boettcher 					break;
2990173a64cbSPatrick Boettcher 			case 3: /* Autosearch FFT max correlation endded */
2991173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_2;
2992173a64cbSPatrick Boettcher 					break;
2993173a64cbSPatrick Boettcher 			}
2994173a64cbSPatrick Boettcher 			break;
2995173a64cbSPatrick Boettcher 
2996173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_2:
2997173a64cbSPatrick Boettcher 			switch (state->autosearch_state) {
2998173a64cbSPatrick Boettcher 			case AS_SEARCHING_FFT:
2999173a64cbSPatrick Boettcher 					/* searching for the correct FFT */
3000173a64cbSPatrick Boettcher 				if (state->revision == 0x8090) {
3001173a64cbSPatrick Boettcher 					corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3002173a64cbSPatrick Boettcher 					corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3003173a64cbSPatrick Boettcher 					corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
3004173a64cbSPatrick Boettcher 				} else {
3005173a64cbSPatrick Boettcher 					corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
3006173a64cbSPatrick Boettcher 					corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3007173a64cbSPatrick Boettcher 					corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3008173a64cbSPatrick Boettcher 				}
3009173a64cbSPatrick Boettcher 					/* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */
3010173a64cbSPatrick Boettcher 
3011173a64cbSPatrick Boettcher 					max_value = 0;
3012173a64cbSPatrick Boettcher 					for (find_index = 1 ; find_index < 3 ; find_index++) {
3013173a64cbSPatrick Boettcher 						if (corm[max_value] < corm[find_index])
3014173a64cbSPatrick Boettcher 							max_value = find_index ;
30159a0bf528SMauro Carvalho Chehab 					}
30169a0bf528SMauro Carvalho Chehab 
3017173a64cbSPatrick Boettcher 					switch (max_value) {
3018173a64cbSPatrick Boettcher 					case 0:
3019173a64cbSPatrick Boettcher 							state->found_nfft = TRANSMISSION_MODE_2K;
3020173a64cbSPatrick Boettcher 							break;
3021173a64cbSPatrick Boettcher 					case 1:
3022173a64cbSPatrick Boettcher 							state->found_nfft = TRANSMISSION_MODE_4K;
3023173a64cbSPatrick Boettcher 							break;
3024173a64cbSPatrick Boettcher 					case 2:
3025173a64cbSPatrick Boettcher 					default:
3026173a64cbSPatrick Boettcher 							state->found_nfft = TRANSMISSION_MODE_8K;
3027173a64cbSPatrick Boettcher 							break;
3028173a64cbSPatrick Boettcher 					}
3029173a64cbSPatrick Boettcher 					/* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */
3030173a64cbSPatrick Boettcher 
3031173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_SEARCH_NEXT;
3032173a64cbSPatrick Boettcher 					state->autosearch_state = AS_SEARCHING_GUARD;
3033173a64cbSPatrick Boettcher 					if (state->revision == 0x8090)
3034173a64cbSPatrick Boettcher 						ret = 50;
3035173a64cbSPatrick Boettcher 					else
3036173a64cbSPatrick Boettcher 						ret = 10;
3037173a64cbSPatrick Boettcher 					break;
3038173a64cbSPatrick Boettcher 			case AS_SEARCHING_GUARD:
3039173a64cbSPatrick Boettcher 					/* searching for the correct guard interval */
3040173a64cbSPatrick Boettcher 					if (state->revision == 0x8090)
3041173a64cbSPatrick Boettcher 						state->found_guard = dib8000_read_word(state, 572) & 0x3;
3042173a64cbSPatrick Boettcher 					else
3043173a64cbSPatrick Boettcher 						state->found_guard = dib8000_read_word(state, 570) & 0x3;
3044173a64cbSPatrick Boettcher 					/* dprintk("guard interval found=%i", state->found_guard); */
3045173a64cbSPatrick Boettcher 
3046173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_3;
3047173a64cbSPatrick Boettcher 					break;
3048173a64cbSPatrick Boettcher 			default:
3049173a64cbSPatrick Boettcher 					/* the demod should never be in this state */
3050173a64cbSPatrick Boettcher 					state->status = FE_STATUS_TUNE_FAILED;
3051173a64cbSPatrick Boettcher 					state->autosearch_state = AS_DONE;
3052173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STOP; /* else we are done here */
3053173a64cbSPatrick Boettcher 					break;
3054173a64cbSPatrick Boettcher 			}
3055173a64cbSPatrick Boettcher 			break;
3056173a64cbSPatrick Boettcher 
3057173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_3: /* 33 */
3058173a64cbSPatrick Boettcher 			state->symbol_duration = dib8000_get_symbol_duration(state);
3059173a64cbSPatrick Boettcher 			dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
3060173a64cbSPatrick Boettcher 			dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
3061173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_4;
3062173a64cbSPatrick Boettcher 			break;
3063173a64cbSPatrick Boettcher 
3064173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_4: /* (34) */
3065173a64cbSPatrick Boettcher 			dib8000_demod_restart(state);
3066173a64cbSPatrick Boettcher 
3067173a64cbSPatrick Boettcher 			dib8000_set_sync_wait(state);
3068173a64cbSPatrick Boettcher 			dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
3069173a64cbSPatrick Boettcher 
3070173a64cbSPatrick Boettcher 			locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
307139c1cb2bSJonathan McCrohan 			/* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */
3072173a64cbSPatrick Boettcher 			*timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
3073173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_5;
3074173a64cbSPatrick Boettcher 			break;
3075173a64cbSPatrick Boettcher 
3076173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_5: /* (35) */
3077173a64cbSPatrick Boettcher 			locks = dib8000_read_lock(fe);
3078173a64cbSPatrick Boettcher 			if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
3079173a64cbSPatrick Boettcher 				dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
3080173a64cbSPatrick Boettcher 				if (!state->differential_constellation) {
3081173a64cbSPatrick Boettcher 					/* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
3082173a64cbSPatrick Boettcher 					*timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
3083173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_7;
3084173a64cbSPatrick Boettcher 				} else {
3085173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_8;
3086173a64cbSPatrick Boettcher 				}
3087173a64cbSPatrick Boettcher 			} else if (now > *timeout) {
3088173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3089173a64cbSPatrick Boettcher 			}
3090173a64cbSPatrick Boettcher 			break;
3091173a64cbSPatrick Boettcher 
3092173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_6: /* (36)  if there is an input (diversity) */
3093173a64cbSPatrick Boettcher 			if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
3094173a64cbSPatrick Boettcher 				/* if there is a diversity fe in input and this fe is has not already failled : wait here until this this fe has succedeed or failled */
3095173a64cbSPatrick Boettcher 				if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
3096173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
3097173a64cbSPatrick Boettcher 				else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */
3098173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3099173a64cbSPatrick Boettcher 					dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3100173a64cbSPatrick Boettcher 					dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3101173a64cbSPatrick Boettcher 					state->status = FE_STATUS_TUNE_FAILED;
3102173a64cbSPatrick Boettcher 				}
3103173a64cbSPatrick Boettcher 			} else {
3104173a64cbSPatrick Boettcher 				dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3105173a64cbSPatrick Boettcher 				dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3106173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3107173a64cbSPatrick Boettcher 				state->status = FE_STATUS_TUNE_FAILED;
3108173a64cbSPatrick Boettcher 			}
3109173a64cbSPatrick Boettcher 			break;
3110173a64cbSPatrick Boettcher 
3111173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_7: /* 37 */
3112173a64cbSPatrick Boettcher 			locks = dib8000_read_lock(fe);
3113173a64cbSPatrick Boettcher 			if (locks & (1<<10)) { /* lmod4_lock */
3114173a64cbSPatrick Boettcher 				ret = 14; /* wait for 14 symbols */
3115173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_8;
3116173a64cbSPatrick Boettcher 			} else if (now > *timeout)
3117173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3118173a64cbSPatrick Boettcher 			break;
3119173a64cbSPatrick Boettcher 
3120173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_8: /* 38 */
3121173a64cbSPatrick Boettcher 			dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3122173a64cbSPatrick Boettcher 			dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3123173a64cbSPatrick Boettcher 
3124173a64cbSPatrick Boettcher 			/* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
3125746f7ae0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode
3126746f7ae0SMauro Carvalho Chehab 			    && c->isdbt_sb_subchannel < 14
3127746f7ae0SMauro Carvalho Chehab 			    && !state->differential_constellation) {
3128173a64cbSPatrick Boettcher 				state->subchannel = 0;
3129173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_11;
3130173a64cbSPatrick Boettcher 			} else {
3131173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_9;
3132173a64cbSPatrick Boettcher 				state->status = FE_STATUS_LOCKED;
3133173a64cbSPatrick Boettcher 			}
3134173a64cbSPatrick Boettcher 			break;
3135173a64cbSPatrick Boettcher 
3136173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_9: /* 39 */
3137173a64cbSPatrick Boettcher 			if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
313839c1cb2bSJonathan McCrohan 				/* defines timeout for mpeg lock depending on interleaver length of longest layer */
3139173a64cbSPatrick Boettcher 				for (i = 0; i < 3; i++) {
3140c82056d0SMauro Carvalho Chehab 					if (c->layer[i].interleaving >= deeper_interleaver) {
3141c82056d0SMauro Carvalho Chehab 						dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving);
3142c82056d0SMauro Carvalho Chehab 						if (c->layer[i].segment_count > 0) { /* valid layer */
3143c82056d0SMauro Carvalho Chehab 							deeper_interleaver = c->layer[0].interleaving;
3144173a64cbSPatrick Boettcher 							state->longest_intlv_layer = i;
3145173a64cbSPatrick Boettcher 						}
3146173a64cbSPatrick Boettcher 					}
3147173a64cbSPatrick Boettcher 				}
3148173a64cbSPatrick Boettcher 
3149173a64cbSPatrick Boettcher 				if (deeper_interleaver == 0)
3150173a64cbSPatrick Boettcher 					locks = 2; /* locks is the tmp local variable name */
3151173a64cbSPatrick Boettcher 				else if (deeper_interleaver == 3)
3152173a64cbSPatrick Boettcher 					locks = 8;
3153173a64cbSPatrick Boettcher 				else
3154173a64cbSPatrick Boettcher 					locks = 2 * deeper_interleaver;
3155173a64cbSPatrick Boettcher 
3156173a64cbSPatrick Boettcher 				if (state->diversity_onoff != 0) /* because of diversity sync */
3157173a64cbSPatrick Boettcher 					locks *= 2;
3158173a64cbSPatrick Boettcher 
3159173a64cbSPatrick Boettcher 				*timeout = now + (2000 * locks); /* give the mpeg lock 800ms if sram is present */
3160173a64cbSPatrick Boettcher 				dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %d", deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
3161173a64cbSPatrick Boettcher 
3162173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_10;
3163173a64cbSPatrick Boettcher 			} else
3164173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP;
3165173a64cbSPatrick Boettcher 			break;
3166173a64cbSPatrick Boettcher 
3167173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_10: /* 40 */
3168173a64cbSPatrick Boettcher 			locks = dib8000_read_lock(fe);
3169173a64cbSPatrick Boettcher 			if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
3170173a64cbSPatrick Boettcher 				dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
3171746f7ae0SMauro Carvalho Chehab 				if (c->isdbt_sb_mode
3172746f7ae0SMauro Carvalho Chehab 				    && c->isdbt_sb_subchannel < 14
3173746f7ae0SMauro Carvalho Chehab 				    && !state->differential_constellation)
3174173a64cbSPatrick Boettcher 					/* signal to the upper layer, that there was a channel found and the parameters can be read */
3175173a64cbSPatrick Boettcher 					state->status = FE_STATUS_DEMOD_SUCCESS;
3176173a64cbSPatrick Boettcher 				else
3177173a64cbSPatrick Boettcher 					state->status = FE_STATUS_DATA_LOCKED;
3178173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP;
3179173a64cbSPatrick Boettcher 			} else if (now > *timeout) {
3180746f7ae0SMauro Carvalho Chehab 				if (c->isdbt_sb_mode
3181746f7ae0SMauro Carvalho Chehab 				    && c->isdbt_sb_subchannel < 14
3182746f7ae0SMauro Carvalho Chehab 				    && !state->differential_constellation) { /* continue to try init prbs autosearch */
3183173a64cbSPatrick Boettcher 					state->subchannel += 3;
3184173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_11;
3185173a64cbSPatrick Boettcher 				} 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 */
3186173a64cbSPatrick Boettcher 					if (locks & (0x7<<5)) {
3187173a64cbSPatrick Boettcher 						dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
3188173a64cbSPatrick Boettcher 						state->status = FE_STATUS_DATA_LOCKED;
3189173a64cbSPatrick Boettcher 					} else
3190173a64cbSPatrick Boettcher 						state->status = FE_STATUS_TUNE_FAILED;
3191173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STOP;
3192173a64cbSPatrick Boettcher 				}
3193173a64cbSPatrick Boettcher 			}
3194173a64cbSPatrick Boettcher 			break;
3195173a64cbSPatrick Boettcher 
3196173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_11:  /* 41 : init prbs autosearch */
3197173a64cbSPatrick Boettcher 			if (state->subchannel <= 41) {
3198173a64cbSPatrick Boettcher 				dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
3199173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_9;
3200173a64cbSPatrick Boettcher 			} else {
3201173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP;
3202173a64cbSPatrick Boettcher 				state->status = FE_STATUS_TUNE_FAILED;
3203173a64cbSPatrick Boettcher 			}
3204173a64cbSPatrick Boettcher 			break;
3205173a64cbSPatrick Boettcher 
3206173a64cbSPatrick Boettcher 	default:
3207173a64cbSPatrick Boettcher 			break;
3208173a64cbSPatrick Boettcher 	}
3209173a64cbSPatrick Boettcher 
3210173a64cbSPatrick Boettcher 	/* tuning is finished - cleanup the demod */
3211173a64cbSPatrick Boettcher 	switch (*tune_state) {
3212173a64cbSPatrick Boettcher 	case CT_DEMOD_STOP: /* (42) */
3213173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3214173a64cbSPatrick Boettcher 			if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
3215173a64cbSPatrick Boettcher 				dib8000_write_word(state, 108, state->agc1_max);
3216173a64cbSPatrick Boettcher 				dib8000_write_word(state, 109, state->agc1_min);
3217173a64cbSPatrick Boettcher 				dib8000_write_word(state, 110, state->agc2_max);
3218173a64cbSPatrick Boettcher 				dib8000_write_word(state, 111, state->agc2_min);
3219173a64cbSPatrick Boettcher 				state->agc1_max = 0;
3220173a64cbSPatrick Boettcher 				state->agc1_min = 0;
3221173a64cbSPatrick Boettcher 				state->agc2_max = 0;
3222173a64cbSPatrick Boettcher 				state->agc2_min = 0;
3223173a64cbSPatrick Boettcher 			}
3224173a64cbSPatrick Boettcher #endif
3225173a64cbSPatrick Boettcher 			ret = FE_CALLBACK_TIME_NEVER;
3226173a64cbSPatrick Boettcher 			break;
3227173a64cbSPatrick Boettcher 	default:
3228173a64cbSPatrick Boettcher 			break;
3229173a64cbSPatrick Boettcher 	}
3230173a64cbSPatrick Boettcher 
3231173a64cbSPatrick Boettcher 	if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
3232173a64cbSPatrick Boettcher 		return ret * state->symbol_duration;
3233173a64cbSPatrick Boettcher 	if ((ret > 0) && (ret < state->symbol_duration))
3234173a64cbSPatrick Boettcher 		return state->symbol_duration; /* at least one symbol */
32359a0bf528SMauro Carvalho Chehab 	return ret;
32369a0bf528SMauro Carvalho Chehab }
32379a0bf528SMauro Carvalho Chehab 
32389a0bf528SMauro Carvalho Chehab static int dib8000_wakeup(struct dvb_frontend *fe)
32399a0bf528SMauro Carvalho Chehab {
32409a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
32419a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
32429a0bf528SMauro Carvalho Chehab 	int ret;
32439a0bf528SMauro Carvalho Chehab 
32449a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
32459a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_ADC_ON);
32469a0bf528SMauro Carvalho Chehab 	if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
32479a0bf528SMauro Carvalho Chehab 		dprintk("could not start Slow ADC");
32489a0bf528SMauro Carvalho Chehab 
3249173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
32509a0bf528SMauro Carvalho Chehab 		dib8000_sad_calib(state);
32519a0bf528SMauro Carvalho Chehab 
32529a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
32539a0bf528SMauro Carvalho Chehab 		ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
32549a0bf528SMauro Carvalho Chehab 		if (ret < 0)
32559a0bf528SMauro Carvalho Chehab 			return ret;
32569a0bf528SMauro Carvalho Chehab 	}
32579a0bf528SMauro Carvalho Chehab 
32589a0bf528SMauro Carvalho Chehab 	return 0;
32599a0bf528SMauro Carvalho Chehab }
32609a0bf528SMauro Carvalho Chehab 
32619a0bf528SMauro Carvalho Chehab static int dib8000_sleep(struct dvb_frontend *fe)
32629a0bf528SMauro Carvalho Chehab {
32639a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
32649a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
32659a0bf528SMauro Carvalho Chehab 	int ret;
32669a0bf528SMauro Carvalho Chehab 
32679a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
32689a0bf528SMauro Carvalho Chehab 		ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
32699a0bf528SMauro Carvalho Chehab 		if (ret < 0)
32709a0bf528SMauro Carvalho Chehab 			return ret;
32719a0bf528SMauro Carvalho Chehab 	}
32729a0bf528SMauro Carvalho Chehab 
32739a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
32749a0bf528SMauro Carvalho Chehab 		dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
32759a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
32769a0bf528SMauro Carvalho Chehab 	return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
32779a0bf528SMauro Carvalho Chehab }
32789a0bf528SMauro Carvalho Chehab 
327970315b3eSMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat);
328070315b3eSMauro Carvalho Chehab 
32819a0bf528SMauro Carvalho Chehab static int dib8000_get_frontend(struct dvb_frontend *fe)
32829a0bf528SMauro Carvalho Chehab {
32839a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
32849a0bf528SMauro Carvalho Chehab 	u16 i, val = 0;
328570315b3eSMauro Carvalho Chehab 	fe_status_t stat = 0;
32869a0bf528SMauro Carvalho Chehab 	u8 index_frontend, sub_index_frontend;
32879a0bf528SMauro Carvalho Chehab 
32889a0bf528SMauro Carvalho Chehab 	fe->dtv_property_cache.bandwidth_hz = 6000000;
32899a0bf528SMauro Carvalho Chehab 
329070315b3eSMauro Carvalho Chehab 	/*
329170315b3eSMauro Carvalho Chehab 	 * If called to early, get_frontend makes dib8000_tune to either
329270315b3eSMauro Carvalho Chehab 	 * not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail.
329370315b3eSMauro Carvalho Chehab 	 * So, let's just return if frontend 0 has not locked.
329470315b3eSMauro Carvalho Chehab 	 */
329570315b3eSMauro Carvalho Chehab 	dib8000_read_status(fe, &stat);
329670315b3eSMauro Carvalho Chehab 	if (!(stat & FE_HAS_SYNC))
329770315b3eSMauro Carvalho Chehab 		return 0;
329870315b3eSMauro Carvalho Chehab 
329970315b3eSMauro Carvalho Chehab 	dprintk("TMCC lock");
33009a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
33019a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
33029a0bf528SMauro Carvalho Chehab 		if (stat&FE_HAS_SYNC) {
33039a0bf528SMauro Carvalho Chehab 			dprintk("TMCC lock on the slave%i", index_frontend);
33049a0bf528SMauro Carvalho Chehab 			/* synchronize the cache with the other frontends */
33059a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
33069a0bf528SMauro Carvalho Chehab 			for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {
33079a0bf528SMauro Carvalho Chehab 				if (sub_index_frontend != index_frontend) {
33089a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
33099a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
33109a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
33119a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
33129a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
33139a0bf528SMauro Carvalho Chehab 					for (i = 0; i < 3; i++) {
33149a0bf528SMauro Carvalho Chehab 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
33159a0bf528SMauro Carvalho Chehab 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
33169a0bf528SMauro Carvalho Chehab 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
33179a0bf528SMauro Carvalho Chehab 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
33189a0bf528SMauro Carvalho Chehab 					}
33199a0bf528SMauro Carvalho Chehab 				}
33209a0bf528SMauro Carvalho Chehab 			}
33219a0bf528SMauro Carvalho Chehab 			return 0;
33229a0bf528SMauro Carvalho Chehab 		}
33239a0bf528SMauro Carvalho Chehab 	}
33249a0bf528SMauro Carvalho Chehab 
33259a0bf528SMauro Carvalho Chehab 	fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
33269a0bf528SMauro Carvalho Chehab 
33279a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
33289a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 572);
33299a0bf528SMauro Carvalho Chehab 	else
33309a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 570);
33319a0bf528SMauro Carvalho Chehab 	fe->dtv_property_cache.inversion = (val & 0x40) >> 6;
33329a0bf528SMauro Carvalho Chehab 	switch ((val & 0x30) >> 4) {
33339a0bf528SMauro Carvalho Chehab 	case 1:
33349a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
33359a0bf528SMauro Carvalho Chehab 		break;
33369a0bf528SMauro Carvalho Chehab 	case 3:
33379a0bf528SMauro Carvalho Chehab 	default:
33389a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
33399a0bf528SMauro Carvalho Chehab 		break;
33409a0bf528SMauro Carvalho Chehab 	}
33419a0bf528SMauro Carvalho Chehab 
33429a0bf528SMauro Carvalho Chehab 	switch (val & 0x3) {
33439a0bf528SMauro Carvalho Chehab 	case 0:
33449a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
33459a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend GI = 1/32 ");
33469a0bf528SMauro Carvalho Chehab 		break;
33479a0bf528SMauro Carvalho Chehab 	case 1:
33489a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
33499a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend GI = 1/16 ");
33509a0bf528SMauro Carvalho Chehab 		break;
33519a0bf528SMauro Carvalho Chehab 	case 2:
33529a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend GI = 1/8 ");
33539a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
33549a0bf528SMauro Carvalho Chehab 		break;
33559a0bf528SMauro Carvalho Chehab 	case 3:
33569a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend GI = 1/4 ");
33579a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
33589a0bf528SMauro Carvalho Chehab 		break;
33599a0bf528SMauro Carvalho Chehab 	}
33609a0bf528SMauro Carvalho Chehab 
33619a0bf528SMauro Carvalho Chehab 	val = dib8000_read_word(state, 505);
33629a0bf528SMauro Carvalho Chehab 	fe->dtv_property_cache.isdbt_partial_reception = val & 1;
33639a0bf528SMauro Carvalho Chehab 	dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
33649a0bf528SMauro Carvalho Chehab 
33659a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 3; i++) {
33669a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 493 + i);
33679a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;
33689a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);
33699a0bf528SMauro Carvalho Chehab 
33709a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 499 + i);
33719a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.layer[i].interleaving = val & 0x3;
33729a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving);
33739a0bf528SMauro Carvalho Chehab 
33749a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 481 + i);
33759a0bf528SMauro Carvalho Chehab 		switch (val & 0x7) {
33769a0bf528SMauro Carvalho Chehab 		case 1:
33779a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_1_2;
33789a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i);
33799a0bf528SMauro Carvalho Chehab 			break;
33809a0bf528SMauro Carvalho Chehab 		case 2:
33819a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_2_3;
33829a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i);
33839a0bf528SMauro Carvalho Chehab 			break;
33849a0bf528SMauro Carvalho Chehab 		case 3:
33859a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_3_4;
33869a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i);
33879a0bf528SMauro Carvalho Chehab 			break;
33889a0bf528SMauro Carvalho Chehab 		case 5:
33899a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_5_6;
33909a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i);
33919a0bf528SMauro Carvalho Chehab 			break;
33929a0bf528SMauro Carvalho Chehab 		default:
33939a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_7_8;
33949a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i);
33959a0bf528SMauro Carvalho Chehab 			break;
33969a0bf528SMauro Carvalho Chehab 		}
33979a0bf528SMauro Carvalho Chehab 
33989a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 487 + i);
33999a0bf528SMauro Carvalho Chehab 		switch (val & 0x3) {
34009a0bf528SMauro Carvalho Chehab 		case 0:
34019a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d DQPSK ", i);
34029a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].modulation = DQPSK;
34039a0bf528SMauro Carvalho Chehab 			break;
34049a0bf528SMauro Carvalho Chehab 		case 1:
34059a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].modulation = QPSK;
34069a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d QPSK ", i);
34079a0bf528SMauro Carvalho Chehab 			break;
34089a0bf528SMauro Carvalho Chehab 		case 2:
34099a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].modulation = QAM_16;
34109a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d QAM16 ", i);
34119a0bf528SMauro Carvalho Chehab 			break;
34129a0bf528SMauro Carvalho Chehab 		case 3:
34139a0bf528SMauro Carvalho Chehab 		default:
34149a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d QAM64 ", i);
34159a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].modulation = QAM_64;
34169a0bf528SMauro Carvalho Chehab 			break;
34179a0bf528SMauro Carvalho Chehab 		}
34189a0bf528SMauro Carvalho Chehab 	}
34199a0bf528SMauro Carvalho Chehab 
34209a0bf528SMauro Carvalho Chehab 	/* synchronize the cache with the other frontends */
34219a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
34229a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode;
34239a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
34249a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
34259a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
34269a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception;
34279a0bf528SMauro Carvalho Chehab 		for (i = 0; i < 3; i++) {
34289a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count;
34299a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving;
34309a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec;
34319a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation;
34329a0bf528SMauro Carvalho Chehab 		}
34339a0bf528SMauro Carvalho Chehab 	}
34349a0bf528SMauro Carvalho Chehab 	return 0;
34359a0bf528SMauro Carvalho Chehab }
34369a0bf528SMauro Carvalho Chehab 
34379a0bf528SMauro Carvalho Chehab static int dib8000_set_frontend(struct dvb_frontend *fe)
34389a0bf528SMauro Carvalho Chehab {
34399a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
3440c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
34414d8d5d92SGeert Uytterhoeven 	int l, i, active, time, time_slave = FE_CALLBACK_TIME_NEVER;
3442173a64cbSPatrick Boettcher 	u8 exit_condition, index_frontend;
3443173a64cbSPatrick Boettcher 	u32 delay, callback_time;
34449a0bf528SMauro Carvalho Chehab 
3445c82056d0SMauro Carvalho Chehab 	if (c->frequency == 0) {
34469a0bf528SMauro Carvalho Chehab 		dprintk("dib8000: must at least specify frequency ");
34479a0bf528SMauro Carvalho Chehab 		return 0;
34489a0bf528SMauro Carvalho Chehab 	}
34499a0bf528SMauro Carvalho Chehab 
3450c82056d0SMauro Carvalho Chehab 	if (c->bandwidth_hz == 0) {
34519a0bf528SMauro Carvalho Chehab 		dprintk("dib8000: no bandwidth specified, set to default ");
3452c82056d0SMauro Carvalho Chehab 		c->bandwidth_hz = 6000000;
34539a0bf528SMauro Carvalho Chehab 	}
34549a0bf528SMauro Carvalho Chehab 
34559a0bf528SMauro Carvalho Chehab 	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
34569a0bf528SMauro Carvalho Chehab 		/* synchronization of the cache */
34579a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
34589a0bf528SMauro Carvalho Chehab 		memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
34599a0bf528SMauro Carvalho Chehab 
3460173a64cbSPatrick Boettcher 		/* set output mode and diversity input */
3461173a64cbSPatrick Boettcher 		if (state->revision != 0x8090) {
3462173a64cbSPatrick Boettcher 			dib8000_set_diversity_in(state->fe[index_frontend], 1);
3463173a64cbSPatrick Boettcher 			if (index_frontend != 0)
34649a0bf528SMauro Carvalho Chehab 				dib8000_set_output_mode(state->fe[index_frontend],
3465173a64cbSPatrick Boettcher 						OUTMODE_DIVERSITY);
34669a0bf528SMauro Carvalho Chehab 			else
3467173a64cbSPatrick Boettcher 				dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3468173a64cbSPatrick Boettcher 		} else {
3469173a64cbSPatrick Boettcher 			dib8096p_set_diversity_in(state->fe[index_frontend], 1);
3470173a64cbSPatrick Boettcher 			if (index_frontend != 0)
34719a0bf528SMauro Carvalho Chehab 				dib8096p_set_output_mode(state->fe[index_frontend],
3472173a64cbSPatrick Boettcher 						OUTMODE_DIVERSITY);
3473173a64cbSPatrick Boettcher 			else
3474173a64cbSPatrick Boettcher 				dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3475173a64cbSPatrick Boettcher 		}
3476173a64cbSPatrick Boettcher 
3477173a64cbSPatrick Boettcher 		/* tune the tuner */
34789a0bf528SMauro Carvalho Chehab 		if (state->fe[index_frontend]->ops.tuner_ops.set_params)
34799a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
34809a0bf528SMauro Carvalho Chehab 
34819a0bf528SMauro Carvalho Chehab 		dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
34829a0bf528SMauro Carvalho Chehab 	}
34839a0bf528SMauro Carvalho Chehab 
3484173a64cbSPatrick Boettcher 	/* turn off the diversity of the last chip */
3485173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
3486173a64cbSPatrick Boettcher 		dib8000_set_diversity_in(state->fe[index_frontend - 1], 0);
3487173a64cbSPatrick Boettcher 	else
3488173a64cbSPatrick Boettcher 		dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0);
3489173a64cbSPatrick Boettcher 
34909a0bf528SMauro Carvalho Chehab 	/* start up the AGC */
34919a0bf528SMauro Carvalho Chehab 	do {
34929a0bf528SMauro Carvalho Chehab 		time = dib8000_agc_startup(state->fe[0]);
34939a0bf528SMauro Carvalho Chehab 		for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
34949a0bf528SMauro Carvalho Chehab 			time_slave = dib8000_agc_startup(state->fe[index_frontend]);
34959a0bf528SMauro Carvalho Chehab 			if (time == FE_CALLBACK_TIME_NEVER)
34969a0bf528SMauro Carvalho Chehab 				time = time_slave;
34979a0bf528SMauro Carvalho Chehab 			else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time))
34989a0bf528SMauro Carvalho Chehab 				time = time_slave;
34999a0bf528SMauro Carvalho Chehab 		}
35009a0bf528SMauro Carvalho Chehab 		if (time != FE_CALLBACK_TIME_NEVER)
35019a0bf528SMauro Carvalho Chehab 			msleep(time / 10);
35029a0bf528SMauro Carvalho Chehab 		else
35039a0bf528SMauro Carvalho Chehab 			break;
35049a0bf528SMauro Carvalho Chehab 		exit_condition = 1;
35059a0bf528SMauro Carvalho Chehab 		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
35069a0bf528SMauro Carvalho Chehab 			if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
35079a0bf528SMauro Carvalho Chehab 				exit_condition = 0;
35089a0bf528SMauro Carvalho Chehab 				break;
35099a0bf528SMauro Carvalho Chehab 			}
35109a0bf528SMauro Carvalho Chehab 		}
35119a0bf528SMauro Carvalho Chehab 	} while (exit_condition == 0);
35129a0bf528SMauro Carvalho Chehab 
35139a0bf528SMauro Carvalho Chehab 	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
35149a0bf528SMauro Carvalho Chehab 		dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
35159a0bf528SMauro Carvalho Chehab 
3516173a64cbSPatrick Boettcher 	active = 1;
35179a0bf528SMauro Carvalho Chehab 	do {
3518173a64cbSPatrick Boettcher 		callback_time = FE_CALLBACK_TIME_NEVER;
35199a0bf528SMauro Carvalho Chehab 		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3520173a64cbSPatrick Boettcher 			delay = dib8000_tune(state->fe[index_frontend]);
3521173a64cbSPatrick Boettcher 			if (delay != FE_CALLBACK_TIME_NEVER)
3522173a64cbSPatrick Boettcher 				delay += systime();
3523173a64cbSPatrick Boettcher 
3524173a64cbSPatrick Boettcher 			/* we are in autosearch */
3525173a64cbSPatrick Boettcher 			if (state->channel_parameters_set == 0) { /* searching */
3526173a64cbSPatrick Boettcher 				if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) {
3527173a64cbSPatrick Boettcher 					dprintk("autosearch succeeded on fe%i", index_frontend);
3528173a64cbSPatrick Boettcher 					dib8000_get_frontend(state->fe[index_frontend]); /* we read the channel parameters from the frontend which was successful */
3529173a64cbSPatrick Boettcher 					state->channel_parameters_set = 1;
3530173a64cbSPatrick Boettcher 
3531173a64cbSPatrick Boettcher 					for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
3532173a64cbSPatrick Boettcher 						if (l != index_frontend) { /* and for all frontend except the successful one */
3533173a64cbSPatrick Boettcher 							dib8000_tune_restart_from_demod(state->fe[l]);
3534173a64cbSPatrick Boettcher 
3535173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3536173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3537173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3538173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3539173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3540173a64cbSPatrick Boettcher 							for (i = 0; i < 3; i++) {
3541173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3542173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3543173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3544173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3545173a64cbSPatrick Boettcher 							}
3546173a64cbSPatrick Boettcher 
35479a0bf528SMauro Carvalho Chehab 						}
35489a0bf528SMauro Carvalho Chehab 					}
35499a0bf528SMauro Carvalho Chehab 				}
3550173a64cbSPatrick Boettcher 			}
3551173a64cbSPatrick Boettcher 			if (delay < callback_time)
3552173a64cbSPatrick Boettcher 				callback_time = delay;
3553173a64cbSPatrick Boettcher 		}
3554173a64cbSPatrick Boettcher 		/* tuning is done when the master frontend is done (failed or success) */
3555173a64cbSPatrick Boettcher 		if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
3556173a64cbSPatrick Boettcher 				dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED ||
3557173a64cbSPatrick Boettcher 				dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) {
3558173a64cbSPatrick Boettcher 			active = 0;
3559173a64cbSPatrick Boettcher 			/* we need to wait for all frontends to be finished */
3560173a64cbSPatrick Boettcher 			for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3561173a64cbSPatrick Boettcher 				if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP)
3562173a64cbSPatrick Boettcher 					active = 1;
3563173a64cbSPatrick Boettcher 			}
3564173a64cbSPatrick Boettcher 			if (active == 0)
3565173a64cbSPatrick Boettcher 				dprintk("tuning done with status %d", dib8000_get_status(state->fe[0]));
35669a0bf528SMauro Carvalho Chehab 		}
35679a0bf528SMauro Carvalho Chehab 
3568173a64cbSPatrick Boettcher 		if ((active == 1) && (callback_time == FE_CALLBACK_TIME_NEVER)) {
3569173a64cbSPatrick Boettcher 			dprintk("strange callback time something went wrong");
3570173a64cbSPatrick Boettcher 			active = 0;
35719a0bf528SMauro Carvalho Chehab 		}
35729a0bf528SMauro Carvalho Chehab 
3573173a64cbSPatrick Boettcher 		while ((active == 1) && (systime() < callback_time))
3574173a64cbSPatrick Boettcher 			msleep(100);
3575173a64cbSPatrick Boettcher 	} while (active);
35769a0bf528SMauro Carvalho Chehab 
3577173a64cbSPatrick Boettcher 	/* set output mode */
3578173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
35799a0bf528SMauro Carvalho Chehab 		dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
3580173a64cbSPatrick Boettcher 	else {
35819a0bf528SMauro Carvalho Chehab 		dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
35829a0bf528SMauro Carvalho Chehab 		if (state->cfg.enMpegOutput == 0) {
35839a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
35849a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
35859a0bf528SMauro Carvalho Chehab 		}
35869a0bf528SMauro Carvalho Chehab 	}
35879a0bf528SMauro Carvalho Chehab 
35884d8d5d92SGeert Uytterhoeven 	return 0;
35899a0bf528SMauro Carvalho Chehab }
35909a0bf528SMauro Carvalho Chehab 
35919a0bf528SMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
35929a0bf528SMauro Carvalho Chehab {
35939a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
35949a0bf528SMauro Carvalho Chehab 	u16 lock_slave = 0, lock;
35959a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
35969a0bf528SMauro Carvalho Chehab 
3597173a64cbSPatrick Boettcher 	lock = dib8000_read_lock(fe);
35989a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
35999a0bf528SMauro Carvalho Chehab 		lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
36009a0bf528SMauro Carvalho Chehab 
36019a0bf528SMauro Carvalho Chehab 	*stat = 0;
36029a0bf528SMauro Carvalho Chehab 
36039a0bf528SMauro Carvalho Chehab 	if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
36049a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SIGNAL;
36059a0bf528SMauro Carvalho Chehab 
36069a0bf528SMauro Carvalho Chehab 	if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
36079a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_CARRIER;
36089a0bf528SMauro Carvalho Chehab 
36099a0bf528SMauro Carvalho Chehab 	if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
36109a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SYNC;
36119a0bf528SMauro Carvalho Chehab 
36129a0bf528SMauro Carvalho Chehab 	if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
36139a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_LOCK;
36149a0bf528SMauro Carvalho Chehab 
36159a0bf528SMauro Carvalho Chehab 	if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
36169a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
36179a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
36189a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
36199a0bf528SMauro Carvalho Chehab 
36209a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
36219a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
36229a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
36239a0bf528SMauro Carvalho Chehab 
36249a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
36259a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
36269a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
36279a0bf528SMauro Carvalho Chehab 	}
36289a0bf528SMauro Carvalho Chehab 
36299a0bf528SMauro Carvalho Chehab 	return 0;
36309a0bf528SMauro Carvalho Chehab }
36319a0bf528SMauro Carvalho Chehab 
36329a0bf528SMauro Carvalho Chehab static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
36339a0bf528SMauro Carvalho Chehab {
36349a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
36359a0bf528SMauro Carvalho Chehab 
36369a0bf528SMauro Carvalho Chehab 	/* 13 segments */
36379a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
36389a0bf528SMauro Carvalho Chehab 		*ber = (dib8000_read_word(state, 562) << 16) |
36399a0bf528SMauro Carvalho Chehab 			dib8000_read_word(state, 563);
36409a0bf528SMauro Carvalho Chehab 	else
36419a0bf528SMauro Carvalho Chehab 		*ber = (dib8000_read_word(state, 560) << 16) |
36429a0bf528SMauro Carvalho Chehab 			dib8000_read_word(state, 561);
36439a0bf528SMauro Carvalho Chehab 	return 0;
36449a0bf528SMauro Carvalho Chehab }
36459a0bf528SMauro Carvalho Chehab 
36469a0bf528SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
36479a0bf528SMauro Carvalho Chehab {
36489a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
36499a0bf528SMauro Carvalho Chehab 
36509a0bf528SMauro Carvalho Chehab 	/* packet error on 13 seg */
36519a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
36529a0bf528SMauro Carvalho Chehab 		*unc = dib8000_read_word(state, 567);
36539a0bf528SMauro Carvalho Chehab 	else
36549a0bf528SMauro Carvalho Chehab 		*unc = dib8000_read_word(state, 565);
36559a0bf528SMauro Carvalho Chehab 	return 0;
36569a0bf528SMauro Carvalho Chehab }
36579a0bf528SMauro Carvalho Chehab 
36589a0bf528SMauro Carvalho Chehab static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
36599a0bf528SMauro Carvalho Chehab {
36609a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
36619a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
36629a0bf528SMauro Carvalho Chehab 	u16 val;
36639a0bf528SMauro Carvalho Chehab 
36649a0bf528SMauro Carvalho Chehab 	*strength = 0;
36659a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
36669a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
36679a0bf528SMauro Carvalho Chehab 		if (val > 65535 - *strength)
36689a0bf528SMauro Carvalho Chehab 			*strength = 65535;
36699a0bf528SMauro Carvalho Chehab 		else
36709a0bf528SMauro Carvalho Chehab 			*strength += val;
36719a0bf528SMauro Carvalho Chehab 	}
36729a0bf528SMauro Carvalho Chehab 
36739a0bf528SMauro Carvalho Chehab 	val = 65535 - dib8000_read_word(state, 390);
36749a0bf528SMauro Carvalho Chehab 	if (val > 65535 - *strength)
36759a0bf528SMauro Carvalho Chehab 		*strength = 65535;
36769a0bf528SMauro Carvalho Chehab 	else
36779a0bf528SMauro Carvalho Chehab 		*strength += val;
36789a0bf528SMauro Carvalho Chehab 	return 0;
36799a0bf528SMauro Carvalho Chehab }
36809a0bf528SMauro Carvalho Chehab 
36819a0bf528SMauro Carvalho Chehab static u32 dib8000_get_snr(struct dvb_frontend *fe)
36829a0bf528SMauro Carvalho Chehab {
36839a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
36849a0bf528SMauro Carvalho Chehab 	u32 n, s, exp;
36859a0bf528SMauro Carvalho Chehab 	u16 val;
36869a0bf528SMauro Carvalho Chehab 
36879a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
36889a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 542);
36899a0bf528SMauro Carvalho Chehab 	else
36909a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 544);
36919a0bf528SMauro Carvalho Chehab 	n = (val >> 6) & 0xff;
36929a0bf528SMauro Carvalho Chehab 	exp = (val & 0x3f);
36939a0bf528SMauro Carvalho Chehab 	if ((exp & 0x20) != 0)
36949a0bf528SMauro Carvalho Chehab 		exp -= 0x40;
36959a0bf528SMauro Carvalho Chehab 	n <<= exp+16;
36969a0bf528SMauro Carvalho Chehab 
36979a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
36989a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 543);
36999a0bf528SMauro Carvalho Chehab 	else
37009a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 545);
37019a0bf528SMauro Carvalho Chehab 	s = (val >> 6) & 0xff;
37029a0bf528SMauro Carvalho Chehab 	exp = (val & 0x3f);
37039a0bf528SMauro Carvalho Chehab 	if ((exp & 0x20) != 0)
37049a0bf528SMauro Carvalho Chehab 		exp -= 0x40;
37059a0bf528SMauro Carvalho Chehab 	s <<= exp+16;
37069a0bf528SMauro Carvalho Chehab 
37079a0bf528SMauro Carvalho Chehab 	if (n > 0) {
37089a0bf528SMauro Carvalho Chehab 		u32 t = (s/n) << 16;
37099a0bf528SMauro Carvalho Chehab 		return t + ((s << 16) - n*t) / n;
37109a0bf528SMauro Carvalho Chehab 	}
37119a0bf528SMauro Carvalho Chehab 	return 0xffffffff;
37129a0bf528SMauro Carvalho Chehab }
37139a0bf528SMauro Carvalho Chehab 
37149a0bf528SMauro Carvalho Chehab static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
37159a0bf528SMauro Carvalho Chehab {
37169a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37179a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
37189a0bf528SMauro Carvalho Chehab 	u32 snr_master;
37199a0bf528SMauro Carvalho Chehab 
37209a0bf528SMauro Carvalho Chehab 	snr_master = dib8000_get_snr(fe);
37219a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
37229a0bf528SMauro Carvalho Chehab 		snr_master += dib8000_get_snr(state->fe[index_frontend]);
37239a0bf528SMauro Carvalho Chehab 
37249a0bf528SMauro Carvalho Chehab 	if ((snr_master >> 16) != 0) {
37259a0bf528SMauro Carvalho Chehab 		snr_master = 10*intlog10(snr_master>>16);
37269a0bf528SMauro Carvalho Chehab 		*snr = snr_master / ((1 << 24) / 10);
37279a0bf528SMauro Carvalho Chehab 	}
37289a0bf528SMauro Carvalho Chehab 	else
37299a0bf528SMauro Carvalho Chehab 		*snr = 0;
37309a0bf528SMauro Carvalho Chehab 
37319a0bf528SMauro Carvalho Chehab 	return 0;
37329a0bf528SMauro Carvalho Chehab }
37339a0bf528SMauro Carvalho Chehab 
37349a0bf528SMauro Carvalho Chehab int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
37359a0bf528SMauro Carvalho Chehab {
37369a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37379a0bf528SMauro Carvalho Chehab 	u8 index_frontend = 1;
37389a0bf528SMauro Carvalho Chehab 
37399a0bf528SMauro Carvalho Chehab 	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
37409a0bf528SMauro Carvalho Chehab 		index_frontend++;
37419a0bf528SMauro Carvalho Chehab 	if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
37429a0bf528SMauro Carvalho Chehab 		dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
37439a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend] = fe_slave;
37449a0bf528SMauro Carvalho Chehab 		return 0;
37459a0bf528SMauro Carvalho Chehab 	}
37469a0bf528SMauro Carvalho Chehab 
37479a0bf528SMauro Carvalho Chehab 	dprintk("too many slave frontend");
37489a0bf528SMauro Carvalho Chehab 	return -ENOMEM;
37499a0bf528SMauro Carvalho Chehab }
37509a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_set_slave_frontend);
37519a0bf528SMauro Carvalho Chehab 
37529a0bf528SMauro Carvalho Chehab int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
37539a0bf528SMauro Carvalho Chehab {
37549a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37559a0bf528SMauro Carvalho Chehab 	u8 index_frontend = 1;
37569a0bf528SMauro Carvalho Chehab 
37579a0bf528SMauro Carvalho Chehab 	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
37589a0bf528SMauro Carvalho Chehab 		index_frontend++;
37599a0bf528SMauro Carvalho Chehab 	if (index_frontend != 1) {
37609a0bf528SMauro Carvalho Chehab 		dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1);
37619a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend] = NULL;
37629a0bf528SMauro Carvalho Chehab 		return 0;
37639a0bf528SMauro Carvalho Chehab 	}
37649a0bf528SMauro Carvalho Chehab 
37659a0bf528SMauro Carvalho Chehab 	dprintk("no frontend to be removed");
37669a0bf528SMauro Carvalho Chehab 	return -ENODEV;
37679a0bf528SMauro Carvalho Chehab }
37689a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_remove_slave_frontend);
37699a0bf528SMauro Carvalho Chehab 
37709a0bf528SMauro Carvalho Chehab struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
37719a0bf528SMauro Carvalho Chehab {
37729a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37739a0bf528SMauro Carvalho Chehab 
37749a0bf528SMauro Carvalho Chehab 	if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
37759a0bf528SMauro Carvalho Chehab 		return NULL;
37769a0bf528SMauro Carvalho Chehab 	return state->fe[slave_index];
37779a0bf528SMauro Carvalho Chehab }
37789a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_get_slave_frontend);
37799a0bf528SMauro Carvalho Chehab 
37809a0bf528SMauro Carvalho Chehab 
37819a0bf528SMauro Carvalho Chehab int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
37829a0bf528SMauro Carvalho Chehab 		u8 default_addr, u8 first_addr, u8 is_dib8096p)
37839a0bf528SMauro Carvalho Chehab {
37849a0bf528SMauro Carvalho Chehab 	int k = 0, ret = 0;
37859a0bf528SMauro Carvalho Chehab 	u8 new_addr = 0;
37869a0bf528SMauro Carvalho Chehab 	struct i2c_device client = {.adap = host };
37879a0bf528SMauro Carvalho Chehab 
37889a0bf528SMauro Carvalho Chehab 	client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
37899a0bf528SMauro Carvalho Chehab 	if (!client.i2c_write_buffer) {
37909a0bf528SMauro Carvalho Chehab 		dprintk("%s: not enough memory", __func__);
37919a0bf528SMauro Carvalho Chehab 		return -ENOMEM;
37929a0bf528SMauro Carvalho Chehab 	}
37939a0bf528SMauro Carvalho Chehab 	client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
37949a0bf528SMauro Carvalho Chehab 	if (!client.i2c_read_buffer) {
37959a0bf528SMauro Carvalho Chehab 		dprintk("%s: not enough memory", __func__);
37969a0bf528SMauro Carvalho Chehab 		ret = -ENOMEM;
37979a0bf528SMauro Carvalho Chehab 		goto error_memory_read;
37989a0bf528SMauro Carvalho Chehab 	}
37999a0bf528SMauro Carvalho Chehab 	client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
38009a0bf528SMauro Carvalho Chehab 	if (!client.i2c_buffer_lock) {
38019a0bf528SMauro Carvalho Chehab 		dprintk("%s: not enough memory", __func__);
38029a0bf528SMauro Carvalho Chehab 		ret = -ENOMEM;
38039a0bf528SMauro Carvalho Chehab 		goto error_memory_lock;
38049a0bf528SMauro Carvalho Chehab 	}
38059a0bf528SMauro Carvalho Chehab 	mutex_init(client.i2c_buffer_lock);
38069a0bf528SMauro Carvalho Chehab 
38079a0bf528SMauro Carvalho Chehab 	for (k = no_of_demods - 1; k >= 0; k--) {
38089a0bf528SMauro Carvalho Chehab 		/* designated i2c address */
38099a0bf528SMauro Carvalho Chehab 		new_addr = first_addr + (k << 1);
38109a0bf528SMauro Carvalho Chehab 
38119a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
38129a0bf528SMauro Carvalho Chehab 		if (!is_dib8096p)
38139a0bf528SMauro Carvalho Chehab 			dib8000_i2c_write16(&client, 1287, 0x0003);	/* sram lead in, rdy */
38149a0bf528SMauro Carvalho Chehab 		if (dib8000_identify(&client) == 0) {
38159a0bf528SMauro Carvalho Chehab 			/* sram lead in, rdy */
38169a0bf528SMauro Carvalho Chehab 			if (!is_dib8096p)
38179a0bf528SMauro Carvalho Chehab 				dib8000_i2c_write16(&client, 1287, 0x0003);
38189a0bf528SMauro Carvalho Chehab 			client.addr = default_addr;
38199a0bf528SMauro Carvalho Chehab 			if (dib8000_identify(&client) == 0) {
38209a0bf528SMauro Carvalho Chehab 				dprintk("#%d: not identified", k);
38219a0bf528SMauro Carvalho Chehab 				ret  = -EINVAL;
38229a0bf528SMauro Carvalho Chehab 				goto error;
38239a0bf528SMauro Carvalho Chehab 			}
38249a0bf528SMauro Carvalho Chehab 		}
38259a0bf528SMauro Carvalho Chehab 
38269a0bf528SMauro Carvalho Chehab 		/* start diversity to pull_down div_str - just for i2c-enumeration */
38279a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
38289a0bf528SMauro Carvalho Chehab 
38299a0bf528SMauro Carvalho Chehab 		/* set new i2c address and force divstart */
38309a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
38319a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
38329a0bf528SMauro Carvalho Chehab 		dib8000_identify(&client);
38339a0bf528SMauro Carvalho Chehab 
38349a0bf528SMauro Carvalho Chehab 		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
38359a0bf528SMauro Carvalho Chehab 	}
38369a0bf528SMauro Carvalho Chehab 
38379a0bf528SMauro Carvalho Chehab 	for (k = 0; k < no_of_demods; k++) {
38389a0bf528SMauro Carvalho Chehab 		new_addr = first_addr | (k << 1);
38399a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
38409a0bf528SMauro Carvalho Chehab 
38419a0bf528SMauro Carvalho Chehab 		// unforce divstr
38429a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1285, new_addr << 2);
38439a0bf528SMauro Carvalho Chehab 
38449a0bf528SMauro Carvalho Chehab 		/* deactivate div - it was just for i2c-enumeration */
38459a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1286, 0);
38469a0bf528SMauro Carvalho Chehab 	}
38479a0bf528SMauro Carvalho Chehab 
38489a0bf528SMauro Carvalho Chehab error:
38499a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_buffer_lock);
38509a0bf528SMauro Carvalho Chehab error_memory_lock:
38519a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_read_buffer);
38529a0bf528SMauro Carvalho Chehab error_memory_read:
38539a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_write_buffer);
38549a0bf528SMauro Carvalho Chehab 
38559a0bf528SMauro Carvalho Chehab 	return ret;
38569a0bf528SMauro Carvalho Chehab }
38579a0bf528SMauro Carvalho Chehab 
38589a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_i2c_enumeration);
38599a0bf528SMauro Carvalho Chehab static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
38609a0bf528SMauro Carvalho Chehab {
38619a0bf528SMauro Carvalho Chehab 	tune->min_delay_ms = 1000;
38629a0bf528SMauro Carvalho Chehab 	tune->step_size = 0;
38639a0bf528SMauro Carvalho Chehab 	tune->max_drift = 0;
38649a0bf528SMauro Carvalho Chehab 	return 0;
38659a0bf528SMauro Carvalho Chehab }
38669a0bf528SMauro Carvalho Chehab 
38679a0bf528SMauro Carvalho Chehab static void dib8000_release(struct dvb_frontend *fe)
38689a0bf528SMauro Carvalho Chehab {
38699a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
38709a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
38719a0bf528SMauro Carvalho Chehab 
38729a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
38739a0bf528SMauro Carvalho Chehab 		dvb_frontend_detach(st->fe[index_frontend]);
38749a0bf528SMauro Carvalho Chehab 
38759a0bf528SMauro Carvalho Chehab 	dibx000_exit_i2c_master(&st->i2c_master);
38769a0bf528SMauro Carvalho Chehab 	i2c_del_adapter(&st->dib8096p_tuner_adap);
38779a0bf528SMauro Carvalho Chehab 	kfree(st->fe[0]);
38789a0bf528SMauro Carvalho Chehab 	kfree(st);
38799a0bf528SMauro Carvalho Chehab }
38809a0bf528SMauro Carvalho Chehab 
38819a0bf528SMauro Carvalho Chehab struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
38829a0bf528SMauro Carvalho Chehab {
38839a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
38849a0bf528SMauro Carvalho Chehab 	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
38859a0bf528SMauro Carvalho Chehab }
38869a0bf528SMauro Carvalho Chehab 
38879a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_get_i2c_master);
38889a0bf528SMauro Carvalho Chehab 
38899a0bf528SMauro Carvalho Chehab int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
38909a0bf528SMauro Carvalho Chehab {
38919a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
38929a0bf528SMauro Carvalho Chehab 	u16 val = dib8000_read_word(st, 299) & 0xffef;
38939a0bf528SMauro Carvalho Chehab 	val |= (onoff & 0x1) << 4;
38949a0bf528SMauro Carvalho Chehab 
38959a0bf528SMauro Carvalho Chehab 	dprintk("pid filter enabled %d", onoff);
38969a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(st, 299, val);
38979a0bf528SMauro Carvalho Chehab }
38989a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_pid_filter_ctrl);
38999a0bf528SMauro Carvalho Chehab 
39009a0bf528SMauro Carvalho Chehab int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
39019a0bf528SMauro Carvalho Chehab {
39029a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
39039a0bf528SMauro Carvalho Chehab 	dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
39049a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
39059a0bf528SMauro Carvalho Chehab }
39069a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_pid_filter);
39079a0bf528SMauro Carvalho Chehab 
39089a0bf528SMauro Carvalho Chehab static const struct dvb_frontend_ops dib8000_ops = {
39099a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ISDBT },
39109a0bf528SMauro Carvalho Chehab 	.info = {
39119a0bf528SMauro Carvalho Chehab 		 .name = "DiBcom 8000 ISDB-T",
39129a0bf528SMauro Carvalho Chehab 		 .frequency_min = 44250000,
39139a0bf528SMauro Carvalho Chehab 		 .frequency_max = 867250000,
39149a0bf528SMauro Carvalho Chehab 		 .frequency_stepsize = 62500,
39159a0bf528SMauro Carvalho Chehab 		 .caps = FE_CAN_INVERSION_AUTO |
39169a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
39179a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
39189a0bf528SMauro Carvalho Chehab 		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
39199a0bf528SMauro Carvalho Chehab 		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
39209a0bf528SMauro Carvalho Chehab 		 },
39219a0bf528SMauro Carvalho Chehab 
39229a0bf528SMauro Carvalho Chehab 	.release = dib8000_release,
39239a0bf528SMauro Carvalho Chehab 
39249a0bf528SMauro Carvalho Chehab 	.init = dib8000_wakeup,
39259a0bf528SMauro Carvalho Chehab 	.sleep = dib8000_sleep,
39269a0bf528SMauro Carvalho Chehab 
39279a0bf528SMauro Carvalho Chehab 	.set_frontend = dib8000_set_frontend,
39289a0bf528SMauro Carvalho Chehab 	.get_tune_settings = dib8000_fe_get_tune_settings,
39299a0bf528SMauro Carvalho Chehab 	.get_frontend = dib8000_get_frontend,
39309a0bf528SMauro Carvalho Chehab 
39319a0bf528SMauro Carvalho Chehab 	.read_status = dib8000_read_status,
39329a0bf528SMauro Carvalho Chehab 	.read_ber = dib8000_read_ber,
39339a0bf528SMauro Carvalho Chehab 	.read_signal_strength = dib8000_read_signal_strength,
39349a0bf528SMauro Carvalho Chehab 	.read_snr = dib8000_read_snr,
39359a0bf528SMauro Carvalho Chehab 	.read_ucblocks = dib8000_read_unc_blocks,
39369a0bf528SMauro Carvalho Chehab };
39379a0bf528SMauro Carvalho Chehab 
39389a0bf528SMauro Carvalho Chehab struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
39399a0bf528SMauro Carvalho Chehab {
39409a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *fe;
39419a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state;
39429a0bf528SMauro Carvalho Chehab 
39439a0bf528SMauro Carvalho Chehab 	dprintk("dib8000_attach");
39449a0bf528SMauro Carvalho Chehab 
39459a0bf528SMauro Carvalho Chehab 	state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
39469a0bf528SMauro Carvalho Chehab 	if (state == NULL)
39479a0bf528SMauro Carvalho Chehab 		return NULL;
39489a0bf528SMauro Carvalho Chehab 	fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
39499a0bf528SMauro Carvalho Chehab 	if (fe == NULL)
39509a0bf528SMauro Carvalho Chehab 		goto error;
39519a0bf528SMauro Carvalho Chehab 
39529a0bf528SMauro Carvalho Chehab 	memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
39539a0bf528SMauro Carvalho Chehab 	state->i2c.adap = i2c_adap;
39549a0bf528SMauro Carvalho Chehab 	state->i2c.addr = i2c_addr;
39559a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_write_buffer = state->i2c_write_buffer;
39569a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_read_buffer = state->i2c_read_buffer;
39579a0bf528SMauro Carvalho Chehab 	mutex_init(&state->i2c_buffer_lock);
39589a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
39599a0bf528SMauro Carvalho Chehab 	state->gpio_val = cfg->gpio_val;
39609a0bf528SMauro Carvalho Chehab 	state->gpio_dir = cfg->gpio_dir;
39619a0bf528SMauro Carvalho Chehab 
39629a0bf528SMauro Carvalho Chehab 	/* Ensure the output mode remains at the previous default if it's
39639a0bf528SMauro Carvalho Chehab 	 * not specifically set by the caller.
39649a0bf528SMauro Carvalho Chehab 	 */
39659a0bf528SMauro Carvalho Chehab 	if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
39669a0bf528SMauro Carvalho Chehab 		state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
39679a0bf528SMauro Carvalho Chehab 
39689a0bf528SMauro Carvalho Chehab 	state->fe[0] = fe;
39699a0bf528SMauro Carvalho Chehab 	fe->demodulator_priv = state;
39709a0bf528SMauro Carvalho Chehab 	memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
39719a0bf528SMauro Carvalho Chehab 
39729a0bf528SMauro Carvalho Chehab 	state->timf_default = cfg->pll->timf;
39739a0bf528SMauro Carvalho Chehab 
39749a0bf528SMauro Carvalho Chehab 	if (dib8000_identify(&state->i2c) == 0)
39759a0bf528SMauro Carvalho Chehab 		goto error;
39769a0bf528SMauro Carvalho Chehab 
39779a0bf528SMauro Carvalho Chehab 	dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
39789a0bf528SMauro Carvalho Chehab 
39799a0bf528SMauro Carvalho Chehab 	/* init 8096p tuner adapter */
39809a0bf528SMauro Carvalho Chehab 	strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
39819a0bf528SMauro Carvalho Chehab 			sizeof(state->dib8096p_tuner_adap.name));
39829a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
39839a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.algo_data = NULL;
39849a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
39859a0bf528SMauro Carvalho Chehab 	i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
39869a0bf528SMauro Carvalho Chehab 	i2c_add_adapter(&state->dib8096p_tuner_adap);
39879a0bf528SMauro Carvalho Chehab 
39889a0bf528SMauro Carvalho Chehab 	dib8000_reset(fe);
39899a0bf528SMauro Carvalho Chehab 
39909a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));	/* ber_rs_len = 3 */
3991173a64cbSPatrick Boettcher 	state->current_demod_bw = 6000;
39929a0bf528SMauro Carvalho Chehab 
39939a0bf528SMauro Carvalho Chehab 	return fe;
39949a0bf528SMauro Carvalho Chehab 
39959a0bf528SMauro Carvalho Chehab error:
39969a0bf528SMauro Carvalho Chehab 	kfree(state);
39979a0bf528SMauro Carvalho Chehab 	return NULL;
39989a0bf528SMauro Carvalho Chehab }
39999a0bf528SMauro Carvalho Chehab 
40009a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_attach);
40019a0bf528SMauro Carvalho Chehab 
40029a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>");
40039a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
40049a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
4005