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>
14b4600d70SMauro Carvalho Chehab #include <asm/div64.h>
159a0bf528SMauro Carvalho Chehab 
169a0bf528SMauro Carvalho Chehab #include "dvb_math.h"
179a0bf528SMauro Carvalho Chehab 
189a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h"
199a0bf528SMauro Carvalho Chehab 
209a0bf528SMauro Carvalho Chehab #include "dib8000.h"
219a0bf528SMauro Carvalho Chehab 
229a0bf528SMauro Carvalho Chehab #define LAYER_ALL -1
239a0bf528SMauro Carvalho Chehab #define LAYER_A   1
249a0bf528SMauro Carvalho Chehab #define LAYER_B   2
259a0bf528SMauro Carvalho Chehab #define LAYER_C   3
269a0bf528SMauro Carvalho Chehab 
279a0bf528SMauro Carvalho Chehab #define MAX_NUMBER_OF_FRONTENDS 6
28173a64cbSPatrick Boettcher /* #define DIB8000_AGC_FREEZE */
299a0bf528SMauro Carvalho Chehab 
309a0bf528SMauro Carvalho Chehab static int debug;
319a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
329a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
339a0bf528SMauro Carvalho Chehab 
349a0bf528SMauro Carvalho Chehab #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0)
359a0bf528SMauro Carvalho Chehab 
369a0bf528SMauro Carvalho Chehab struct i2c_device {
379a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *adap;
389a0bf528SMauro Carvalho Chehab 	u8 addr;
399a0bf528SMauro Carvalho Chehab 	u8 *i2c_write_buffer;
409a0bf528SMauro Carvalho Chehab 	u8 *i2c_read_buffer;
419a0bf528SMauro Carvalho Chehab 	struct mutex *i2c_buffer_lock;
429a0bf528SMauro Carvalho Chehab };
439a0bf528SMauro Carvalho Chehab 
44173a64cbSPatrick Boettcher enum param_loop_step {
45173a64cbSPatrick Boettcher 	LOOP_TUNE_1,
46173a64cbSPatrick Boettcher 	LOOP_TUNE_2
47173a64cbSPatrick Boettcher };
48173a64cbSPatrick Boettcher 
49173a64cbSPatrick Boettcher enum dib8000_autosearch_step {
50173a64cbSPatrick Boettcher 	AS_START = 0,
51173a64cbSPatrick Boettcher 	AS_SEARCHING_FFT,
52173a64cbSPatrick Boettcher 	AS_SEARCHING_GUARD,
53173a64cbSPatrick Boettcher 	AS_DONE = 100,
54173a64cbSPatrick Boettcher };
55173a64cbSPatrick Boettcher 
56173a64cbSPatrick Boettcher enum timeout_mode {
57173a64cbSPatrick Boettcher 	SYMBOL_DEPENDENT_OFF = 0,
58173a64cbSPatrick Boettcher 	SYMBOL_DEPENDENT_ON,
59173a64cbSPatrick Boettcher };
60173a64cbSPatrick Boettcher 
619a0bf528SMauro Carvalho Chehab struct dib8000_state {
629a0bf528SMauro Carvalho Chehab 	struct dib8000_config cfg;
639a0bf528SMauro Carvalho Chehab 
649a0bf528SMauro Carvalho Chehab 	struct i2c_device i2c;
659a0bf528SMauro Carvalho Chehab 
669a0bf528SMauro Carvalho Chehab 	struct dibx000_i2c_master i2c_master;
679a0bf528SMauro Carvalho Chehab 
689a0bf528SMauro Carvalho Chehab 	u16 wbd_ref;
699a0bf528SMauro Carvalho Chehab 
709a0bf528SMauro Carvalho Chehab 	u8 current_band;
719a0bf528SMauro Carvalho Chehab 	u32 current_bandwidth;
729a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *current_agc;
739a0bf528SMauro Carvalho Chehab 	u32 timf;
749a0bf528SMauro Carvalho Chehab 	u32 timf_default;
759a0bf528SMauro Carvalho Chehab 
769a0bf528SMauro Carvalho Chehab 	u8 div_force_off:1;
779a0bf528SMauro Carvalho Chehab 	u8 div_state:1;
789a0bf528SMauro Carvalho Chehab 	u16 div_sync_wait;
799a0bf528SMauro Carvalho Chehab 
809a0bf528SMauro Carvalho Chehab 	u8 agc_state;
819a0bf528SMauro Carvalho Chehab 	u8 differential_constellation;
829a0bf528SMauro Carvalho Chehab 	u8 diversity_onoff;
839a0bf528SMauro Carvalho Chehab 
849a0bf528SMauro Carvalho Chehab 	s16 ber_monitored_layer;
859a0bf528SMauro Carvalho Chehab 	u16 gpio_dir;
869a0bf528SMauro Carvalho Chehab 	u16 gpio_val;
879a0bf528SMauro Carvalho Chehab 
889a0bf528SMauro Carvalho Chehab 	u16 revision;
899a0bf528SMauro Carvalho Chehab 	u8 isdbt_cfg_loaded;
909a0bf528SMauro Carvalho Chehab 	enum frontend_tune_state tune_state;
91173a64cbSPatrick Boettcher 	s32 status;
929a0bf528SMauro Carvalho Chehab 
939a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
949a0bf528SMauro Carvalho Chehab 
959a0bf528SMauro Carvalho Chehab 	/* for the I2C transfer */
969a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2];
979a0bf528SMauro Carvalho Chehab 	u8 i2c_write_buffer[4];
989a0bf528SMauro Carvalho Chehab 	u8 i2c_read_buffer[2];
999a0bf528SMauro Carvalho Chehab 	struct mutex i2c_buffer_lock;
1009a0bf528SMauro Carvalho Chehab 	u8 input_mode_mpeg;
1019a0bf528SMauro Carvalho Chehab 
1029a0bf528SMauro Carvalho Chehab 	u16 tuner_enable;
1039a0bf528SMauro Carvalho Chehab 	struct i2c_adapter dib8096p_tuner_adap;
104173a64cbSPatrick Boettcher 	u16 current_demod_bw;
105173a64cbSPatrick Boettcher 
106173a64cbSPatrick Boettcher 	u16 seg_mask;
107173a64cbSPatrick Boettcher 	u16 seg_diff_mask;
108173a64cbSPatrick Boettcher 	u16 mode;
109173a64cbSPatrick Boettcher 	u8 layer_b_nb_seg;
110173a64cbSPatrick Boettcher 	u8 layer_c_nb_seg;
111173a64cbSPatrick Boettcher 
112173a64cbSPatrick Boettcher 	u8 channel_parameters_set;
113173a64cbSPatrick Boettcher 	u16 autosearch_state;
114173a64cbSPatrick Boettcher 	u16 found_nfft;
115173a64cbSPatrick Boettcher 	u16 found_guard;
116173a64cbSPatrick Boettcher 	u8 subchannel;
117173a64cbSPatrick Boettcher 	u8 symbol_duration;
118173a64cbSPatrick Boettcher 	u32 timeout;
119173a64cbSPatrick Boettcher 	u8 longest_intlv_layer;
120173a64cbSPatrick Boettcher 	u16 output_mode;
121173a64cbSPatrick Boettcher 
122704f01bbSMauro Carvalho Chehab 	/* for DVBv5 stats */
1237a9d85d5SMauro Carvalho Chehab 	s64 init_ucb;
1240400c535SMauro Carvalho Chehab 	unsigned long per_jiffies_stats;
1250400c535SMauro Carvalho Chehab 	unsigned long ber_jiffies_stats;
1260400c535SMauro Carvalho Chehab 	unsigned long ber_jiffies_stats_layer[3];
127704f01bbSMauro Carvalho Chehab 
128173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
129173a64cbSPatrick Boettcher 	u16 agc1_max;
130173a64cbSPatrick Boettcher 	u16 agc1_min;
131173a64cbSPatrick Boettcher 	u16 agc2_max;
132173a64cbSPatrick Boettcher 	u16 agc2_min;
133173a64cbSPatrick Boettcher #endif
1349a0bf528SMauro Carvalho Chehab };
1359a0bf528SMauro Carvalho Chehab 
1369a0bf528SMauro Carvalho Chehab enum dib8000_power_mode {
1379a0bf528SMauro Carvalho Chehab 	DIB8000_POWER_ALL = 0,
1389a0bf528SMauro Carvalho Chehab 	DIB8000_POWER_INTERFACE_ONLY,
1399a0bf528SMauro Carvalho Chehab };
1409a0bf528SMauro Carvalho Chehab 
1419a0bf528SMauro Carvalho Chehab static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
1429a0bf528SMauro Carvalho Chehab {
1439a0bf528SMauro Carvalho Chehab 	u16 ret;
1449a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2] = {
1459a0bf528SMauro Carvalho Chehab 		{.addr = i2c->addr >> 1, .flags = 0, .len = 2},
1469a0bf528SMauro Carvalho Chehab 		{.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
1479a0bf528SMauro Carvalho Chehab 	};
1489a0bf528SMauro Carvalho Chehab 
1499a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
1509a0bf528SMauro Carvalho Chehab 		dprintk("could not acquire lock");
1519a0bf528SMauro Carvalho Chehab 		return 0;
1529a0bf528SMauro Carvalho Chehab 	}
1539a0bf528SMauro Carvalho Chehab 
1549a0bf528SMauro Carvalho Chehab 	msg[0].buf    = i2c->i2c_write_buffer;
1559a0bf528SMauro Carvalho Chehab 	msg[0].buf[0] = reg >> 8;
1569a0bf528SMauro Carvalho Chehab 	msg[0].buf[1] = reg & 0xff;
1579a0bf528SMauro Carvalho Chehab 	msg[1].buf    = i2c->i2c_read_buffer;
1589a0bf528SMauro Carvalho Chehab 
1599a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(i2c->adap, msg, 2) != 2)
1609a0bf528SMauro Carvalho Chehab 		dprintk("i2c read error on %d", reg);
1619a0bf528SMauro Carvalho Chehab 
1629a0bf528SMauro Carvalho Chehab 	ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
1639a0bf528SMauro Carvalho Chehab 	mutex_unlock(i2c->i2c_buffer_lock);
1649a0bf528SMauro Carvalho Chehab 	return ret;
1659a0bf528SMauro Carvalho Chehab }
1669a0bf528SMauro Carvalho Chehab 
1675ac64ba1SMauro Carvalho Chehab static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg)
1689a0bf528SMauro Carvalho Chehab {
1699a0bf528SMauro Carvalho Chehab 	u16 ret;
1709a0bf528SMauro Carvalho Chehab 
1719a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = reg >> 8;
1729a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
1739a0bf528SMauro Carvalho Chehab 
1749a0bf528SMauro Carvalho Chehab 	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
1759a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c.addr >> 1;
1769a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
1779a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
1789a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 2;
1799a0bf528SMauro Carvalho Chehab 	state->msg[1].addr = state->i2c.addr >> 1;
1809a0bf528SMauro Carvalho Chehab 	state->msg[1].flags = I2C_M_RD;
1819a0bf528SMauro Carvalho Chehab 	state->msg[1].buf = state->i2c_read_buffer;
1829a0bf528SMauro Carvalho Chehab 	state->msg[1].len = 2;
1839a0bf528SMauro Carvalho Chehab 
1849a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
1859a0bf528SMauro Carvalho Chehab 		dprintk("i2c read error on %d", reg);
1869a0bf528SMauro Carvalho Chehab 
1879a0bf528SMauro Carvalho Chehab 	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
1885ac64ba1SMauro Carvalho Chehab 
1895ac64ba1SMauro Carvalho Chehab 	return ret;
1905ac64ba1SMauro Carvalho Chehab }
1915ac64ba1SMauro Carvalho Chehab 
1925ac64ba1SMauro Carvalho Chehab static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
1935ac64ba1SMauro Carvalho Chehab {
1945ac64ba1SMauro Carvalho Chehab 	u16 ret;
1955ac64ba1SMauro Carvalho Chehab 
1965ac64ba1SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
1975ac64ba1SMauro Carvalho Chehab 		dprintk("could not acquire lock");
1985ac64ba1SMauro Carvalho Chehab 		return 0;
1995ac64ba1SMauro Carvalho Chehab 	}
2005ac64ba1SMauro Carvalho Chehab 
2015ac64ba1SMauro Carvalho Chehab 	ret = __dib8000_read_word(state, reg);
2025ac64ba1SMauro Carvalho Chehab 
2039a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
2049a0bf528SMauro Carvalho Chehab 
2059a0bf528SMauro Carvalho Chehab 	return ret;
2069a0bf528SMauro Carvalho Chehab }
2079a0bf528SMauro Carvalho Chehab 
2089a0bf528SMauro Carvalho Chehab static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
2099a0bf528SMauro Carvalho Chehab {
2109a0bf528SMauro Carvalho Chehab 	u16 rw[2];
2119a0bf528SMauro Carvalho Chehab 
2125ac64ba1SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2135ac64ba1SMauro Carvalho Chehab 		dprintk("could not acquire lock");
2145ac64ba1SMauro Carvalho Chehab 		return 0;
2155ac64ba1SMauro Carvalho Chehab 	}
2165ac64ba1SMauro Carvalho Chehab 
2175ac64ba1SMauro Carvalho Chehab 	rw[0] = __dib8000_read_word(state, reg + 0);
2185ac64ba1SMauro Carvalho Chehab 	rw[1] = __dib8000_read_word(state, reg + 1);
2195ac64ba1SMauro Carvalho Chehab 
2205ac64ba1SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
2219a0bf528SMauro Carvalho Chehab 
2229a0bf528SMauro Carvalho Chehab 	return ((rw[0] << 16) | (rw[1]));
2239a0bf528SMauro Carvalho Chehab }
2249a0bf528SMauro Carvalho Chehab 
2259a0bf528SMauro Carvalho Chehab static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
2269a0bf528SMauro Carvalho Chehab {
2279a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
2289a0bf528SMauro Carvalho Chehab 	int ret = 0;
2299a0bf528SMauro Carvalho Chehab 
2309a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
2319a0bf528SMauro Carvalho Chehab 		dprintk("could not acquire lock");
2329a0bf528SMauro Carvalho Chehab 		return -EINVAL;
2339a0bf528SMauro Carvalho Chehab 	}
2349a0bf528SMauro Carvalho Chehab 
2359a0bf528SMauro Carvalho Chehab 	msg.buf    = i2c->i2c_write_buffer;
2369a0bf528SMauro Carvalho Chehab 	msg.buf[0] = (reg >> 8) & 0xff;
2379a0bf528SMauro Carvalho Chehab 	msg.buf[1] = reg & 0xff;
2389a0bf528SMauro Carvalho Chehab 	msg.buf[2] = (val >> 8) & 0xff;
2399a0bf528SMauro Carvalho Chehab 	msg.buf[3] = val & 0xff;
2409a0bf528SMauro Carvalho Chehab 
2419a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
2429a0bf528SMauro Carvalho Chehab 	mutex_unlock(i2c->i2c_buffer_lock);
2439a0bf528SMauro Carvalho Chehab 
2449a0bf528SMauro Carvalho Chehab 	return ret;
2459a0bf528SMauro Carvalho Chehab }
2469a0bf528SMauro Carvalho Chehab 
2479a0bf528SMauro Carvalho Chehab static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
2489a0bf528SMauro Carvalho Chehab {
2499a0bf528SMauro Carvalho Chehab 	int ret;
2509a0bf528SMauro Carvalho Chehab 
2519a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2529a0bf528SMauro Carvalho Chehab 		dprintk("could not acquire lock");
2539a0bf528SMauro Carvalho Chehab 		return -EINVAL;
2549a0bf528SMauro Carvalho Chehab 	}
2559a0bf528SMauro Carvalho Chehab 
2569a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
2579a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
2589a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
2599a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[3] = val & 0xff;
2609a0bf528SMauro Carvalho Chehab 
2619a0bf528SMauro Carvalho Chehab 	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
2629a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c.addr >> 1;
2639a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
2649a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
2659a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 4;
2669a0bf528SMauro Carvalho Chehab 
2679a0bf528SMauro Carvalho Chehab 	ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
2689a0bf528SMauro Carvalho Chehab 			-EREMOTEIO : 0);
2699a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
2709a0bf528SMauro Carvalho Chehab 
2719a0bf528SMauro Carvalho Chehab 	return ret;
2729a0bf528SMauro Carvalho Chehab }
2739a0bf528SMauro Carvalho Chehab 
2749a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
2759a0bf528SMauro Carvalho Chehab 	(769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c,
2769a0bf528SMauro Carvalho Chehab 		(920 << 5) | 0x09
2779a0bf528SMauro Carvalho Chehab };
2789a0bf528SMauro Carvalho Chehab 
2799a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg[8] = {
2809a0bf528SMauro Carvalho Chehab 	(692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
2819a0bf528SMauro Carvalho Chehab };
2829a0bf528SMauro Carvalho Chehab 
2839a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
2849a0bf528SMauro Carvalho Chehab 	(832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11,
2859a0bf528SMauro Carvalho Chehab 		(-931 << 5) | 0x0f
2869a0bf528SMauro Carvalho Chehab };
2879a0bf528SMauro Carvalho Chehab 
2889a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
2899a0bf528SMauro Carvalho Chehab 	(622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e,
2909a0bf528SMauro Carvalho Chehab 		(982 << 5) | 0x0c
2919a0bf528SMauro Carvalho Chehab };
2929a0bf528SMauro Carvalho Chehab 
2939a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
2949a0bf528SMauro Carvalho Chehab 	(699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12,
2959a0bf528SMauro Carvalho Chehab 		(-720 << 5) | 0x0d
2969a0bf528SMauro Carvalho Chehab };
2979a0bf528SMauro Carvalho Chehab 
2989a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg[8] = {
2999a0bf528SMauro Carvalho Chehab 	(664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e,
3009a0bf528SMauro Carvalho Chehab 		(-610 << 5) | 0x0a
3019a0bf528SMauro Carvalho Chehab };
3029a0bf528SMauro Carvalho Chehab 
3039a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
3049a0bf528SMauro Carvalho Chehab 	(-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f,
3059a0bf528SMauro Carvalho Chehab 		(-922 << 5) | 0x0d
3069a0bf528SMauro Carvalho Chehab };
3079a0bf528SMauro Carvalho Chehab 
3089a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg[8] = {
3099a0bf528SMauro Carvalho Chehab 	(638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d,
3109a0bf528SMauro Carvalho Chehab 		(-655 << 5) | 0x0a
3119a0bf528SMauro Carvalho Chehab };
3129a0bf528SMauro Carvalho Chehab 
3139a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
3149a0bf528SMauro Carvalho Chehab 	(-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14,
3159a0bf528SMauro Carvalho Chehab 		(-958 << 5) | 0x13
3169a0bf528SMauro Carvalho Chehab };
3179a0bf528SMauro Carvalho Chehab 
3189a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
3199a0bf528SMauro Carvalho Chehab 	(-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12,
3209a0bf528SMauro Carvalho Chehab 		(-568 << 5) | 0x0f
3219a0bf528SMauro Carvalho Chehab };
3229a0bf528SMauro Carvalho Chehab 
3239a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
3249a0bf528SMauro Carvalho Chehab 	(-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14,
3259a0bf528SMauro Carvalho Chehab 		(-848 << 5) | 0x13
3269a0bf528SMauro Carvalho Chehab };
3279a0bf528SMauro Carvalho Chehab 
3289a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg[8] = {
3299a0bf528SMauro Carvalho Chehab 	(612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12,
3309a0bf528SMauro Carvalho Chehab 		(-869 << 5) | 0x13
3319a0bf528SMauro Carvalho Chehab };
3329a0bf528SMauro Carvalho Chehab 
3339a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
3349a0bf528SMauro Carvalho Chehab 	(-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13,
3359a0bf528SMauro Carvalho Chehab 		(-598 << 5) | 0x10
3369a0bf528SMauro Carvalho Chehab };
3379a0bf528SMauro Carvalho Chehab 
3389a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg[8] = {
3399a0bf528SMauro Carvalho Chehab 	(673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f,
3409a0bf528SMauro Carvalho Chehab 		(585 << 5) | 0x0f
3419a0bf528SMauro Carvalho Chehab };
3429a0bf528SMauro Carvalho Chehab 
3439a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
3449a0bf528SMauro Carvalho Chehab 	(863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18,
3459a0bf528SMauro Carvalho Chehab 		(0 << 5) | 0x14
3469a0bf528SMauro Carvalho Chehab };
3479a0bf528SMauro Carvalho Chehab 
3489a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
3499a0bf528SMauro Carvalho Chehab 	(-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15,
3509a0bf528SMauro Carvalho Chehab 		(-877 << 5) | 0x15
3519a0bf528SMauro Carvalho Chehab };
3529a0bf528SMauro Carvalho Chehab 
3539a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
3549a0bf528SMauro Carvalho Chehab 	(-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18,
3559a0bf528SMauro Carvalho Chehab 		(-921 << 5) | 0x14
3569a0bf528SMauro Carvalho Chehab };
3579a0bf528SMauro Carvalho Chehab 
3589a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg[8] = {
3599a0bf528SMauro Carvalho Chehab 	(514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15,
3609a0bf528SMauro Carvalho Chehab 		(690 << 5) | 0x14
3619a0bf528SMauro Carvalho Chehab };
3629a0bf528SMauro Carvalho Chehab 
3639a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_3seg[24] = {
3649a0bf528SMauro 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
3659a0bf528SMauro Carvalho Chehab };
3669a0bf528SMauro Carvalho Chehab 
3679a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_1seg[24] = {
3689a0bf528SMauro 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
3699a0bf528SMauro Carvalho Chehab };
3709a0bf528SMauro Carvalho Chehab 
3719a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_13seg[24] = {
3729a0bf528SMauro 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
3739a0bf528SMauro Carvalho Chehab };
3749a0bf528SMauro Carvalho Chehab 
3759a0bf528SMauro Carvalho Chehab static u16 fft_to_mode(struct dib8000_state *state)
3769a0bf528SMauro Carvalho Chehab {
3779a0bf528SMauro Carvalho Chehab 	u16 mode;
3789a0bf528SMauro Carvalho Chehab 	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
3799a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
3809a0bf528SMauro Carvalho Chehab 		mode = 1;
3819a0bf528SMauro Carvalho Chehab 		break;
3829a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
3839a0bf528SMauro Carvalho Chehab 		mode = 2;
3849a0bf528SMauro Carvalho Chehab 		break;
3859a0bf528SMauro Carvalho Chehab 	default:
3869a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_AUTO:
3879a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
3889a0bf528SMauro Carvalho Chehab 		mode = 3;
3899a0bf528SMauro Carvalho Chehab 		break;
3909a0bf528SMauro Carvalho Chehab 	}
3919a0bf528SMauro Carvalho Chehab 	return mode;
3929a0bf528SMauro Carvalho Chehab }
3939a0bf528SMauro Carvalho Chehab 
3949a0bf528SMauro Carvalho Chehab static void dib8000_set_acquisition_mode(struct dib8000_state *state)
3959a0bf528SMauro Carvalho Chehab {
3969a0bf528SMauro Carvalho Chehab 	u16 nud = dib8000_read_word(state, 298);
3979a0bf528SMauro Carvalho Chehab 	nud |= (1 << 3) | (1 << 0);
3989a0bf528SMauro Carvalho Chehab 	dprintk("acquisition mode activated");
3999a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 298, nud);
4009a0bf528SMauro Carvalho Chehab }
4019a0bf528SMauro Carvalho Chehab static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
4029a0bf528SMauro Carvalho Chehab {
4039a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
4049a0bf528SMauro Carvalho Chehab 	u16 outreg, fifo_threshold, smo_mode, sram = 0x0205;	/* by default SDRAM deintlv is enabled */
4059a0bf528SMauro Carvalho Chehab 
406173a64cbSPatrick Boettcher 	state->output_mode = mode;
4079a0bf528SMauro Carvalho Chehab 	outreg = 0;
4089a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
4099a0bf528SMauro Carvalho Chehab 	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
4109a0bf528SMauro Carvalho Chehab 
4119a0bf528SMauro Carvalho Chehab 	dprintk("-I-	Setting output mode for demod %p to %d",
4129a0bf528SMauro Carvalho Chehab 			&state->fe[0], mode);
4139a0bf528SMauro Carvalho Chehab 
4149a0bf528SMauro Carvalho Chehab 	switch (mode) {
4159a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:	// STBs with parallel gated clock
4169a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10);	/* 0x0400 */
4179a0bf528SMauro Carvalho Chehab 		break;
4189a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK:	// STBs with parallel continues clock
4199a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (1 << 6);	/* 0x0440 */
4209a0bf528SMauro Carvalho Chehab 		break;
4219a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:	// STBs with serial input
4229a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (2 << 6) | (0 << 1);	/* 0x0482 */
4239a0bf528SMauro Carvalho Chehab 		break;
4249a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
4259a0bf528SMauro Carvalho Chehab 		if (state->cfg.hostbus_diversity) {
4269a0bf528SMauro Carvalho Chehab 			outreg = (1 << 10) | (4 << 6);	/* 0x0500 */
4279a0bf528SMauro Carvalho Chehab 			sram &= 0xfdff;
4289a0bf528SMauro Carvalho Chehab 		} else
4299a0bf528SMauro Carvalho Chehab 			sram |= 0x0c00;
4309a0bf528SMauro Carvalho Chehab 		break;
4319a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:	// e.g. USB feeding
4329a0bf528SMauro Carvalho Chehab 		smo_mode |= (3 << 1);
4339a0bf528SMauro Carvalho Chehab 		fifo_threshold = 512;
4349a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (5 << 6);
4359a0bf528SMauro Carvalho Chehab 		break;
4369a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:	// disable
4379a0bf528SMauro Carvalho Chehab 		outreg = 0;
4389a0bf528SMauro Carvalho Chehab 		break;
4399a0bf528SMauro Carvalho Chehab 
4409a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
4419a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (3 << 6);
4429a0bf528SMauro Carvalho Chehab 		dib8000_set_acquisition_mode(state);
4439a0bf528SMauro Carvalho Chehab 		break;
4449a0bf528SMauro Carvalho Chehab 
4459a0bf528SMauro Carvalho Chehab 	default:
4469a0bf528SMauro Carvalho Chehab 		dprintk("Unhandled output_mode passed to be set for demod %p",
4479a0bf528SMauro Carvalho Chehab 				&state->fe[0]);
4489a0bf528SMauro Carvalho Chehab 		return -EINVAL;
4499a0bf528SMauro Carvalho Chehab 	}
4509a0bf528SMauro Carvalho Chehab 
4519a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
4529a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
4539a0bf528SMauro Carvalho Chehab 
4549a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 299, smo_mode);
4559a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 300, fifo_threshold);	/* synchronous fread */
4569a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1286, outreg);
4579a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1291, sram);
4589a0bf528SMauro Carvalho Chehab 
4599a0bf528SMauro Carvalho Chehab 	return 0;
4609a0bf528SMauro Carvalho Chehab }
4619a0bf528SMauro Carvalho Chehab 
4629a0bf528SMauro Carvalho Chehab static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
4639a0bf528SMauro Carvalho Chehab {
4649a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
465173a64cbSPatrick Boettcher 	u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0;
4669a0bf528SMauro Carvalho Chehab 
467173a64cbSPatrick Boettcher 	dprintk("set diversity input to %i", onoff);
4689a0bf528SMauro Carvalho Chehab 	if (!state->differential_constellation) {
4699a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 272, 1 << 9);	//dvsy_off_lmod4 = 1
4709a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2);	// sync_enable = 1; comb_mode = 2
4719a0bf528SMauro Carvalho Chehab 	} else {
4729a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 272, 0);	//dvsy_off_lmod4 = 0
4739a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 273, sync_wait);	// sync_enable = 0; comb_mode = 0
4749a0bf528SMauro Carvalho Chehab 	}
4759a0bf528SMauro Carvalho Chehab 	state->diversity_onoff = onoff;
4769a0bf528SMauro Carvalho Chehab 
4779a0bf528SMauro Carvalho Chehab 	switch (onoff) {
4789a0bf528SMauro Carvalho Chehab 	case 0:		/* only use the internal way - not the diversity input */
4799a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 270, 1);
4809a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 271, 0);
4819a0bf528SMauro Carvalho Chehab 		break;
4829a0bf528SMauro Carvalho Chehab 	case 1:		/* both ways */
4839a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 270, 6);
4849a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 271, 6);
4859a0bf528SMauro Carvalho Chehab 		break;
4869a0bf528SMauro Carvalho Chehab 	case 2:		/* only the diversity input */
4879a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 270, 0);
4889a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 271, 1);
4899a0bf528SMauro Carvalho Chehab 		break;
4909a0bf528SMauro Carvalho Chehab 	}
491173a64cbSPatrick Boettcher 
492173a64cbSPatrick Boettcher 	if (state->revision == 0x8002) {
493173a64cbSPatrick Boettcher 		tmp = dib8000_read_word(state, 903);
494173a64cbSPatrick Boettcher 		dib8000_write_word(state, 903, tmp & ~(1 << 3));
495173a64cbSPatrick Boettcher 		msleep(30);
496173a64cbSPatrick Boettcher 		dib8000_write_word(state, 903, tmp | (1 << 3));
497173a64cbSPatrick Boettcher 	}
4989a0bf528SMauro Carvalho Chehab 	return 0;
4999a0bf528SMauro Carvalho Chehab }
5009a0bf528SMauro Carvalho Chehab 
5019a0bf528SMauro Carvalho Chehab static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
5029a0bf528SMauro Carvalho Chehab {
5039a0bf528SMauro Carvalho Chehab 	/* by default everything is going to be powered off */
5049a0bf528SMauro Carvalho Chehab 	u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
5059a0bf528SMauro Carvalho Chehab 		reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
5069a0bf528SMauro Carvalho Chehab 		reg_1280;
5079a0bf528SMauro Carvalho Chehab 
5089a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
5099a0bf528SMauro Carvalho Chehab 		reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
5109a0bf528SMauro Carvalho Chehab 	else
5119a0bf528SMauro Carvalho Chehab 		reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80;
5129a0bf528SMauro Carvalho Chehab 
5139a0bf528SMauro Carvalho Chehab 	/* now, depending on the requested mode, we power on */
5149a0bf528SMauro Carvalho Chehab 	switch (mode) {
5159a0bf528SMauro Carvalho Chehab 		/* power up everything in the demod */
5169a0bf528SMauro Carvalho Chehab 	case DIB8000_POWER_ALL:
5179a0bf528SMauro Carvalho Chehab 		reg_774 = 0x0000;
5189a0bf528SMauro Carvalho Chehab 		reg_775 = 0x0000;
5199a0bf528SMauro Carvalho Chehab 		reg_776 = 0x0000;
5209a0bf528SMauro Carvalho Chehab 		reg_900 &= 0xfffc;
5219a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090)
5229a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x00ff;
5239a0bf528SMauro Carvalho Chehab 		else
5249a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x707f;
5259a0bf528SMauro Carvalho Chehab 		break;
5269a0bf528SMauro Carvalho Chehab 	case DIB8000_POWER_INTERFACE_ONLY:
5279a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090)
5289a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x00ff;
5299a0bf528SMauro Carvalho Chehab 		else
5309a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0xfa7b;
5319a0bf528SMauro Carvalho Chehab 		break;
5329a0bf528SMauro Carvalho Chehab 	}
5339a0bf528SMauro Carvalho Chehab 
5349a0bf528SMauro Carvalho Chehab 	dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280);
5359a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 774, reg_774);
5369a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 775, reg_775);
5379a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 776, reg_776);
5389a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 900, reg_900);
5399a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1280, reg_1280);
5409a0bf528SMauro Carvalho Chehab }
5419a0bf528SMauro Carvalho Chehab 
5429a0bf528SMauro Carvalho Chehab static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
5439a0bf528SMauro Carvalho Chehab {
5449a0bf528SMauro Carvalho Chehab 	int ret = 0;
5459a0bf528SMauro Carvalho Chehab 	u16 reg, reg_907 = dib8000_read_word(state, 907);
5469a0bf528SMauro Carvalho Chehab 	u16 reg_908 = dib8000_read_word(state, 908);
5479a0bf528SMauro Carvalho Chehab 
5489a0bf528SMauro Carvalho Chehab 	switch (no) {
5499a0bf528SMauro Carvalho Chehab 	case DIBX000_SLOW_ADC_ON:
5509a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090) {
5519a0bf528SMauro Carvalho Chehab 			reg_908 |= (1 << 1) | (1 << 0);
5529a0bf528SMauro Carvalho Chehab 			ret |= dib8000_write_word(state, 908, reg_908);
5539a0bf528SMauro Carvalho Chehab 			reg_908 &= ~(1 << 1);
5549a0bf528SMauro Carvalho Chehab 		} else {
5559a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1925);
5569a0bf528SMauro Carvalho Chehab 			/* en_slowAdc = 1 & reset_sladc = 1 */
5579a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1925, reg |
5589a0bf528SMauro Carvalho Chehab 					(1<<4) | (1<<2));
5599a0bf528SMauro Carvalho Chehab 
5609a0bf528SMauro Carvalho Chehab 			/* read acces to make it works... strange ... */
5619a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1925);
5629a0bf528SMauro Carvalho Chehab 			msleep(20);
5639a0bf528SMauro Carvalho Chehab 			/* en_slowAdc = 1 & reset_sladc = 0 */
5649a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1925, reg & ~(1<<4));
5659a0bf528SMauro Carvalho Chehab 
5669a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 921) & ~((0x3 << 14)
5679a0bf528SMauro Carvalho Chehab 					| (0x3 << 12));
5689a0bf528SMauro Carvalho Chehab 			/* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ;
5699a0bf528SMauro Carvalho Chehab 			   (Vin2 = Vcm) */
5709a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 921, reg | (1 << 14)
5719a0bf528SMauro Carvalho Chehab 					| (3 << 12));
5729a0bf528SMauro Carvalho Chehab 		}
5739a0bf528SMauro Carvalho Chehab 		break;
5749a0bf528SMauro Carvalho Chehab 
5759a0bf528SMauro Carvalho Chehab 	case DIBX000_SLOW_ADC_OFF:
5769a0bf528SMauro Carvalho Chehab 		if (state->revision == 0x8090) {
5779a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1925);
5789a0bf528SMauro Carvalho Chehab 			/* reset_sladc = 1 en_slowAdc = 0 */
5799a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1925,
5809a0bf528SMauro Carvalho Chehab 					(reg & ~(1<<2)) | (1<<4));
5819a0bf528SMauro Carvalho Chehab 		}
5829a0bf528SMauro Carvalho Chehab 		reg_908 |= (1 << 1) | (1 << 0);
5839a0bf528SMauro Carvalho Chehab 		break;
5849a0bf528SMauro Carvalho Chehab 
5859a0bf528SMauro Carvalho Chehab 	case DIBX000_ADC_ON:
5869a0bf528SMauro Carvalho Chehab 		reg_907 &= 0x0fff;
5879a0bf528SMauro Carvalho Chehab 		reg_908 &= 0x0003;
5889a0bf528SMauro Carvalho Chehab 		break;
5899a0bf528SMauro Carvalho Chehab 
5909a0bf528SMauro Carvalho Chehab 	case DIBX000_ADC_OFF:	// leave the VBG voltage on
5919a0bf528SMauro Carvalho Chehab 		reg_907 |= (1 << 14) | (1 << 13) | (1 << 12);
5929a0bf528SMauro Carvalho Chehab 		reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
5939a0bf528SMauro Carvalho Chehab 		break;
5949a0bf528SMauro Carvalho Chehab 
5959a0bf528SMauro Carvalho Chehab 	case DIBX000_VBG_ENABLE:
5969a0bf528SMauro Carvalho Chehab 		reg_907 &= ~(1 << 15);
5979a0bf528SMauro Carvalho Chehab 		break;
5989a0bf528SMauro Carvalho Chehab 
5999a0bf528SMauro Carvalho Chehab 	case DIBX000_VBG_DISABLE:
6009a0bf528SMauro Carvalho Chehab 		reg_907 |= (1 << 15);
6019a0bf528SMauro Carvalho Chehab 		break;
6029a0bf528SMauro Carvalho Chehab 
6039a0bf528SMauro Carvalho Chehab 	default:
6049a0bf528SMauro Carvalho Chehab 		break;
6059a0bf528SMauro Carvalho Chehab 	}
6069a0bf528SMauro Carvalho Chehab 
6079a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 907, reg_907);
6089a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 908, reg_908);
6099a0bf528SMauro Carvalho Chehab 
6109a0bf528SMauro Carvalho Chehab 	return ret;
6119a0bf528SMauro Carvalho Chehab }
6129a0bf528SMauro Carvalho Chehab 
6139a0bf528SMauro Carvalho Chehab static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
6149a0bf528SMauro Carvalho Chehab {
6159a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
6169a0bf528SMauro Carvalho Chehab 	u32 timf;
6179a0bf528SMauro Carvalho Chehab 
6189a0bf528SMauro Carvalho Chehab 	if (bw == 0)
6199a0bf528SMauro Carvalho Chehab 		bw = 6000;
6209a0bf528SMauro Carvalho Chehab 
6219a0bf528SMauro Carvalho Chehab 	if (state->timf == 0) {
6229a0bf528SMauro Carvalho Chehab 		dprintk("using default timf");
6239a0bf528SMauro Carvalho Chehab 		timf = state->timf_default;
6249a0bf528SMauro Carvalho Chehab 	} else {
6259a0bf528SMauro Carvalho Chehab 		dprintk("using updated timf");
6269a0bf528SMauro Carvalho Chehab 		timf = state->timf;
6279a0bf528SMauro Carvalho Chehab 	}
6289a0bf528SMauro Carvalho Chehab 
6299a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
6309a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
6319a0bf528SMauro Carvalho Chehab 
6329a0bf528SMauro Carvalho Chehab 	return 0;
6339a0bf528SMauro Carvalho Chehab }
6349a0bf528SMauro Carvalho Chehab 
6359a0bf528SMauro Carvalho Chehab static int dib8000_sad_calib(struct dib8000_state *state)
6369a0bf528SMauro Carvalho Chehab {
637173a64cbSPatrick Boettcher 	u8 sad_sel = 3;
638173a64cbSPatrick Boettcher 
6399a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090) {
640173a64cbSPatrick Boettcher 		dib8000_write_word(state, 922, (sad_sel << 2));
641173a64cbSPatrick Boettcher 		dib8000_write_word(state, 923, 2048);
642173a64cbSPatrick Boettcher 
643173a64cbSPatrick Boettcher 		dib8000_write_word(state, 922, (sad_sel << 2) | 0x1);
644173a64cbSPatrick Boettcher 		dib8000_write_word(state, 922, (sad_sel << 2));
645173a64cbSPatrick Boettcher 	} else {
6469a0bf528SMauro Carvalho Chehab 		/* internal */
6479a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
648173a64cbSPatrick Boettcher 		dib8000_write_word(state, 924, 776);
6499a0bf528SMauro Carvalho Chehab 
6509a0bf528SMauro Carvalho Chehab 		/* do the calibration */
6519a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923, (1 << 0));
6529a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923, (0 << 0));
653173a64cbSPatrick Boettcher 	}
6549a0bf528SMauro Carvalho Chehab 
6559a0bf528SMauro Carvalho Chehab 	msleep(1);
6569a0bf528SMauro Carvalho Chehab 	return 0;
6579a0bf528SMauro Carvalho Chehab }
6589a0bf528SMauro Carvalho Chehab 
659d44913c1SMauro Carvalho Chehab static int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
6609a0bf528SMauro Carvalho Chehab {
6619a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
6629a0bf528SMauro Carvalho Chehab 	if (value > 4095)
6639a0bf528SMauro Carvalho Chehab 		value = 4095;
6649a0bf528SMauro Carvalho Chehab 	state->wbd_ref = value;
6659a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(state, 106, value);
6669a0bf528SMauro Carvalho Chehab }
667173a64cbSPatrick Boettcher 
6689a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
6699a0bf528SMauro Carvalho Chehab {
6709a0bf528SMauro Carvalho Chehab 	dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
6719a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
6729a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23,
6739a0bf528SMauro Carvalho Chehab 				(u16) (((bw->internal * 1000) >> 16) & 0xffff));
6749a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24,
6759a0bf528SMauro Carvalho Chehab 				(u16) ((bw->internal * 1000) & 0xffff));
6769a0bf528SMauro Carvalho Chehab 	} else {
6779a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff));
6789a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24,
6799a0bf528SMauro Carvalho Chehab 				(u16) ((bw->internal  / 2 * 1000) & 0xffff));
6809a0bf528SMauro Carvalho Chehab 	}
6819a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
6829a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
6839a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
6849a0bf528SMauro Carvalho Chehab 
6859a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
6869a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 922, bw->sad_cfg);
6879a0bf528SMauro Carvalho Chehab }
6889a0bf528SMauro Carvalho Chehab 
6899a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll(struct dib8000_state *state)
6909a0bf528SMauro Carvalho Chehab {
6919a0bf528SMauro Carvalho Chehab 	const struct dibx000_bandwidth_config *pll = state->cfg.pll;
6929a0bf528SMauro Carvalho Chehab 	u16 clk_cfg1, reg;
6939a0bf528SMauro Carvalho Chehab 
6949a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
6959a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 901,
6969a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv << 8) | (pll->pll_ratio << 0));
6979a0bf528SMauro Carvalho Chehab 
6989a0bf528SMauro Carvalho Chehab 		clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
6999a0bf528SMauro Carvalho Chehab 			(pll->bypclk_div << 5) | (pll->enable_refdiv << 4) |
7009a0bf528SMauro Carvalho Chehab 			(1 << 3) | (pll->pll_range << 1) |
7019a0bf528SMauro Carvalho Chehab 			(pll->pll_reset << 0);
7029a0bf528SMauro Carvalho Chehab 
7039a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 902, clk_cfg1);
7049a0bf528SMauro Carvalho Chehab 		clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
7059a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 902, clk_cfg1);
7069a0bf528SMauro Carvalho Chehab 
7079a0bf528SMauro Carvalho Chehab 		dprintk("clk_cfg1: 0x%04x", clk_cfg1);
7089a0bf528SMauro Carvalho Chehab 
7099a0bf528SMauro Carvalho Chehab 		/* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
7109a0bf528SMauro Carvalho Chehab 		if (state->cfg.pll->ADClkSrc == 0)
7119a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904,
7129a0bf528SMauro Carvalho Chehab 					(0 << 15) | (0 << 12) | (0 << 10) |
7139a0bf528SMauro Carvalho Chehab 					(pll->modulo << 8) |
7149a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
7159a0bf528SMauro Carvalho Chehab 		else if (state->cfg.refclksel != 0)
7169a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
7179a0bf528SMauro Carvalho Chehab 					((state->cfg.refclksel & 0x3) << 10) |
7189a0bf528SMauro Carvalho Chehab 					(pll->modulo << 8) |
7199a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
7209a0bf528SMauro Carvalho Chehab 		else
7219a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
7229a0bf528SMauro Carvalho Chehab 					(3 << 10) | (pll->modulo << 8) |
7239a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
7249a0bf528SMauro Carvalho Chehab 	} else {
7259a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1856, (!pll->pll_reset<<13) |
7269a0bf528SMauro Carvalho Chehab 				(pll->pll_range<<12) | (pll->pll_ratio<<6) |
7279a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv));
7289a0bf528SMauro Carvalho Chehab 
7299a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 1857);
7309a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15));
7319a0bf528SMauro Carvalho Chehab 
7329a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */
7339a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1858, reg | 1);
7349a0bf528SMauro Carvalho Chehab 
7359a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 904, (pll->modulo << 8));
7369a0bf528SMauro Carvalho Chehab 	}
7379a0bf528SMauro Carvalho Chehab 
7389a0bf528SMauro Carvalho Chehab 	dib8000_reset_pll_common(state, pll);
7399a0bf528SMauro Carvalho Chehab }
7409a0bf528SMauro Carvalho Chehab 
741d44913c1SMauro Carvalho Chehab static int dib8000_update_pll(struct dvb_frontend *fe,
742173a64cbSPatrick Boettcher 		struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
7439a0bf528SMauro Carvalho Chehab {
7449a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
7459a0bf528SMauro Carvalho Chehab 	u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
746173a64cbSPatrick Boettcher 	u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ;
7479a0bf528SMauro Carvalho Chehab 	u32 internal, xtal;
7489a0bf528SMauro Carvalho Chehab 
7499a0bf528SMauro Carvalho Chehab 	/* get back old values */
7509a0bf528SMauro Carvalho Chehab 	prediv = reg_1856 & 0x3f;
7519a0bf528SMauro Carvalho Chehab 	loopdiv = (reg_1856 >> 6) & 0x3f;
7529a0bf528SMauro Carvalho Chehab 
753173a64cbSPatrick Boettcher 	if ((pll == NULL) || (pll->pll_prediv == prediv &&
754173a64cbSPatrick Boettcher 				pll->pll_ratio == loopdiv))
755173a64cbSPatrick Boettcher 		return -EINVAL;
756173a64cbSPatrick Boettcher 
7579a0bf528SMauro Carvalho Chehab 	dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
758173a64cbSPatrick Boettcher 	if (state->revision == 0x8090) {
7599a0bf528SMauro Carvalho Chehab 		reg_1856 &= 0xf000;
7609a0bf528SMauro Carvalho Chehab 		reg_1857 = dib8000_read_word(state, 1857);
7619a0bf528SMauro Carvalho Chehab 		/* disable PLL */
7629a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15));
7639a0bf528SMauro Carvalho Chehab 
7649a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1856, reg_1856 |
7659a0bf528SMauro Carvalho Chehab 				((pll->pll_ratio & 0x3f) << 6) |
7669a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv & 0x3f));
7679a0bf528SMauro Carvalho Chehab 
7689a0bf528SMauro Carvalho Chehab 		/* write new system clk into P_sec_len */
7699a0bf528SMauro Carvalho Chehab 		internal = dib8000_read32(state, 23) / 1000;
7709a0bf528SMauro Carvalho Chehab 		dprintk("Old Internal = %d", internal);
7719a0bf528SMauro Carvalho Chehab 		xtal = 2 * (internal / loopdiv) * prediv;
7729a0bf528SMauro Carvalho Chehab 		internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio;
7739a0bf528SMauro Carvalho Chehab 		dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d", xtal, internal/1000, internal/2000, internal/8000);
7749a0bf528SMauro Carvalho Chehab 		dprintk("New Internal = %d", internal);
7759a0bf528SMauro Carvalho Chehab 
7769a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23,
7779a0bf528SMauro Carvalho Chehab 				(u16) (((internal / 2) >> 16) & 0xffff));
7789a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff));
7799a0bf528SMauro Carvalho Chehab 		/* enable PLL */
7809a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg_1857 | (1 << 15));
7819a0bf528SMauro Carvalho Chehab 
7829a0bf528SMauro Carvalho Chehab 		while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1)
7839a0bf528SMauro Carvalho Chehab 			dprintk("Waiting for PLL to lock");
7849a0bf528SMauro Carvalho Chehab 
7859a0bf528SMauro Carvalho Chehab 		/* verify */
7869a0bf528SMauro Carvalho Chehab 		reg_1856 = dib8000_read_word(state, 1856);
7879a0bf528SMauro Carvalho Chehab 		dprintk("PLL Updated with prediv = %d and loopdiv = %d",
7889a0bf528SMauro Carvalho Chehab 				reg_1856&0x3f, (reg_1856>>6)&0x3f);
789173a64cbSPatrick Boettcher 	} else {
790173a64cbSPatrick Boettcher 		if (bw != state->current_demod_bw) {
791173a64cbSPatrick Boettcher 			/** Bandwidth change => force PLL update **/
792173a64cbSPatrick 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);
793173a64cbSPatrick Boettcher 
794173a64cbSPatrick Boettcher 			if (state->cfg.pll->pll_prediv != oldprediv) {
795173a64cbSPatrick Boettcher 				/** Full PLL change only if prediv is changed **/
796173a64cbSPatrick Boettcher 
797173a64cbSPatrick Boettcher 				/** full update => bypass and reconfigure **/
798173a64cbSPatrick 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);
799173a64cbSPatrick Boettcher 				dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */
800173a64cbSPatrick Boettcher 				dib8000_reset_pll(state);
801173a64cbSPatrick Boettcher 				dib8000_write_word(state, 898, 0x0004); /* sad */
802173a64cbSPatrick Boettcher 			} else
803173a64cbSPatrick Boettcher 				ratio = state->cfg.pll->pll_ratio;
804173a64cbSPatrick Boettcher 
805173a64cbSPatrick Boettcher 			state->current_demod_bw = bw;
806173a64cbSPatrick Boettcher 		}
807173a64cbSPatrick Boettcher 
808173a64cbSPatrick Boettcher 		if (ratio != 0) {
809173a64cbSPatrick Boettcher 			/** ratio update => only change ratio **/
810173a64cbSPatrick Boettcher 			dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio);
811173a64cbSPatrick Boettcher 			dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
812173a64cbSPatrick Boettcher 		}
813173a64cbSPatrick Boettcher 	}
8149a0bf528SMauro Carvalho Chehab 
8159a0bf528SMauro Carvalho Chehab 	return 0;
8169a0bf528SMauro Carvalho Chehab }
8179a0bf528SMauro Carvalho Chehab 
8189a0bf528SMauro Carvalho Chehab static int dib8000_reset_gpio(struct dib8000_state *st)
8199a0bf528SMauro Carvalho Chehab {
8209a0bf528SMauro Carvalho Chehab 	/* reset the GPIOs */
8219a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
8229a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1030, st->cfg.gpio_val);
8239a0bf528SMauro Carvalho Chehab 
8249a0bf528SMauro Carvalho Chehab 	/* TODO 782 is P_gpio_od */
8259a0bf528SMauro Carvalho Chehab 
8269a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
8279a0bf528SMauro Carvalho Chehab 
8289a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
8299a0bf528SMauro Carvalho Chehab 	return 0;
8309a0bf528SMauro Carvalho Chehab }
8319a0bf528SMauro Carvalho Chehab 
8329a0bf528SMauro Carvalho Chehab static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
8339a0bf528SMauro Carvalho Chehab {
8349a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir = dib8000_read_word(st, 1029);
8359a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir &= ~(1 << num);	/* reset the direction bit */
8369a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
8379a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
8389a0bf528SMauro Carvalho Chehab 
8399a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val = dib8000_read_word(st, 1030);
8409a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val &= ~(1 << num);	/* reset the direction bit */
8419a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val |= (val & 0x01) << num;	/* set the new value */
8429a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1030, st->cfg.gpio_val);
8439a0bf528SMauro Carvalho Chehab 
8449a0bf528SMauro Carvalho Chehab 	dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val);
8459a0bf528SMauro Carvalho Chehab 
8469a0bf528SMauro Carvalho Chehab 	return 0;
8479a0bf528SMauro Carvalho Chehab }
8489a0bf528SMauro Carvalho Chehab 
849d44913c1SMauro Carvalho Chehab static int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
8509a0bf528SMauro Carvalho Chehab {
8519a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
8529a0bf528SMauro Carvalho Chehab 	return dib8000_cfg_gpio(state, num, dir, val);
8539a0bf528SMauro Carvalho Chehab }
8549a0bf528SMauro Carvalho Chehab 
8559a0bf528SMauro Carvalho Chehab static const u16 dib8000_defaults[] = {
8569a0bf528SMauro Carvalho Chehab 	/* auto search configuration - lock0 by default waiting
8579a0bf528SMauro Carvalho Chehab 	 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
8589a0bf528SMauro Carvalho Chehab 	3, 7,
8599a0bf528SMauro Carvalho Chehab 	0x0004,
8609a0bf528SMauro Carvalho Chehab 	0x0400,
8619a0bf528SMauro Carvalho Chehab 	0x0814,
8629a0bf528SMauro Carvalho Chehab 
8639a0bf528SMauro Carvalho Chehab 	12, 11,
8649a0bf528SMauro Carvalho Chehab 	0x001b,
8659a0bf528SMauro Carvalho Chehab 	0x7740,
8669a0bf528SMauro Carvalho Chehab 	0x005b,
8679a0bf528SMauro Carvalho Chehab 	0x8d80,
8689a0bf528SMauro Carvalho Chehab 	0x01c9,
8699a0bf528SMauro Carvalho Chehab 	0xc380,
8709a0bf528SMauro Carvalho Chehab 	0x0000,
8719a0bf528SMauro Carvalho Chehab 	0x0080,
8729a0bf528SMauro Carvalho Chehab 	0x0000,
8739a0bf528SMauro Carvalho Chehab 	0x0090,
8749a0bf528SMauro Carvalho Chehab 	0x0001,
8759a0bf528SMauro Carvalho Chehab 	0xd4c0,
8769a0bf528SMauro Carvalho Chehab 
8779a0bf528SMauro Carvalho Chehab 	/*1, 32,
8789a0bf528SMauro Carvalho Chehab 		0x6680 // P_corm_thres Lock algorithms configuration */
8799a0bf528SMauro Carvalho Chehab 
8809a0bf528SMauro Carvalho Chehab 	11, 80,			/* set ADC level to -16 */
8819a0bf528SMauro Carvalho Chehab 	(1 << 13) - 825 - 117,
8829a0bf528SMauro Carvalho Chehab 	(1 << 13) - 837 - 117,
8839a0bf528SMauro Carvalho Chehab 	(1 << 13) - 811 - 117,
8849a0bf528SMauro Carvalho Chehab 	(1 << 13) - 766 - 117,
8859a0bf528SMauro Carvalho Chehab 	(1 << 13) - 737 - 117,
8869a0bf528SMauro Carvalho Chehab 	(1 << 13) - 693 - 117,
8879a0bf528SMauro Carvalho Chehab 	(1 << 13) - 648 - 117,
8889a0bf528SMauro Carvalho Chehab 	(1 << 13) - 619 - 117,
8899a0bf528SMauro Carvalho Chehab 	(1 << 13) - 575 - 117,
8909a0bf528SMauro Carvalho Chehab 	(1 << 13) - 531 - 117,
8919a0bf528SMauro Carvalho Chehab 	(1 << 13) - 501 - 117,
8929a0bf528SMauro Carvalho Chehab 
8939a0bf528SMauro Carvalho Chehab 	4, 108,
8949a0bf528SMauro Carvalho Chehab 	0,
8959a0bf528SMauro Carvalho Chehab 	0,
8969a0bf528SMauro Carvalho Chehab 	0,
8979a0bf528SMauro Carvalho Chehab 	0,
8989a0bf528SMauro Carvalho Chehab 
8999a0bf528SMauro Carvalho Chehab 	1, 175,
9009a0bf528SMauro Carvalho Chehab 	0x0410,
9019a0bf528SMauro Carvalho Chehab 	1, 179,
9029a0bf528SMauro Carvalho Chehab 	8192,			// P_fft_nb_to_cut
9039a0bf528SMauro Carvalho Chehab 
9049a0bf528SMauro Carvalho Chehab 	6, 181,
9059a0bf528SMauro Carvalho Chehab 	0x2800,			// P_coff_corthres_ ( 2k 4k 8k ) 0x2800
9069a0bf528SMauro Carvalho Chehab 	0x2800,
9079a0bf528SMauro Carvalho Chehab 	0x2800,
9089a0bf528SMauro Carvalho Chehab 	0x2800,			// P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
9099a0bf528SMauro Carvalho Chehab 	0x2800,
9109a0bf528SMauro Carvalho Chehab 	0x2800,
9119a0bf528SMauro Carvalho Chehab 
9129a0bf528SMauro Carvalho Chehab 	2, 193,
9139a0bf528SMauro Carvalho Chehab 	0x0666,			// P_pha3_thres
9149a0bf528SMauro Carvalho Chehab 	0x0000,			// P_cti_use_cpe, P_cti_use_prog
9159a0bf528SMauro Carvalho Chehab 
9169a0bf528SMauro Carvalho Chehab 	2, 205,
9179a0bf528SMauro Carvalho Chehab 	0x200f,			// P_cspu_regul, P_cspu_win_cut
9189a0bf528SMauro Carvalho Chehab 	0x000f,			// P_des_shift_work
9199a0bf528SMauro Carvalho Chehab 
9209a0bf528SMauro Carvalho Chehab 	5, 215,
9219a0bf528SMauro Carvalho Chehab 	0x023d,			// P_adp_regul_cnt
9229a0bf528SMauro Carvalho Chehab 	0x00a4,			// P_adp_noise_cnt
9239a0bf528SMauro Carvalho Chehab 	0x00a4,			// P_adp_regul_ext
9249a0bf528SMauro Carvalho Chehab 	0x7ff0,			// P_adp_noise_ext
9259a0bf528SMauro Carvalho Chehab 	0x3ccc,			// P_adp_fil
9269a0bf528SMauro Carvalho Chehab 
9279a0bf528SMauro Carvalho Chehab 	1, 230,
9289a0bf528SMauro Carvalho Chehab 	0x0000,			// P_2d_byp_ti_num
9299a0bf528SMauro Carvalho Chehab 
9309a0bf528SMauro Carvalho Chehab 	1, 263,
9319a0bf528SMauro Carvalho Chehab 	0x800,			//P_equal_thres_wgn
9329a0bf528SMauro Carvalho Chehab 
9339a0bf528SMauro Carvalho Chehab 	1, 268,
9349a0bf528SMauro Carvalho Chehab 	(2 << 9) | 39,		// P_equal_ctrl_synchro, P_equal_speedmode
9359a0bf528SMauro Carvalho Chehab 
9369a0bf528SMauro Carvalho Chehab 	1, 270,
9379a0bf528SMauro Carvalho Chehab 	0x0001,			// P_div_lock0_wait
9389a0bf528SMauro Carvalho Chehab 	1, 285,
9399a0bf528SMauro Carvalho Chehab 	0x0020,			//p_fec_
9409a0bf528SMauro Carvalho Chehab 	1, 299,
9419a0bf528SMauro Carvalho Chehab 	0x0062,			/* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */
9429a0bf528SMauro Carvalho Chehab 
9439a0bf528SMauro Carvalho Chehab 	1, 338,
9449a0bf528SMauro Carvalho Chehab 	(1 << 12) |		// P_ctrl_corm_thres4pre_freq_inh=1
9459a0bf528SMauro Carvalho Chehab 		(1 << 10) |
9469a0bf528SMauro Carvalho Chehab 		(0 << 9) |		/* P_ctrl_pre_freq_inh=0 */
9479a0bf528SMauro Carvalho Chehab 		(3 << 5) |		/* P_ctrl_pre_freq_step=3 */
9489a0bf528SMauro Carvalho Chehab 		(1 << 0),		/* P_pre_freq_win_len=1 */
9499a0bf528SMauro Carvalho Chehab 
9509a0bf528SMauro Carvalho Chehab 	0,
9519a0bf528SMauro Carvalho Chehab };
9529a0bf528SMauro Carvalho Chehab 
9539a0bf528SMauro Carvalho Chehab static u16 dib8000_identify(struct i2c_device *client)
9549a0bf528SMauro Carvalho Chehab {
9559a0bf528SMauro Carvalho Chehab 	u16 value;
9569a0bf528SMauro Carvalho Chehab 
9579a0bf528SMauro Carvalho Chehab 	//because of glitches sometimes
9589a0bf528SMauro Carvalho Chehab 	value = dib8000_i2c_read16(client, 896);
9599a0bf528SMauro Carvalho Chehab 
9609a0bf528SMauro Carvalho Chehab 	if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
9619a0bf528SMauro Carvalho Chehab 		dprintk("wrong Vendor ID (read=0x%x)", value);
9629a0bf528SMauro Carvalho Chehab 		return 0;
9639a0bf528SMauro Carvalho Chehab 	}
9649a0bf528SMauro Carvalho Chehab 
9659a0bf528SMauro Carvalho Chehab 	value = dib8000_i2c_read16(client, 897);
9669a0bf528SMauro Carvalho Chehab 	if (value != 0x8000 && value != 0x8001 &&
9679a0bf528SMauro Carvalho Chehab 			value != 0x8002 && value != 0x8090) {
9689a0bf528SMauro Carvalho Chehab 		dprintk("wrong Device ID (%x)", value);
9699a0bf528SMauro Carvalho Chehab 		return 0;
9709a0bf528SMauro Carvalho Chehab 	}
9719a0bf528SMauro Carvalho Chehab 
9729a0bf528SMauro Carvalho Chehab 	switch (value) {
9739a0bf528SMauro Carvalho Chehab 	case 0x8000:
9749a0bf528SMauro Carvalho Chehab 		dprintk("found DiB8000A");
9759a0bf528SMauro Carvalho Chehab 		break;
9769a0bf528SMauro Carvalho Chehab 	case 0x8001:
9779a0bf528SMauro Carvalho Chehab 		dprintk("found DiB8000B");
9789a0bf528SMauro Carvalho Chehab 		break;
9799a0bf528SMauro Carvalho Chehab 	case 0x8002:
9809a0bf528SMauro Carvalho Chehab 		dprintk("found DiB8000C");
9819a0bf528SMauro Carvalho Chehab 		break;
9829a0bf528SMauro Carvalho Chehab 	case 0x8090:
9839a0bf528SMauro Carvalho Chehab 		dprintk("found DiB8096P");
9849a0bf528SMauro Carvalho Chehab 		break;
9859a0bf528SMauro Carvalho Chehab 	}
9869a0bf528SMauro Carvalho Chehab 	return value;
9879a0bf528SMauro Carvalho Chehab }
9889a0bf528SMauro Carvalho Chehab 
9897a9d85d5SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 *unc);
9907a9d85d5SMauro Carvalho Chehab 
9916ef06e78SMauro Carvalho Chehab static void dib8000_reset_stats(struct dvb_frontend *fe)
9926ef06e78SMauro Carvalho Chehab {
9936ef06e78SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
9946ef06e78SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
9957a9d85d5SMauro Carvalho Chehab 	u32 ucb;
9966ef06e78SMauro Carvalho Chehab 
9976ef06e78SMauro Carvalho Chehab 	memset(&c->strength, 0, sizeof(c->strength));
9986ef06e78SMauro Carvalho Chehab 	memset(&c->cnr, 0, sizeof(c->cnr));
9996ef06e78SMauro Carvalho Chehab 	memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
10006ef06e78SMauro Carvalho Chehab 	memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
10016ef06e78SMauro Carvalho Chehab 	memset(&c->block_error, 0, sizeof(c->block_error));
10026ef06e78SMauro Carvalho Chehab 
10036ef06e78SMauro Carvalho Chehab 	c->strength.len = 1;
10046ef06e78SMauro Carvalho Chehab 	c->cnr.len = 1;
10056ef06e78SMauro Carvalho Chehab 	c->block_error.len = 1;
10060400c535SMauro Carvalho Chehab 	c->block_count.len = 1;
10076ef06e78SMauro Carvalho Chehab 	c->post_bit_error.len = 1;
10086ef06e78SMauro Carvalho Chehab 	c->post_bit_count.len = 1;
10096ef06e78SMauro Carvalho Chehab 
1010b4600d70SMauro Carvalho Chehab 	c->strength.stat[0].scale = FE_SCALE_DECIBEL;
10116ef06e78SMauro Carvalho Chehab 	c->strength.stat[0].uvalue = 0;
10126ef06e78SMauro Carvalho Chehab 
10136ef06e78SMauro Carvalho Chehab 	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10146ef06e78SMauro Carvalho Chehab 	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10150400c535SMauro Carvalho Chehab 	c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10166ef06e78SMauro Carvalho Chehab 	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10176ef06e78SMauro Carvalho Chehab 	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10187a9d85d5SMauro Carvalho Chehab 
10197a9d85d5SMauro Carvalho Chehab 	dib8000_read_unc_blocks(fe, &ucb);
1020704f01bbSMauro Carvalho Chehab 
10217a9d85d5SMauro Carvalho Chehab 	state->init_ucb = -ucb;
10220400c535SMauro Carvalho Chehab 	state->ber_jiffies_stats = 0;
10230400c535SMauro Carvalho Chehab 	state->per_jiffies_stats = 0;
10240400c535SMauro Carvalho Chehab 	memset(&state->ber_jiffies_stats_layer, 0,
10250400c535SMauro Carvalho Chehab 	       sizeof(state->ber_jiffies_stats_layer));
10266ef06e78SMauro Carvalho Chehab }
10276ef06e78SMauro Carvalho Chehab 
10289a0bf528SMauro Carvalho Chehab static int dib8000_reset(struct dvb_frontend *fe)
10299a0bf528SMauro Carvalho Chehab {
10309a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
10319a0bf528SMauro Carvalho Chehab 
10329a0bf528SMauro Carvalho Chehab 	if ((state->revision = dib8000_identify(&state->i2c)) == 0)
10339a0bf528SMauro Carvalho Chehab 		return -EINVAL;
10349a0bf528SMauro Carvalho Chehab 
10359a0bf528SMauro Carvalho Chehab 	/* sram lead in, rdy */
10369a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
10379a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1287, 0x0003);
10389a0bf528SMauro Carvalho Chehab 
10399a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8000)
10409a0bf528SMauro Carvalho Chehab 		dprintk("error : dib8000 MA not supported");
10419a0bf528SMauro Carvalho Chehab 
10429a0bf528SMauro Carvalho Chehab 	dibx000_reset_i2c_master(&state->i2c_master);
10439a0bf528SMauro Carvalho Chehab 
10449a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
10459a0bf528SMauro Carvalho Chehab 
10469a0bf528SMauro Carvalho Chehab 	/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
1047173a64cbSPatrick Boettcher 	dib8000_set_adc_state(state, DIBX000_ADC_OFF);
10489a0bf528SMauro Carvalho Chehab 
10499a0bf528SMauro Carvalho Chehab 	/* restart all parts */
10509a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0xffff);
10519a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 771, 0xffff);
10529a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 772, 0xfffc);
10539a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
10549a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1280, 0x0045);
10559a0bf528SMauro Carvalho Chehab 	else
10569a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1280, 0x004d);
10579a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1281, 0x000c);
10589a0bf528SMauro Carvalho Chehab 
10599a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0000);
10609a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 771, 0x0000);
10619a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 772, 0x0000);
10629a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 898, 0x0004);	// sad
10639a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1280, 0x0000);
10649a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1281, 0x0000);
10659a0bf528SMauro Carvalho Chehab 
10669a0bf528SMauro Carvalho Chehab 	/* drives */
10679a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
10689a0bf528SMauro Carvalho Chehab 		if (state->cfg.drives)
10699a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 906, state->cfg.drives);
10709a0bf528SMauro Carvalho Chehab 		else {
10719a0bf528SMauro Carvalho Chehab 			dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
10729a0bf528SMauro Carvalho Chehab 			/* min drive SDRAM - not optimal - adjust */
10739a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 906, 0x2d98);
10749a0bf528SMauro Carvalho Chehab 		}
10759a0bf528SMauro Carvalho Chehab 	}
10769a0bf528SMauro Carvalho Chehab 
10779a0bf528SMauro Carvalho Chehab 	dib8000_reset_pll(state);
10789a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
10799a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 898, 0x0004);
10809a0bf528SMauro Carvalho Chehab 
10819a0bf528SMauro Carvalho Chehab 	if (dib8000_reset_gpio(state) != 0)
10829a0bf528SMauro Carvalho Chehab 		dprintk("GPIO reset was not successful.");
10839a0bf528SMauro Carvalho Chehab 
10849a0bf528SMauro Carvalho Chehab 	if ((state->revision != 0x8090) &&
10859a0bf528SMauro Carvalho Chehab 			(dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
10869a0bf528SMauro Carvalho Chehab 		dprintk("OUTPUT_MODE could not be resetted.");
10879a0bf528SMauro Carvalho Chehab 
10889a0bf528SMauro Carvalho Chehab 	state->current_agc = NULL;
10899a0bf528SMauro Carvalho Chehab 
10909a0bf528SMauro Carvalho Chehab 	// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
10919a0bf528SMauro Carvalho Chehab 	/* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
10929a0bf528SMauro Carvalho Chehab 	if (state->cfg.pll->ifreq == 0)
10939a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 40, 0x0755);	/* P_iqc_corr_inh = 0 enable IQcorr block */
10949a0bf528SMauro Carvalho Chehab 	else
10959a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 40, 0x1f55);	/* P_iqc_corr_inh = 1 disable IQcorr block */
10969a0bf528SMauro Carvalho Chehab 
10979a0bf528SMauro Carvalho Chehab 	{
10989a0bf528SMauro Carvalho Chehab 		u16 l = 0, r;
10999a0bf528SMauro Carvalho Chehab 		const u16 *n;
11009a0bf528SMauro Carvalho Chehab 		n = dib8000_defaults;
11019a0bf528SMauro Carvalho Chehab 		l = *n++;
11029a0bf528SMauro Carvalho Chehab 		while (l) {
11039a0bf528SMauro Carvalho Chehab 			r = *n++;
11049a0bf528SMauro Carvalho Chehab 			do {
11059a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, r, *n++);
11069a0bf528SMauro Carvalho Chehab 				r++;
11079a0bf528SMauro Carvalho Chehab 			} while (--l);
11089a0bf528SMauro Carvalho Chehab 			l = *n++;
11099a0bf528SMauro Carvalho Chehab 		}
11109a0bf528SMauro Carvalho Chehab 	}
1111173a64cbSPatrick Boettcher 
11129a0bf528SMauro Carvalho Chehab 	state->isdbt_cfg_loaded = 0;
11139a0bf528SMauro Carvalho Chehab 
11149a0bf528SMauro Carvalho Chehab 	//div_cfg override for special configs
1115173a64cbSPatrick Boettcher 	if ((state->revision != 8090) && (state->cfg.div_cfg != 0))
11169a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 903, state->cfg.div_cfg);
11179a0bf528SMauro Carvalho Chehab 
11189a0bf528SMauro Carvalho Chehab 	/* unforce divstr regardless whether i2c enumeration was done or not */
11199a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
11209a0bf528SMauro Carvalho Chehab 
11219a0bf528SMauro Carvalho Chehab 	dib8000_set_bandwidth(fe, 6000);
11229a0bf528SMauro Carvalho Chehab 
11239a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
11249a0bf528SMauro Carvalho Chehab 	dib8000_sad_calib(state);
1125173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
11269a0bf528SMauro Carvalho Chehab 		dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
1127173a64cbSPatrick Boettcher 
1128173a64cbSPatrick Boettcher 	/* ber_rs_len = 3 */
1129173a64cbSPatrick Boettcher 	dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));
11309a0bf528SMauro Carvalho Chehab 
11319a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
11329a0bf528SMauro Carvalho Chehab 
11336ef06e78SMauro Carvalho Chehab 	dib8000_reset_stats(fe);
11346ef06e78SMauro Carvalho Chehab 
11359a0bf528SMauro Carvalho Chehab 	return 0;
11369a0bf528SMauro Carvalho Chehab }
11379a0bf528SMauro Carvalho Chehab 
11389a0bf528SMauro Carvalho Chehab static void dib8000_restart_agc(struct dib8000_state *state)
11399a0bf528SMauro Carvalho Chehab {
11409a0bf528SMauro Carvalho Chehab 	// P_restart_iqc & P_restart_agc
11419a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0a00);
11429a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0000);
11439a0bf528SMauro Carvalho Chehab }
11449a0bf528SMauro Carvalho Chehab 
11459a0bf528SMauro Carvalho Chehab static int dib8000_update_lna(struct dib8000_state *state)
11469a0bf528SMauro Carvalho Chehab {
11479a0bf528SMauro Carvalho Chehab 	u16 dyn_gain;
11489a0bf528SMauro Carvalho Chehab 
11499a0bf528SMauro Carvalho Chehab 	if (state->cfg.update_lna) {
11509a0bf528SMauro Carvalho Chehab 		// read dyn_gain here (because it is demod-dependent and not tuner)
11519a0bf528SMauro Carvalho Chehab 		dyn_gain = dib8000_read_word(state, 390);
11529a0bf528SMauro Carvalho Chehab 
11539a0bf528SMauro Carvalho Chehab 		if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
11549a0bf528SMauro Carvalho Chehab 			dib8000_restart_agc(state);
11559a0bf528SMauro Carvalho Chehab 			return 1;
11569a0bf528SMauro Carvalho Chehab 		}
11579a0bf528SMauro Carvalho Chehab 	}
11589a0bf528SMauro Carvalho Chehab 	return 0;
11599a0bf528SMauro Carvalho Chehab }
11609a0bf528SMauro Carvalho Chehab 
11619a0bf528SMauro Carvalho Chehab static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
11629a0bf528SMauro Carvalho Chehab {
11639a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *agc = NULL;
11649a0bf528SMauro Carvalho Chehab 	int i;
11659a0bf528SMauro Carvalho Chehab 	u16 reg;
11669a0bf528SMauro Carvalho Chehab 
11679a0bf528SMauro Carvalho Chehab 	if (state->current_band == band && state->current_agc != NULL)
11689a0bf528SMauro Carvalho Chehab 		return 0;
11699a0bf528SMauro Carvalho Chehab 	state->current_band = band;
11709a0bf528SMauro Carvalho Chehab 
11719a0bf528SMauro Carvalho Chehab 	for (i = 0; i < state->cfg.agc_config_count; i++)
11729a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc[i].band_caps & band) {
11739a0bf528SMauro Carvalho Chehab 			agc = &state->cfg.agc[i];
11749a0bf528SMauro Carvalho Chehab 			break;
11759a0bf528SMauro Carvalho Chehab 		}
11769a0bf528SMauro Carvalho Chehab 
11779a0bf528SMauro Carvalho Chehab 	if (agc == NULL) {
11789a0bf528SMauro Carvalho Chehab 		dprintk("no valid AGC configuration found for band 0x%02x", band);
11799a0bf528SMauro Carvalho Chehab 		return -EINVAL;
11809a0bf528SMauro Carvalho Chehab 	}
11819a0bf528SMauro Carvalho Chehab 
11829a0bf528SMauro Carvalho Chehab 	state->current_agc = agc;
11839a0bf528SMauro Carvalho Chehab 
11849a0bf528SMauro Carvalho Chehab 	/* AGC */
11859a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 76, agc->setup);
11869a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 77, agc->inv_gain);
11879a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 78, agc->time_stabiliz);
11889a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
11899a0bf528SMauro Carvalho Chehab 
11909a0bf528SMauro Carvalho Chehab 	// Demod AGC loop configuration
11919a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
11929a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
11939a0bf528SMauro Carvalho Chehab 
11949a0bf528SMauro Carvalho Chehab 	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
11959a0bf528SMauro Carvalho Chehab 		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
11969a0bf528SMauro Carvalho Chehab 
11979a0bf528SMauro Carvalho Chehab 	/* AGC continued */
11989a0bf528SMauro Carvalho Chehab 	if (state->wbd_ref != 0)
11999a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 106, state->wbd_ref);
12009a0bf528SMauro Carvalho Chehab 	else			// use default
12019a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 106, agc->wbd_ref);
12029a0bf528SMauro Carvalho Chehab 
12039a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090) {
12049a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 922) & (0x3 << 2);
12059a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
12069a0bf528SMauro Carvalho Chehab 	}
12079a0bf528SMauro Carvalho Chehab 
12089a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
12099a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 108, agc->agc1_max);
12109a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 109, agc->agc1_min);
12119a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 110, agc->agc2_max);
12129a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 111, agc->agc2_min);
12139a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
12149a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
12159a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
12169a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
12179a0bf528SMauro Carvalho Chehab 
12189a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 75, agc->agc1_pt3);
12199a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
12209a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923,
12219a0bf528SMauro Carvalho Chehab 				(dib8000_read_word(state, 923) & 0xffe3) |
12229a0bf528SMauro Carvalho Chehab 				(agc->wbd_inv << 4) | (agc->wbd_sel << 2));
12239a0bf528SMauro Carvalho Chehab 
12249a0bf528SMauro Carvalho Chehab 	return 0;
12259a0bf528SMauro Carvalho Chehab }
12269a0bf528SMauro Carvalho Chehab 
1227d44913c1SMauro Carvalho Chehab static void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
12289a0bf528SMauro Carvalho Chehab {
12299a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
12309a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_ADC_ON);
12319a0bf528SMauro Carvalho Chehab 	dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
12329a0bf528SMauro Carvalho Chehab }
12339a0bf528SMauro Carvalho Chehab 
12349a0bf528SMauro Carvalho Chehab static int dib8000_agc_soft_split(struct dib8000_state *state)
12359a0bf528SMauro Carvalho Chehab {
12369a0bf528SMauro Carvalho Chehab 	u16 agc, split_offset;
12379a0bf528SMauro Carvalho Chehab 
12389a0bf528SMauro Carvalho Chehab 	if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
12399a0bf528SMauro Carvalho Chehab 		return FE_CALLBACK_TIME_NEVER;
12409a0bf528SMauro Carvalho Chehab 
12419a0bf528SMauro Carvalho Chehab 	// n_agc_global
12429a0bf528SMauro Carvalho Chehab 	agc = dib8000_read_word(state, 390);
12439a0bf528SMauro Carvalho Chehab 
12449a0bf528SMauro Carvalho Chehab 	if (agc > state->current_agc->split.min_thres)
12459a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.min;
12469a0bf528SMauro Carvalho Chehab 	else if (agc < state->current_agc->split.max_thres)
12479a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.max;
12489a0bf528SMauro Carvalho Chehab 	else
12499a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.max *
12509a0bf528SMauro Carvalho Chehab 			(agc - state->current_agc->split.min_thres) /
12519a0bf528SMauro Carvalho Chehab 			(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
12529a0bf528SMauro Carvalho Chehab 
12539a0bf528SMauro Carvalho Chehab 	dprintk("AGC split_offset: %d", split_offset);
12549a0bf528SMauro Carvalho Chehab 
12559a0bf528SMauro Carvalho Chehab 	// P_agc_force_split and P_agc_split_offset
12569a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
12579a0bf528SMauro Carvalho Chehab 	return 5000;
12589a0bf528SMauro Carvalho Chehab }
12599a0bf528SMauro Carvalho Chehab 
12609a0bf528SMauro Carvalho Chehab static int dib8000_agc_startup(struct dvb_frontend *fe)
12619a0bf528SMauro Carvalho Chehab {
12629a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
12639a0bf528SMauro Carvalho Chehab 	enum frontend_tune_state *tune_state = &state->tune_state;
12649a0bf528SMauro Carvalho Chehab 	int ret = 0;
12659a0bf528SMauro Carvalho Chehab 	u16 reg, upd_demod_gain_period = 0x8000;
12669a0bf528SMauro Carvalho Chehab 
12679a0bf528SMauro Carvalho Chehab 	switch (*tune_state) {
12689a0bf528SMauro Carvalho Chehab 	case CT_AGC_START:
12699a0bf528SMauro Carvalho Chehab 		// set power-up level: interf+analog+AGC
12709a0bf528SMauro Carvalho Chehab 
12719a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090)
12729a0bf528SMauro Carvalho Chehab 			dib8000_set_adc_state(state, DIBX000_ADC_ON);
12739a0bf528SMauro Carvalho Chehab 		else {
12749a0bf528SMauro Carvalho Chehab 			dib8000_set_power_mode(state, DIB8000_POWER_ALL);
12759a0bf528SMauro Carvalho Chehab 
12769a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1947)&0xff00;
12779a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1946,
12789a0bf528SMauro Carvalho Chehab 					upd_demod_gain_period & 0xFFFF);
12799a0bf528SMauro Carvalho Chehab 			/* bit 14 = enDemodGain */
12809a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1947, reg | (1<<14) |
12819a0bf528SMauro Carvalho Chehab 					((upd_demod_gain_period >> 16) & 0xFF));
12829a0bf528SMauro Carvalho Chehab 
12839a0bf528SMauro Carvalho Chehab 			/* enable adc i & q */
12849a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1920);
12859a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1920, (reg | 0x3) &
12869a0bf528SMauro Carvalho Chehab 					(~(1 << 7)));
12879a0bf528SMauro Carvalho Chehab 		}
12889a0bf528SMauro Carvalho Chehab 
12899a0bf528SMauro Carvalho Chehab 		if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
12909a0bf528SMauro Carvalho Chehab 			*tune_state = CT_AGC_STOP;
12919a0bf528SMauro Carvalho Chehab 			state->status = FE_STATUS_TUNE_FAILED;
12929a0bf528SMauro Carvalho Chehab 			break;
12939a0bf528SMauro Carvalho Chehab 		}
12949a0bf528SMauro Carvalho Chehab 
12959a0bf528SMauro Carvalho Chehab 		ret = 70;
12969a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STEP_0;
12979a0bf528SMauro Carvalho Chehab 		break;
12989a0bf528SMauro Carvalho Chehab 
12999a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_0:
13009a0bf528SMauro Carvalho Chehab 		//AGC initialization
13019a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
13029a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(fe, 1);
13039a0bf528SMauro Carvalho Chehab 
13049a0bf528SMauro Carvalho Chehab 		dib8000_restart_agc(state);
13059a0bf528SMauro Carvalho Chehab 
13069a0bf528SMauro Carvalho Chehab 		// wait AGC rough lock time
13079a0bf528SMauro Carvalho Chehab 		ret = 50;
13089a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STEP_1;
13099a0bf528SMauro Carvalho Chehab 		break;
13109a0bf528SMauro Carvalho Chehab 
13119a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_1:
13129a0bf528SMauro Carvalho Chehab 		// wait AGC accurate lock time
13139a0bf528SMauro Carvalho Chehab 		ret = 70;
13149a0bf528SMauro Carvalho Chehab 
13159a0bf528SMauro Carvalho Chehab 		if (dib8000_update_lna(state))
13169a0bf528SMauro Carvalho Chehab 			// wait only AGC rough lock time
13179a0bf528SMauro Carvalho Chehab 			ret = 50;
13189a0bf528SMauro Carvalho Chehab 		else
13199a0bf528SMauro Carvalho Chehab 			*tune_state = CT_AGC_STEP_2;
13209a0bf528SMauro Carvalho Chehab 		break;
13219a0bf528SMauro Carvalho Chehab 
13229a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_2:
13239a0bf528SMauro Carvalho Chehab 		dib8000_agc_soft_split(state);
13249a0bf528SMauro Carvalho Chehab 
13259a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
13269a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(fe, 0);
13279a0bf528SMauro Carvalho Chehab 
13289a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STOP;
13299a0bf528SMauro Carvalho Chehab 		break;
13309a0bf528SMauro Carvalho Chehab 	default:
13319a0bf528SMauro Carvalho Chehab 		ret = dib8000_agc_soft_split(state);
13329a0bf528SMauro Carvalho Chehab 		break;
13339a0bf528SMauro Carvalho Chehab 	}
13349a0bf528SMauro Carvalho Chehab 	return ret;
13359a0bf528SMauro Carvalho Chehab 
13369a0bf528SMauro Carvalho Chehab }
13379a0bf528SMauro Carvalho Chehab 
13389a0bf528SMauro Carvalho Chehab static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
13399a0bf528SMauro Carvalho Chehab {
13409a0bf528SMauro Carvalho Chehab 	u16 reg;
13419a0bf528SMauro Carvalho Chehab 
13429a0bf528SMauro Carvalho Chehab 	drive &= 0x7;
13439a0bf528SMauro Carvalho Chehab 
13449a0bf528SMauro Carvalho Chehab 	/* drive host bus 2, 3, 4 */
13459a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1798) &
13469a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
13479a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
13489a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1798, reg);
13499a0bf528SMauro Carvalho Chehab 
13509a0bf528SMauro Carvalho Chehab 	/* drive host bus 5,6 */
13519a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
13529a0bf528SMauro Carvalho Chehab 	reg |= (drive<<8) | (drive<<2);
13539a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1799, reg);
13549a0bf528SMauro Carvalho Chehab 
13559a0bf528SMauro Carvalho Chehab 	/* drive host bus 7, 8, 9 */
13569a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1800) &
13579a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
13589a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
13599a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1800, reg);
13609a0bf528SMauro Carvalho Chehab 
13619a0bf528SMauro Carvalho Chehab 	/* drive host bus 10, 11 */
13629a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
13639a0bf528SMauro Carvalho Chehab 	reg |= (drive<<8) | (drive<<2);
13649a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1801, reg);
13659a0bf528SMauro Carvalho Chehab 
13669a0bf528SMauro Carvalho Chehab 	/* drive host bus 12, 13, 14 */
13679a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1802) &
13689a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
13699a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
13709a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1802, reg);
13719a0bf528SMauro Carvalho Chehab }
13729a0bf528SMauro Carvalho Chehab 
13739a0bf528SMauro Carvalho Chehab static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
13749a0bf528SMauro Carvalho Chehab 		u32 insertExtSynchro, u32 syncSize)
13759a0bf528SMauro Carvalho Chehab {
13769a0bf528SMauro Carvalho Chehab 	u32 quantif = 3;
13779a0bf528SMauro Carvalho Chehab 	u32 nom = (insertExtSynchro * P_Kin+syncSize);
13789a0bf528SMauro Carvalho Chehab 	u32 denom = P_Kout;
13799a0bf528SMauro Carvalho Chehab 	u32 syncFreq = ((nom << quantif) / denom);
13809a0bf528SMauro Carvalho Chehab 
13819a0bf528SMauro Carvalho Chehab 	if ((syncFreq & ((1 << quantif) - 1)) != 0)
13829a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif) + 1;
13839a0bf528SMauro Carvalho Chehab 	else
13849a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif);
13859a0bf528SMauro Carvalho Chehab 
13869a0bf528SMauro Carvalho Chehab 	if (syncFreq != 0)
13879a0bf528SMauro Carvalho Chehab 		syncFreq = syncFreq - 1;
13889a0bf528SMauro Carvalho Chehab 
13899a0bf528SMauro Carvalho Chehab 	return syncFreq;
13909a0bf528SMauro Carvalho Chehab }
13919a0bf528SMauro Carvalho Chehab 
13929a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
13939a0bf528SMauro Carvalho Chehab 		u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
13949a0bf528SMauro Carvalho Chehab 		u32 syncWord, u32 syncSize)
13959a0bf528SMauro Carvalho Chehab {
13969a0bf528SMauro Carvalho Chehab 	dprintk("Configure DibStream Tx");
13979a0bf528SMauro Carvalho Chehab 
13989a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1615, 1);
13999a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1603, P_Kin);
14009a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1605, P_Kout);
14019a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1606, insertExtSynchro);
14029a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1608, synchroMode);
14039a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
14049a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1610, syncWord & 0xffff);
14059a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1612, syncSize);
14069a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1615, 0);
14079a0bf528SMauro Carvalho Chehab }
14089a0bf528SMauro Carvalho Chehab 
14099a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
14109a0bf528SMauro Carvalho Chehab 		u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
14119a0bf528SMauro Carvalho Chehab 		u32 syncWord, u32 syncSize, u32 dataOutRate)
14129a0bf528SMauro Carvalho Chehab {
14139a0bf528SMauro Carvalho Chehab 	u32 syncFreq;
14149a0bf528SMauro Carvalho Chehab 
14159a0bf528SMauro Carvalho Chehab 	dprintk("Configure DibStream Rx synchroMode = %d", synchroMode);
14169a0bf528SMauro Carvalho Chehab 
14179a0bf528SMauro Carvalho Chehab 	if ((P_Kin != 0) && (P_Kout != 0)) {
14189a0bf528SMauro Carvalho Chehab 		syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
14199a0bf528SMauro Carvalho Chehab 				insertExtSynchro, syncSize);
14209a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1542, syncFreq);
14219a0bf528SMauro Carvalho Chehab 	}
14229a0bf528SMauro Carvalho Chehab 
14239a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1554, 1);
14249a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1536, P_Kin);
14259a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1537, P_Kout);
14269a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1539, synchroMode);
14279a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
14289a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1541, syncWord & 0xffff);
14299a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1543, syncSize);
14309a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1544, dataOutRate);
14319a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1554, 0);
14329a0bf528SMauro Carvalho Chehab }
14339a0bf528SMauro Carvalho Chehab 
14349a0bf528SMauro Carvalho Chehab static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
14359a0bf528SMauro Carvalho Chehab {
14369a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
14379a0bf528SMauro Carvalho Chehab 
14389a0bf528SMauro Carvalho Chehab 	reg_1287 = dib8000_read_word(state, 1287);
14399a0bf528SMauro Carvalho Chehab 
14409a0bf528SMauro Carvalho Chehab 	switch (onoff) {
14419a0bf528SMauro Carvalho Chehab 	case 1:
14429a0bf528SMauro Carvalho Chehab 			reg_1287 &= ~(1 << 8);
14439a0bf528SMauro Carvalho Chehab 			break;
14449a0bf528SMauro Carvalho Chehab 	case 0:
14459a0bf528SMauro Carvalho Chehab 			reg_1287 |= (1 << 8);
14469a0bf528SMauro Carvalho Chehab 			break;
14479a0bf528SMauro Carvalho Chehab 	}
14489a0bf528SMauro Carvalho Chehab 
14499a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1287, reg_1287);
14509a0bf528SMauro Carvalho Chehab }
14519a0bf528SMauro Carvalho Chehab 
14529a0bf528SMauro Carvalho Chehab static void dib8096p_configMpegMux(struct dib8000_state *state,
14539a0bf528SMauro Carvalho Chehab 		u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
14549a0bf528SMauro Carvalho Chehab {
14559a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
14569a0bf528SMauro Carvalho Chehab 
14579a0bf528SMauro Carvalho Chehab 	dprintk("Enable Mpeg mux");
14589a0bf528SMauro Carvalho Chehab 
14599a0bf528SMauro Carvalho Chehab 	dib8096p_enMpegMux(state, 0);
14609a0bf528SMauro Carvalho Chehab 
14619a0bf528SMauro Carvalho Chehab 	/* If the input mode is MPEG do not divide the serial clock */
14629a0bf528SMauro Carvalho Chehab 	if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
14639a0bf528SMauro Carvalho Chehab 		enSerialClkDiv2 = 0;
14649a0bf528SMauro Carvalho Chehab 
14659a0bf528SMauro Carvalho Chehab 	reg_1287 = ((pulseWidth & 0x1f) << 3) |
14669a0bf528SMauro Carvalho Chehab 		((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
14679a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1287, reg_1287);
14689a0bf528SMauro Carvalho Chehab 
14699a0bf528SMauro Carvalho Chehab 	dib8096p_enMpegMux(state, 1);
14709a0bf528SMauro Carvalho Chehab }
14719a0bf528SMauro Carvalho Chehab 
14729a0bf528SMauro Carvalho Chehab static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
14739a0bf528SMauro Carvalho Chehab {
14749a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
14759a0bf528SMauro Carvalho Chehab 
14769a0bf528SMauro Carvalho Chehab 	switch (mode) {
14779a0bf528SMauro Carvalho Chehab 	case MPEG_ON_DIBTX:
14789a0bf528SMauro Carvalho Chehab 			dprintk("SET MPEG ON DIBSTREAM TX");
14799a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
14809a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 9); break;
14819a0bf528SMauro Carvalho Chehab 	case DIV_ON_DIBTX:
14829a0bf528SMauro Carvalho Chehab 			dprintk("SET DIV_OUT ON DIBSTREAM TX");
14839a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
14849a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 8); break;
14859a0bf528SMauro Carvalho Chehab 	case ADC_ON_DIBTX:
14869a0bf528SMauro Carvalho Chehab 			dprintk("SET ADC_OUT ON DIBSTREAM TX");
14879a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
14889a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 7); break;
14899a0bf528SMauro Carvalho Chehab 	default:
14909a0bf528SMauro Carvalho Chehab 			break;
14919a0bf528SMauro Carvalho Chehab 	}
14929a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1288, reg_1288);
14939a0bf528SMauro Carvalho Chehab }
14949a0bf528SMauro Carvalho Chehab 
14959a0bf528SMauro Carvalho Chehab static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
14969a0bf528SMauro Carvalho Chehab {
14979a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
14989a0bf528SMauro Carvalho Chehab 
14999a0bf528SMauro Carvalho Chehab 	switch (mode) {
15009a0bf528SMauro Carvalho Chehab 	case DEMOUT_ON_HOSTBUS:
15019a0bf528SMauro Carvalho Chehab 			dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
15029a0bf528SMauro Carvalho Chehab 			dib8096p_enMpegMux(state, 0);
15039a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 6);
15049a0bf528SMauro Carvalho Chehab 			break;
15059a0bf528SMauro Carvalho Chehab 	case DIBTX_ON_HOSTBUS:
15069a0bf528SMauro Carvalho Chehab 			dprintk("SET DIBSTREAM TX ON HOST BUS");
15079a0bf528SMauro Carvalho Chehab 			dib8096p_enMpegMux(state, 0);
15089a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 5);
15099a0bf528SMauro Carvalho Chehab 			break;
15109a0bf528SMauro Carvalho Chehab 	case MPEG_ON_HOSTBUS:
15119a0bf528SMauro Carvalho Chehab 			dprintk("SET MPEG MUX ON HOST BUS");
15129a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 4);
15139a0bf528SMauro Carvalho Chehab 			break;
15149a0bf528SMauro Carvalho Chehab 	default:
15159a0bf528SMauro Carvalho Chehab 			break;
15169a0bf528SMauro Carvalho Chehab 	}
15179a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1288, reg_1288);
15189a0bf528SMauro Carvalho Chehab }
15199a0bf528SMauro Carvalho Chehab 
15209a0bf528SMauro Carvalho Chehab static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
15219a0bf528SMauro Carvalho Chehab {
15229a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
15239a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
15249a0bf528SMauro Carvalho Chehab 
15259a0bf528SMauro Carvalho Chehab 	switch (onoff) {
15269a0bf528SMauro Carvalho Chehab 	case 0: /* only use the internal way - not the diversity input */
15279a0bf528SMauro Carvalho Chehab 			dprintk("%s mode OFF : by default Enable Mpeg INPUT",
15289a0bf528SMauro Carvalho Chehab 					__func__);
15299a0bf528SMauro Carvalho Chehab 			/* outputRate = 8 */
15309a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
15319a0bf528SMauro Carvalho Chehab 
15329a0bf528SMauro Carvalho Chehab 			/* Do not divide the serial clock of MPEG MUX in
15339a0bf528SMauro Carvalho Chehab 			   SERIAL MODE in case input mode MPEG is used */
15349a0bf528SMauro Carvalho Chehab 			reg_1287 = dib8000_read_word(state, 1287);
15359a0bf528SMauro Carvalho Chehab 			/* enSerialClkDiv2 == 1 ? */
15369a0bf528SMauro Carvalho Chehab 			if ((reg_1287 & 0x1) == 1) {
15379a0bf528SMauro Carvalho Chehab 				/* force enSerialClkDiv2 = 0 */
15389a0bf528SMauro Carvalho Chehab 				reg_1287 &= ~0x1;
15399a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, 1287, reg_1287);
15409a0bf528SMauro Carvalho Chehab 			}
15419a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 1;
15429a0bf528SMauro Carvalho Chehab 			break;
15439a0bf528SMauro Carvalho Chehab 	case 1: /* both ways */
15449a0bf528SMauro Carvalho Chehab 	case 2: /* only the diversity input */
15459a0bf528SMauro Carvalho Chehab 			dprintk("%s ON : Enable diversity INPUT", __func__);
15469a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
15479a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 0;
15489a0bf528SMauro Carvalho Chehab 			break;
15499a0bf528SMauro Carvalho Chehab 	}
15509a0bf528SMauro Carvalho Chehab 
15519a0bf528SMauro Carvalho Chehab 	dib8000_set_diversity_in(state->fe[0], onoff);
15529a0bf528SMauro Carvalho Chehab 	return 0;
15539a0bf528SMauro Carvalho Chehab }
15549a0bf528SMauro Carvalho Chehab 
15559a0bf528SMauro Carvalho Chehab static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
15569a0bf528SMauro Carvalho Chehab {
15579a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
15589a0bf528SMauro Carvalho Chehab 	u16 outreg, smo_mode, fifo_threshold;
15599a0bf528SMauro Carvalho Chehab 	u8 prefer_mpeg_mux_use = 1;
15609a0bf528SMauro Carvalho Chehab 	int ret = 0;
15619a0bf528SMauro Carvalho Chehab 
1562173a64cbSPatrick Boettcher 	state->output_mode = mode;
15639a0bf528SMauro Carvalho Chehab 	dib8096p_host_bus_drive(state, 1);
15649a0bf528SMauro Carvalho Chehab 
15659a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
15669a0bf528SMauro Carvalho Chehab 	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
15679a0bf528SMauro Carvalho Chehab 	outreg   = dib8000_read_word(state, 1286) &
15689a0bf528SMauro Carvalho Chehab 		~((1 << 10) | (0x7 << 6) | (1 << 1));
15699a0bf528SMauro Carvalho Chehab 
15709a0bf528SMauro Carvalho Chehab 	switch (mode) {
15719a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:
15729a0bf528SMauro Carvalho Chehab 			outreg = 0;
15739a0bf528SMauro Carvalho Chehab 			break;
15749a0bf528SMauro Carvalho Chehab 
15759a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:
15769a0bf528SMauro Carvalho Chehab 			if (prefer_mpeg_mux_use) {
15779a0bf528SMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux");
15789a0bf528SMauro Carvalho Chehab 				dib8096p_configMpegMux(state, 3, 1, 1);
15799a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
15809a0bf528SMauro Carvalho Chehab 			} else {/* Use Smooth block */
15819a0bf528SMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc");
15829a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state,
15839a0bf528SMauro Carvalho Chehab 						DEMOUT_ON_HOSTBUS);
15849a0bf528SMauro Carvalho Chehab 				outreg |= (2 << 6) | (0 << 1);
15859a0bf528SMauro Carvalho Chehab 			}
15869a0bf528SMauro Carvalho Chehab 			break;
15879a0bf528SMauro Carvalho Chehab 
15889a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:
15899a0bf528SMauro Carvalho Chehab 			if (prefer_mpeg_mux_use) {
15909a0bf528SMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
15919a0bf528SMauro Carvalho Chehab 				dib8096p_configMpegMux(state, 2, 0, 0);
15929a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
15939a0bf528SMauro Carvalho Chehab 			} else { /* Use Smooth block */
15949a0bf528SMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block");
15959a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state,
15969a0bf528SMauro Carvalho Chehab 						DEMOUT_ON_HOSTBUS);
15979a0bf528SMauro Carvalho Chehab 				outreg |= (0 << 6);
15989a0bf528SMauro Carvalho Chehab 			}
15999a0bf528SMauro Carvalho Chehab 			break;
16009a0bf528SMauro Carvalho Chehab 
16019a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
16029a0bf528SMauro Carvalho Chehab 			dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block");
16039a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
16049a0bf528SMauro Carvalho Chehab 			outreg |= (1 << 6);
16059a0bf528SMauro Carvalho Chehab 			break;
16069a0bf528SMauro Carvalho Chehab 
16079a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:
16089a0bf528SMauro Carvalho Chehab 			/* Using Smooth block because not supported
16099a0bf528SMauro Carvalho Chehab 			   by new Mpeg Mux bloc */
16109a0bf528SMauro Carvalho Chehab 			dprintk("dib8096P setting output mode TS_FIFO using Smooth block");
16119a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
16129a0bf528SMauro Carvalho Chehab 			outreg |= (5 << 6);
16139a0bf528SMauro Carvalho Chehab 			smo_mode |= (3 << 1);
16149a0bf528SMauro Carvalho Chehab 			fifo_threshold = 512;
16159a0bf528SMauro Carvalho Chehab 			break;
16169a0bf528SMauro Carvalho Chehab 
16179a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
16189a0bf528SMauro Carvalho Chehab 			dprintk("dib8096P setting output mode MODE_DIVERSITY");
16199a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
16209a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
16219a0bf528SMauro Carvalho Chehab 			break;
16229a0bf528SMauro Carvalho Chehab 
16239a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
16249a0bf528SMauro Carvalho Chehab 			dprintk("dib8096P setting output mode MODE_ANALOG_ADC");
16259a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
16269a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
16279a0bf528SMauro Carvalho Chehab 			break;
16289a0bf528SMauro Carvalho Chehab 	}
16299a0bf528SMauro Carvalho Chehab 
16309a0bf528SMauro Carvalho Chehab 	if (mode != OUTMODE_HIGH_Z)
16319a0bf528SMauro Carvalho Chehab 		outreg |= (1<<10);
16329a0bf528SMauro Carvalho Chehab 
16339a0bf528SMauro Carvalho Chehab 	dprintk("output_mpeg2_in_188_bytes = %d",
16349a0bf528SMauro Carvalho Chehab 			state->cfg.output_mpeg2_in_188_bytes);
16359a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
16369a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
16379a0bf528SMauro Carvalho Chehab 
16389a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 299, smo_mode);
16399a0bf528SMauro Carvalho Chehab 	/* synchronous fread */
16409a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
16419a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 1286, outreg);
16429a0bf528SMauro Carvalho Chehab 
16439a0bf528SMauro Carvalho Chehab 	return ret;
16449a0bf528SMauro Carvalho Chehab }
16459a0bf528SMauro Carvalho Chehab 
16469a0bf528SMauro Carvalho Chehab static int map_addr_to_serpar_number(struct i2c_msg *msg)
16479a0bf528SMauro Carvalho Chehab {
16489a0bf528SMauro Carvalho Chehab 	if (msg->buf[0] <= 15)
16499a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 1;
16509a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 17)
16519a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 15;
16529a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 16)
16539a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 17;
16549a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 19)
16559a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 16;
16569a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
16579a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 3;
16589a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 28)
16599a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 23;
16609a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 99)
16619a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 99;
16629a0bf528SMauro Carvalho Chehab 	else
16639a0bf528SMauro Carvalho Chehab 		return -EINVAL;
16649a0bf528SMauro Carvalho Chehab 	return 0;
16659a0bf528SMauro Carvalho Chehab }
16669a0bf528SMauro Carvalho Chehab 
16679a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
16689a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
16699a0bf528SMauro Carvalho Chehab {
16709a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
16719a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1;
16729a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
16739a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
16749a0bf528SMauro Carvalho Chehab 
16759a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
16769a0bf528SMauro Carvalho Chehab 		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
16779a0bf528SMauro Carvalho Chehab 		i--;
16789a0bf528SMauro Carvalho Chehab 		if (i == 0)
16799a0bf528SMauro Carvalho Chehab 			dprintk("Tuner ITF: write busy (overflow)");
16809a0bf528SMauro Carvalho Chehab 	}
16819a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
16829a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
16839a0bf528SMauro Carvalho Chehab 
16849a0bf528SMauro Carvalho Chehab 	return num;
16859a0bf528SMauro Carvalho Chehab }
16869a0bf528SMauro Carvalho Chehab 
16879a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
16889a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
16899a0bf528SMauro Carvalho Chehab {
16909a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
16919a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1, n_empty = 1;
16929a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
16939a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
16949a0bf528SMauro Carvalho Chehab 	u16 read_word;
16959a0bf528SMauro Carvalho Chehab 
16969a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
16979a0bf528SMauro Carvalho Chehab 		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
16989a0bf528SMauro Carvalho Chehab 		i--;
16999a0bf528SMauro Carvalho Chehab 		if (i == 0)
17009a0bf528SMauro Carvalho Chehab 			dprintk("TunerITF: read busy (overflow)");
17019a0bf528SMauro Carvalho Chehab 	}
17029a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
17039a0bf528SMauro Carvalho Chehab 
17049a0bf528SMauro Carvalho Chehab 	i = 1000;
17059a0bf528SMauro Carvalho Chehab 	while (n_empty == 1 && i) {
17069a0bf528SMauro Carvalho Chehab 		n_empty = dib8000_read_word(state, 1984)&0x1;
17079a0bf528SMauro Carvalho Chehab 		i--;
17089a0bf528SMauro Carvalho Chehab 		if (i == 0)
17099a0bf528SMauro Carvalho Chehab 			dprintk("TunerITF: read busy (empty)");
17109a0bf528SMauro Carvalho Chehab 	}
17119a0bf528SMauro Carvalho Chehab 
17129a0bf528SMauro Carvalho Chehab 	read_word = dib8000_read_word(state, 1987);
17139a0bf528SMauro Carvalho Chehab 	msg[1].buf[0] = (read_word >> 8) & 0xff;
17149a0bf528SMauro Carvalho Chehab 	msg[1].buf[1] = (read_word) & 0xff;
17159a0bf528SMauro Carvalho Chehab 
17169a0bf528SMauro Carvalho Chehab 	return num;
17179a0bf528SMauro Carvalho Chehab }
17189a0bf528SMauro Carvalho Chehab 
17199a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
17209a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
17219a0bf528SMauro Carvalho Chehab {
17229a0bf528SMauro Carvalho Chehab 	if (map_addr_to_serpar_number(&msg[0]) == 0) {
17239a0bf528SMauro Carvalho Chehab 		if (num == 1) /* write */
17249a0bf528SMauro Carvalho Chehab 			return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
17259a0bf528SMauro Carvalho Chehab 		else /* read */
17269a0bf528SMauro Carvalho Chehab 			return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
17279a0bf528SMauro Carvalho Chehab 	}
17289a0bf528SMauro Carvalho Chehab 	return num;
17299a0bf528SMauro Carvalho Chehab }
17309a0bf528SMauro Carvalho Chehab 
17319a0bf528SMauro Carvalho Chehab static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
17329a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num, u16 apb_address)
17339a0bf528SMauro Carvalho Chehab {
17349a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
17359a0bf528SMauro Carvalho Chehab 	u16 word;
17369a0bf528SMauro Carvalho Chehab 
17379a0bf528SMauro Carvalho Chehab 	if (num == 1) {		/* write */
17389a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, apb_address,
17399a0bf528SMauro Carvalho Chehab 				((msg[0].buf[1] << 8) | (msg[0].buf[2])));
17409a0bf528SMauro Carvalho Chehab 	} else {
17419a0bf528SMauro Carvalho Chehab 		word = dib8000_read_word(state, apb_address);
17429a0bf528SMauro Carvalho Chehab 		msg[1].buf[0] = (word >> 8) & 0xff;
17439a0bf528SMauro Carvalho Chehab 		msg[1].buf[1] = (word) & 0xff;
17449a0bf528SMauro Carvalho Chehab 	}
17459a0bf528SMauro Carvalho Chehab 	return num;
17469a0bf528SMauro Carvalho Chehab }
17479a0bf528SMauro Carvalho Chehab 
17489a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
17499a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
17509a0bf528SMauro Carvalho Chehab {
17519a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
17529a0bf528SMauro Carvalho Chehab 	u16 apb_address = 0, word;
17539a0bf528SMauro Carvalho Chehab 	int i = 0;
17549a0bf528SMauro Carvalho Chehab 
17559a0bf528SMauro Carvalho Chehab 	switch (msg[0].buf[0]) {
17569a0bf528SMauro Carvalho Chehab 	case 0x12:
17579a0bf528SMauro Carvalho Chehab 			apb_address = 1920;
17589a0bf528SMauro Carvalho Chehab 			break;
17599a0bf528SMauro Carvalho Chehab 	case 0x14:
17609a0bf528SMauro Carvalho Chehab 			apb_address = 1921;
17619a0bf528SMauro Carvalho Chehab 			break;
17629a0bf528SMauro Carvalho Chehab 	case 0x24:
17639a0bf528SMauro Carvalho Chehab 			apb_address = 1922;
17649a0bf528SMauro Carvalho Chehab 			break;
17659a0bf528SMauro Carvalho Chehab 	case 0x1a:
17669a0bf528SMauro Carvalho Chehab 			apb_address = 1923;
17679a0bf528SMauro Carvalho Chehab 			break;
17689a0bf528SMauro Carvalho Chehab 	case 0x22:
17699a0bf528SMauro Carvalho Chehab 			apb_address = 1924;
17709a0bf528SMauro Carvalho Chehab 			break;
17719a0bf528SMauro Carvalho Chehab 	case 0x33:
17729a0bf528SMauro Carvalho Chehab 			apb_address = 1926;
17739a0bf528SMauro Carvalho Chehab 			break;
17749a0bf528SMauro Carvalho Chehab 	case 0x34:
17759a0bf528SMauro Carvalho Chehab 			apb_address = 1927;
17769a0bf528SMauro Carvalho Chehab 			break;
17779a0bf528SMauro Carvalho Chehab 	case 0x35:
17789a0bf528SMauro Carvalho Chehab 			apb_address = 1928;
17799a0bf528SMauro Carvalho Chehab 			break;
17809a0bf528SMauro Carvalho Chehab 	case 0x36:
17819a0bf528SMauro Carvalho Chehab 			apb_address = 1929;
17829a0bf528SMauro Carvalho Chehab 			break;
17839a0bf528SMauro Carvalho Chehab 	case 0x37:
17849a0bf528SMauro Carvalho Chehab 			apb_address = 1930;
17859a0bf528SMauro Carvalho Chehab 			break;
17869a0bf528SMauro Carvalho Chehab 	case 0x38:
17879a0bf528SMauro Carvalho Chehab 			apb_address = 1931;
17889a0bf528SMauro Carvalho Chehab 			break;
17899a0bf528SMauro Carvalho Chehab 	case 0x39:
17909a0bf528SMauro Carvalho Chehab 			apb_address = 1932;
17919a0bf528SMauro Carvalho Chehab 			break;
17929a0bf528SMauro Carvalho Chehab 	case 0x2a:
17939a0bf528SMauro Carvalho Chehab 			apb_address = 1935;
17949a0bf528SMauro Carvalho Chehab 			break;
17959a0bf528SMauro Carvalho Chehab 	case 0x2b:
17969a0bf528SMauro Carvalho Chehab 			apb_address = 1936;
17979a0bf528SMauro Carvalho Chehab 			break;
17989a0bf528SMauro Carvalho Chehab 	case 0x2c:
17999a0bf528SMauro Carvalho Chehab 			apb_address = 1937;
18009a0bf528SMauro Carvalho Chehab 			break;
18019a0bf528SMauro Carvalho Chehab 	case 0x2d:
18029a0bf528SMauro Carvalho Chehab 			apb_address = 1938;
18039a0bf528SMauro Carvalho Chehab 			break;
18049a0bf528SMauro Carvalho Chehab 	case 0x2e:
18059a0bf528SMauro Carvalho Chehab 			apb_address = 1939;
18069a0bf528SMauro Carvalho Chehab 			break;
18079a0bf528SMauro Carvalho Chehab 	case 0x2f:
18089a0bf528SMauro Carvalho Chehab 			apb_address = 1940;
18099a0bf528SMauro Carvalho Chehab 			break;
18109a0bf528SMauro Carvalho Chehab 	case 0x30:
18119a0bf528SMauro Carvalho Chehab 			apb_address = 1941;
18129a0bf528SMauro Carvalho Chehab 			break;
18139a0bf528SMauro Carvalho Chehab 	case 0x31:
18149a0bf528SMauro Carvalho Chehab 			apb_address = 1942;
18159a0bf528SMauro Carvalho Chehab 			break;
18169a0bf528SMauro Carvalho Chehab 	case 0x32:
18179a0bf528SMauro Carvalho Chehab 			apb_address = 1943;
18189a0bf528SMauro Carvalho Chehab 			break;
18199a0bf528SMauro Carvalho Chehab 	case 0x3e:
18209a0bf528SMauro Carvalho Chehab 			apb_address = 1944;
18219a0bf528SMauro Carvalho Chehab 			break;
18229a0bf528SMauro Carvalho Chehab 	case 0x3f:
18239a0bf528SMauro Carvalho Chehab 			apb_address = 1945;
18249a0bf528SMauro Carvalho Chehab 			break;
18259a0bf528SMauro Carvalho Chehab 	case 0x40:
18269a0bf528SMauro Carvalho Chehab 			apb_address = 1948;
18279a0bf528SMauro Carvalho Chehab 			break;
18289a0bf528SMauro Carvalho Chehab 	case 0x25:
18299a0bf528SMauro Carvalho Chehab 			apb_address = 936;
18309a0bf528SMauro Carvalho Chehab 			break;
18319a0bf528SMauro Carvalho Chehab 	case 0x26:
18329a0bf528SMauro Carvalho Chehab 			apb_address = 937;
18339a0bf528SMauro Carvalho Chehab 			break;
18349a0bf528SMauro Carvalho Chehab 	case 0x27:
18359a0bf528SMauro Carvalho Chehab 			apb_address = 938;
18369a0bf528SMauro Carvalho Chehab 			break;
18379a0bf528SMauro Carvalho Chehab 	case 0x28:
18389a0bf528SMauro Carvalho Chehab 			apb_address = 939;
18399a0bf528SMauro Carvalho Chehab 			break;
18409a0bf528SMauro Carvalho Chehab 	case 0x1d:
18419a0bf528SMauro Carvalho Chehab 			/* get sad sel request */
18429a0bf528SMauro Carvalho Chehab 			i = ((dib8000_read_word(state, 921) >> 12)&0x3);
18439a0bf528SMauro Carvalho Chehab 			word = dib8000_read_word(state, 924+i);
18449a0bf528SMauro Carvalho Chehab 			msg[1].buf[0] = (word >> 8) & 0xff;
18459a0bf528SMauro Carvalho Chehab 			msg[1].buf[1] = (word) & 0xff;
18469a0bf528SMauro Carvalho Chehab 			return num;
18479a0bf528SMauro Carvalho Chehab 	case 0x1f:
18489a0bf528SMauro Carvalho Chehab 			if (num == 1) {	/* write */
18499a0bf528SMauro Carvalho Chehab 				word = (u16) ((msg[0].buf[1] << 8) |
18509a0bf528SMauro Carvalho Chehab 						msg[0].buf[2]);
18519a0bf528SMauro Carvalho Chehab 				/* in the VGAMODE Sel are located on bit 0/1 */
18529a0bf528SMauro Carvalho Chehab 				word &= 0x3;
18539a0bf528SMauro Carvalho Chehab 				word = (dib8000_read_word(state, 921) &
18549a0bf528SMauro Carvalho Chehab 						~(3<<12)) | (word<<12);
18559a0bf528SMauro Carvalho Chehab 				/* Set the proper input */
18569a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, 921, word);
18579a0bf528SMauro Carvalho Chehab 				return num;
18589a0bf528SMauro Carvalho Chehab 			}
18599a0bf528SMauro Carvalho Chehab 	}
18609a0bf528SMauro Carvalho Chehab 
18619a0bf528SMauro Carvalho Chehab 	if (apb_address != 0) /* R/W acces via APB */
18629a0bf528SMauro Carvalho Chehab 		return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
18639a0bf528SMauro Carvalho Chehab 	else  /* R/W access via SERPAR  */
18649a0bf528SMauro Carvalho Chehab 		return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
18659a0bf528SMauro Carvalho Chehab 
18669a0bf528SMauro Carvalho Chehab 	return 0;
18679a0bf528SMauro Carvalho Chehab }
18689a0bf528SMauro Carvalho Chehab 
18699a0bf528SMauro Carvalho Chehab static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
18709a0bf528SMauro Carvalho Chehab {
18719a0bf528SMauro Carvalho Chehab 	return I2C_FUNC_I2C;
18729a0bf528SMauro Carvalho Chehab }
18739a0bf528SMauro Carvalho Chehab 
18749a0bf528SMauro Carvalho Chehab static struct i2c_algorithm dib8096p_tuner_xfer_algo = {
18759a0bf528SMauro Carvalho Chehab 	.master_xfer = dib8096p_tuner_xfer,
18769a0bf528SMauro Carvalho Chehab 	.functionality = dib8096p_i2c_func,
18779a0bf528SMauro Carvalho Chehab };
18789a0bf528SMauro Carvalho Chehab 
1879d44913c1SMauro Carvalho Chehab static struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
18809a0bf528SMauro Carvalho Chehab {
18819a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
18829a0bf528SMauro Carvalho Chehab 	return &st->dib8096p_tuner_adap;
18839a0bf528SMauro Carvalho Chehab }
18849a0bf528SMauro Carvalho Chehab 
1885d44913c1SMauro Carvalho Chehab static int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
18869a0bf528SMauro Carvalho Chehab {
18879a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
18889a0bf528SMauro Carvalho Chehab 	u16 en_cur_state;
18899a0bf528SMauro Carvalho Chehab 
18909a0bf528SMauro Carvalho Chehab 	dprintk("sleep dib8096p: %d", onoff);
18919a0bf528SMauro Carvalho Chehab 
18929a0bf528SMauro Carvalho Chehab 	en_cur_state = dib8000_read_word(state, 1922);
18939a0bf528SMauro Carvalho Chehab 
18949a0bf528SMauro Carvalho Chehab 	/* LNAs and MIX are ON and therefore it is a valid configuration */
18959a0bf528SMauro Carvalho Chehab 	if (en_cur_state > 0xff)
18969a0bf528SMauro Carvalho Chehab 		state->tuner_enable = en_cur_state ;
18979a0bf528SMauro Carvalho Chehab 
18989a0bf528SMauro Carvalho Chehab 	if (onoff)
18999a0bf528SMauro Carvalho Chehab 		en_cur_state &= 0x00ff;
19009a0bf528SMauro Carvalho Chehab 	else {
19019a0bf528SMauro Carvalho Chehab 		if (state->tuner_enable != 0)
19029a0bf528SMauro Carvalho Chehab 			en_cur_state = state->tuner_enable;
19039a0bf528SMauro Carvalho Chehab 	}
19049a0bf528SMauro Carvalho Chehab 
19059a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1922, en_cur_state);
19069a0bf528SMauro Carvalho Chehab 
19079a0bf528SMauro Carvalho Chehab 	return 0;
19089a0bf528SMauro Carvalho Chehab }
19099a0bf528SMauro Carvalho Chehab 
19109a0bf528SMauro Carvalho Chehab static const s32 lut_1000ln_mant[] =
19119a0bf528SMauro Carvalho Chehab {
19129a0bf528SMauro Carvalho Chehab 	908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
19139a0bf528SMauro Carvalho Chehab };
19149a0bf528SMauro Carvalho Chehab 
1915d44913c1SMauro Carvalho Chehab static s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
19169a0bf528SMauro Carvalho Chehab {
19179a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
19189a0bf528SMauro Carvalho Chehab 	u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
19199a0bf528SMauro Carvalho Chehab 	s32 val;
19209a0bf528SMauro Carvalho Chehab 
19219a0bf528SMauro Carvalho Chehab 	val = dib8000_read32(state, 384);
19229a0bf528SMauro Carvalho Chehab 	if (mode) {
19239a0bf528SMauro Carvalho Chehab 		tmp_val = val;
19249a0bf528SMauro Carvalho Chehab 		while (tmp_val >>= 1)
19259a0bf528SMauro Carvalho Chehab 			exp++;
19269a0bf528SMauro Carvalho Chehab 		mant = (val * 1000 / (1<<exp));
19279a0bf528SMauro Carvalho Chehab 		ix = (u8)((mant-1000)/100); /* index of the LUT */
19289a0bf528SMauro Carvalho Chehab 		val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
19299a0bf528SMauro Carvalho Chehab 		val = (val*256)/1000;
19309a0bf528SMauro Carvalho Chehab 	}
19319a0bf528SMauro Carvalho Chehab 	return val;
19329a0bf528SMauro Carvalho Chehab }
19339a0bf528SMauro Carvalho Chehab 
1934d44913c1SMauro Carvalho Chehab static int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
19359a0bf528SMauro Carvalho Chehab {
19369a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
19379a0bf528SMauro Carvalho Chehab 	int val = 0;
19389a0bf528SMauro Carvalho Chehab 
19399a0bf528SMauro Carvalho Chehab 	switch (IQ) {
19409a0bf528SMauro Carvalho Chehab 	case 1:
19419a0bf528SMauro Carvalho Chehab 			val = dib8000_read_word(state, 403);
19429a0bf528SMauro Carvalho Chehab 			break;
19439a0bf528SMauro Carvalho Chehab 	case 0:
19449a0bf528SMauro Carvalho Chehab 			val = dib8000_read_word(state, 404);
19459a0bf528SMauro Carvalho Chehab 			break;
19469a0bf528SMauro Carvalho Chehab 	}
19479a0bf528SMauro Carvalho Chehab 	if (val  & 0x200)
19489a0bf528SMauro Carvalho Chehab 		val -= 1024;
19499a0bf528SMauro Carvalho Chehab 
19509a0bf528SMauro Carvalho Chehab 	return val;
19519a0bf528SMauro Carvalho Chehab }
19529a0bf528SMauro Carvalho Chehab 
19539a0bf528SMauro Carvalho Chehab static void dib8000_update_timf(struct dib8000_state *state)
19549a0bf528SMauro Carvalho Chehab {
19559a0bf528SMauro Carvalho Chehab 	u32 timf = state->timf = dib8000_read32(state, 435);
19569a0bf528SMauro Carvalho Chehab 
19579a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 29, (u16) (timf >> 16));
19589a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 30, (u16) (timf & 0xffff));
19599a0bf528SMauro Carvalho Chehab 	dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
19609a0bf528SMauro Carvalho Chehab }
19619a0bf528SMauro Carvalho Chehab 
1962d44913c1SMauro Carvalho Chehab static u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
19639a0bf528SMauro Carvalho Chehab {
19649a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
19659a0bf528SMauro Carvalho Chehab 
19669a0bf528SMauro Carvalho Chehab 	switch (op) {
19679a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_SET:
19689a0bf528SMauro Carvalho Chehab 			state->timf = timf;
19699a0bf528SMauro Carvalho Chehab 			break;
19709a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_UPDATE:
19719a0bf528SMauro Carvalho Chehab 			dib8000_update_timf(state);
19729a0bf528SMauro Carvalho Chehab 			break;
19739a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_GET:
19749a0bf528SMauro Carvalho Chehab 			break;
19759a0bf528SMauro Carvalho Chehab 	}
19769a0bf528SMauro Carvalho Chehab 	dib8000_set_bandwidth(state->fe[0], 6000);
19779a0bf528SMauro Carvalho Chehab 
19789a0bf528SMauro Carvalho Chehab 	return state->timf;
19799a0bf528SMauro Carvalho Chehab }
19809a0bf528SMauro Carvalho Chehab 
19819a0bf528SMauro Carvalho Chehab static const u16 adc_target_16dB[11] = {
19829a0bf528SMauro Carvalho Chehab 	(1 << 13) - 825 - 117,
19839a0bf528SMauro Carvalho Chehab 	(1 << 13) - 837 - 117,
19849a0bf528SMauro Carvalho Chehab 	(1 << 13) - 811 - 117,
19859a0bf528SMauro Carvalho Chehab 	(1 << 13) - 766 - 117,
19869a0bf528SMauro Carvalho Chehab 	(1 << 13) - 737 - 117,
19879a0bf528SMauro Carvalho Chehab 	(1 << 13) - 693 - 117,
19889a0bf528SMauro Carvalho Chehab 	(1 << 13) - 648 - 117,
19899a0bf528SMauro Carvalho Chehab 	(1 << 13) - 619 - 117,
19909a0bf528SMauro Carvalho Chehab 	(1 << 13) - 575 - 117,
19919a0bf528SMauro Carvalho Chehab 	(1 << 13) - 531 - 117,
19929a0bf528SMauro Carvalho Chehab 	(1 << 13) - 501 - 117
19939a0bf528SMauro Carvalho Chehab };
19949a0bf528SMauro Carvalho Chehab static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
19959a0bf528SMauro Carvalho Chehab 
1996173a64cbSPatrick Boettcher static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
19979a0bf528SMauro Carvalho Chehab {
1998173a64cbSPatrick Boettcher 	u8  cr, constellation, time_intlv;
1999c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
20009a0bf528SMauro Carvalho Chehab 
2001c82056d0SMauro Carvalho Chehab 	switch (c->layer[layer_index].modulation) {
20029a0bf528SMauro Carvalho Chehab 	case DQPSK:
20039a0bf528SMauro Carvalho Chehab 			constellation = 0;
20049a0bf528SMauro Carvalho Chehab 			break;
20059a0bf528SMauro Carvalho Chehab 	case  QPSK:
20069a0bf528SMauro Carvalho Chehab 			constellation = 1;
20079a0bf528SMauro Carvalho Chehab 			break;
20089a0bf528SMauro Carvalho Chehab 	case QAM_16:
20099a0bf528SMauro Carvalho Chehab 			constellation = 2;
20109a0bf528SMauro Carvalho Chehab 			break;
20119a0bf528SMauro Carvalho Chehab 	case QAM_64:
20129a0bf528SMauro Carvalho Chehab 	default:
20139a0bf528SMauro Carvalho Chehab 			constellation = 3;
20149a0bf528SMauro Carvalho Chehab 			break;
20159a0bf528SMauro Carvalho Chehab 	}
20169a0bf528SMauro Carvalho Chehab 
2017c82056d0SMauro Carvalho Chehab 	switch (c->layer[layer_index].fec) {
20189a0bf528SMauro Carvalho Chehab 	case FEC_1_2:
2019173a64cbSPatrick Boettcher 			cr = 1;
20209a0bf528SMauro Carvalho Chehab 			break;
20219a0bf528SMauro Carvalho Chehab 	case FEC_2_3:
2022173a64cbSPatrick Boettcher 			cr = 2;
20239a0bf528SMauro Carvalho Chehab 			break;
20249a0bf528SMauro Carvalho Chehab 	case FEC_3_4:
2025173a64cbSPatrick Boettcher 			cr = 3;
20269a0bf528SMauro Carvalho Chehab 			break;
20279a0bf528SMauro Carvalho Chehab 	case FEC_5_6:
2028173a64cbSPatrick Boettcher 			cr = 5;
20299a0bf528SMauro Carvalho Chehab 			break;
20309a0bf528SMauro Carvalho Chehab 	case FEC_7_8:
20319a0bf528SMauro Carvalho Chehab 	default:
2032173a64cbSPatrick Boettcher 			cr = 7;
20339a0bf528SMauro Carvalho Chehab 			break;
20349a0bf528SMauro Carvalho Chehab 	}
20359a0bf528SMauro Carvalho Chehab 
203634ba2e65SMauro Carvalho Chehab 	time_intlv = fls(c->layer[layer_index].interleaving);
203734ba2e65SMauro Carvalho Chehab 	if (time_intlv > 3 && !(time_intlv == 4 && c->isdbt_sb_mode == 1))
2038173a64cbSPatrick Boettcher 		time_intlv = 0;
2039173a64cbSPatrick Boettcher 
2040c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
2041c82056d0SMauro Carvalho Chehab 	if (c->layer[layer_index].segment_count > 0) {
20429a0bf528SMauro Carvalho Chehab 		switch (max_constellation) {
20439a0bf528SMauro Carvalho Chehab 		case DQPSK:
20449a0bf528SMauro Carvalho Chehab 		case QPSK:
2045c82056d0SMauro Carvalho Chehab 				if (c->layer[layer_index].modulation == QAM_16 || c->layer[layer_index].modulation == QAM_64)
2046c82056d0SMauro Carvalho Chehab 					max_constellation = c->layer[layer_index].modulation;
20479a0bf528SMauro Carvalho Chehab 				break;
20489a0bf528SMauro Carvalho Chehab 		case QAM_16:
2049c82056d0SMauro Carvalho Chehab 				if (c->layer[layer_index].modulation == QAM_64)
2050c82056d0SMauro Carvalho Chehab 					max_constellation = c->layer[layer_index].modulation;
20519a0bf528SMauro Carvalho Chehab 				break;
20529a0bf528SMauro Carvalho Chehab 		}
20539a0bf528SMauro Carvalho Chehab 	}
2054173a64cbSPatrick Boettcher 
2055173a64cbSPatrick Boettcher 	return  max_constellation;
20569a0bf528SMauro Carvalho Chehab }
20579a0bf528SMauro Carvalho Chehab 
2058173a64cbSPatrick 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 */
2059173a64cbSPatrick 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 */
2060173a64cbSPatrick 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 */
2061173a64cbSPatrick Boettcher static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation)
2062173a64cbSPatrick Boettcher {
2063173a64cbSPatrick Boettcher 	u16 i, ana_gain = 0;
2064173a64cbSPatrick Boettcher 	const u16 *adp;
20659a0bf528SMauro Carvalho Chehab 
2066173a64cbSPatrick Boettcher 	/* channel estimation fine configuration */
2067173a64cbSPatrick Boettcher 	switch (max_constellation) {
2068173a64cbSPatrick Boettcher 	case QAM_64:
2069173a64cbSPatrick Boettcher 			ana_gain = 0x7;
2070173a64cbSPatrick Boettcher 			adp = &adp_Q64[0];
2071173a64cbSPatrick Boettcher 			break;
2072173a64cbSPatrick Boettcher 	case QAM_16:
2073173a64cbSPatrick Boettcher 			ana_gain = 0x7;
2074173a64cbSPatrick Boettcher 			adp = &adp_Q16[0];
2075173a64cbSPatrick Boettcher 			break;
2076173a64cbSPatrick Boettcher 	default:
2077173a64cbSPatrick Boettcher 			ana_gain = 0;
2078173a64cbSPatrick Boettcher 			adp = &adp_Qdefault[0];
2079173a64cbSPatrick Boettcher 			break;
20809a0bf528SMauro Carvalho Chehab 	}
20819a0bf528SMauro Carvalho Chehab 
2082173a64cbSPatrick Boettcher 	for (i = 0; i < 4; i++)
2083173a64cbSPatrick Boettcher 		dib8000_write_word(state, 215 + i, adp[i]);
20849a0bf528SMauro Carvalho Chehab 
2085173a64cbSPatrick Boettcher 	return ana_gain;
2086173a64cbSPatrick Boettcher }
20879a0bf528SMauro Carvalho Chehab 
2088173a64cbSPatrick Boettcher static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain)
2089173a64cbSPatrick Boettcher {
2090173a64cbSPatrick Boettcher 	u16 i;
20919a0bf528SMauro Carvalho Chehab 
2092173a64cbSPatrick Boettcher 	dib8000_write_word(state, 116, ana_gain);
20939a0bf528SMauro Carvalho Chehab 
2094173a64cbSPatrick Boettcher 	/* update ADC target depending on ana_gain */
2095173a64cbSPatrick Boettcher 	if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */
2096173a64cbSPatrick Boettcher 		for (i = 0; i < 10; i++)
2097173a64cbSPatrick Boettcher 			dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
2098173a64cbSPatrick Boettcher 	} else { /* set -22dB ADC target for ana_gain=0 */
2099173a64cbSPatrick Boettcher 		for (i = 0; i < 10; i++)
2100173a64cbSPatrick Boettcher 			dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
2101173a64cbSPatrick Boettcher 	}
2102173a64cbSPatrick Boettcher }
21039a0bf528SMauro Carvalho Chehab 
2104173a64cbSPatrick Boettcher static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
2105173a64cbSPatrick Boettcher {
2106173a64cbSPatrick Boettcher 	u16 mode = 0;
21079a0bf528SMauro Carvalho Chehab 
2108173a64cbSPatrick Boettcher 	if (state->isdbt_cfg_loaded == 0)
2109173a64cbSPatrick Boettcher 		for (mode = 0; mode < 24; mode++)
2110173a64cbSPatrick Boettcher 			dib8000_write_word(state, 117 + mode, ana_fe[mode]);
2111173a64cbSPatrick Boettcher }
21129a0bf528SMauro Carvalho Chehab 
2113173a64cbSPatrick Boettcher static const u16 lut_prbs_2k[14] = {
2114173a64cbSPatrick Boettcher 	0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213
2115173a64cbSPatrick Boettcher };
2116173a64cbSPatrick Boettcher static const u16 lut_prbs_4k[14] = {
2117173a64cbSPatrick Boettcher 	0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E
2118173a64cbSPatrick Boettcher };
2119173a64cbSPatrick Boettcher static const u16 lut_prbs_8k[14] = {
2120173a64cbSPatrick Boettcher 	0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684
2121173a64cbSPatrick Boettcher };
2122173a64cbSPatrick Boettcher 
2123173a64cbSPatrick Boettcher static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
2124173a64cbSPatrick Boettcher {
2125173a64cbSPatrick Boettcher 	int sub_channel_prbs_group = 0;
2126173a64cbSPatrick Boettcher 
2127173a64cbSPatrick Boettcher 	sub_channel_prbs_group = (subchannel / 3) + 1;
2128173a64cbSPatrick Boettcher 	dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]);
2129173a64cbSPatrick Boettcher 
21309a0bf528SMauro Carvalho Chehab 	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
21319a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
2132173a64cbSPatrick Boettcher 			return lut_prbs_2k[sub_channel_prbs_group];
21339a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
2134173a64cbSPatrick Boettcher 			return lut_prbs_4k[sub_channel_prbs_group];
21359a0bf528SMauro Carvalho Chehab 	default:
2136173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2137173a64cbSPatrick Boettcher 			return lut_prbs_8k[sub_channel_prbs_group];
21389a0bf528SMauro Carvalho Chehab 	}
21399a0bf528SMauro Carvalho Chehab }
21409a0bf528SMauro Carvalho Chehab 
2141173a64cbSPatrick Boettcher static void dib8000_set_13seg_channel(struct dib8000_state *state)
2142173a64cbSPatrick Boettcher {
2143173a64cbSPatrick Boettcher 	u16 i;
2144173a64cbSPatrick Boettcher 	u16 coff_pow = 0x2800;
21459a0bf528SMauro Carvalho Chehab 
2146173a64cbSPatrick Boettcher 	state->seg_mask = 0x1fff; /* All 13 segments enabled */
21479a0bf528SMauro Carvalho Chehab 
2148173a64cbSPatrick Boettcher 	/* ---- COFF ---- Carloff, the most robust --- */
2149173a64cbSPatrick Boettcher 	if (state->isdbt_cfg_loaded == 0) {  /* if not Sound Broadcasting mode : put default values for 13 segments */
21509a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 180, (16 << 6) | 9);
21519a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
21529a0bf528SMauro Carvalho Chehab 		coff_pow = 0x2800;
21539a0bf528SMauro Carvalho Chehab 		for (i = 0; i < 6; i++)
21549a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 181+i, coff_pow);
21559a0bf528SMauro Carvalho Chehab 
2156173a64cbSPatrick Boettcher 		/* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */
2157173a64cbSPatrick 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 */
21589a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
21599a0bf528SMauro Carvalho Chehab 
2160173a64cbSPatrick Boettcher 		/* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */
21619a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
2162173a64cbSPatrick Boettcher 		/* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */
21639a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
21649a0bf528SMauro Carvalho Chehab 
2165173a64cbSPatrick Boettcher 		dib8000_write_word(state, 228, 0);  /* default value */
2166173a64cbSPatrick Boettcher 		dib8000_write_word(state, 265, 31); /* default value */
2167173a64cbSPatrick Boettcher 		dib8000_write_word(state, 205, 0x200f); /* init value */
2168173a64cbSPatrick Boettcher 	}
2169173a64cbSPatrick Boettcher 
2170173a64cbSPatrick Boettcher 	/*
2171173a64cbSPatrick Boettcher 	 * make the cpil_coff_lock more robust but slower p_coff_winlen
21729a0bf528SMauro Carvalho Chehab 	 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
21739a0bf528SMauro Carvalho Chehab 	 */
21749a0bf528SMauro Carvalho Chehab 
2175173a64cbSPatrick Boettcher 	if (state->cfg.pll->ifreq == 0)
2176173a64cbSPatrick Boettcher 		dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
21779a0bf528SMauro Carvalho Chehab 
2178173a64cbSPatrick Boettcher 	dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg);
2179173a64cbSPatrick Boettcher }
21809a0bf528SMauro Carvalho Chehab 
2181173a64cbSPatrick Boettcher static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs)
2182173a64cbSPatrick Boettcher {
2183173a64cbSPatrick Boettcher 	u16 reg_1;
21849a0bf528SMauro Carvalho Chehab 
2185173a64cbSPatrick Boettcher 	reg_1 = dib8000_read_word(state, 1);
2186173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */
2187173a64cbSPatrick Boettcher }
21889a0bf528SMauro Carvalho Chehab 
2189173a64cbSPatrick Boettcher static void dib8000_small_fine_tune(struct dib8000_state *state)
2190173a64cbSPatrick Boettcher {
2191173a64cbSPatrick Boettcher 	u16 i;
2192173a64cbSPatrick Boettcher 	const s16 *ncoeff;
2193c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
21949a0bf528SMauro Carvalho Chehab 
2195173a64cbSPatrick Boettcher 	dib8000_write_word(state, 352, state->seg_diff_mask);
2196173a64cbSPatrick Boettcher 	dib8000_write_word(state, 353, state->seg_mask);
21979a0bf528SMauro Carvalho Chehab 
2198173a64cbSPatrick 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 */
2199c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 351, (c->isdbt_sb_mode << 9) | (c->isdbt_sb_mode << 8) | (13 << 4) | 5);
2200173a64cbSPatrick Boettcher 
2201c82056d0SMauro Carvalho Chehab 	if (c->isdbt_sb_mode) {
2202173a64cbSPatrick Boettcher 		/* ---- SMALL ---- */
2203c82056d0SMauro Carvalho Chehab 		switch (c->transmission_mode) {
2204173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_2K:
2205c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2206c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2207173a64cbSPatrick Boettcher 						ncoeff = coeff_2k_sb_1seg_dqpsk;
2208173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2209173a64cbSPatrick Boettcher 						ncoeff = coeff_2k_sb_1seg;
2210173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2211c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2212c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2213173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
2214173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2215173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg_0dqpsk;
2216173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2217c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2218173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg_1dqpsk;
2219173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2220173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg;
2221173a64cbSPatrick Boettcher 					}
2222173a64cbSPatrick Boettcher 				}
22239a0bf528SMauro Carvalho Chehab 				break;
22249a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_4K:
2225c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2226c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2227173a64cbSPatrick Boettcher 						ncoeff = coeff_4k_sb_1seg_dqpsk;
2228173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2229173a64cbSPatrick Boettcher 						ncoeff = coeff_4k_sb_1seg;
2230173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2231c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2232c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2233173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
2234173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2235173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_0dqpsk;
2236173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2237c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2238173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_1dqpsk;
2239173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2240173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg;
2241173a64cbSPatrick Boettcher 					}
2242173a64cbSPatrick Boettcher 				}
22439a0bf528SMauro Carvalho Chehab 				break;
2244173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_AUTO:
2245173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_8K:
22469a0bf528SMauro Carvalho Chehab 		default:
2247c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2248c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2249173a64cbSPatrick Boettcher 						ncoeff = coeff_8k_sb_1seg_dqpsk;
2250173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2251173a64cbSPatrick Boettcher 						ncoeff = coeff_8k_sb_1seg;
2252173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2253c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2254c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2255173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
2256173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2257173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_0dqpsk;
2258173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2259c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2260173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_1dqpsk;
2261173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2262173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg;
2263173a64cbSPatrick Boettcher 					}
2264173a64cbSPatrick Boettcher 				}
22659a0bf528SMauro Carvalho Chehab 				break;
22669a0bf528SMauro Carvalho Chehab 		}
2267173a64cbSPatrick Boettcher 
2268173a64cbSPatrick Boettcher 		for (i = 0; i < 8; i++)
2269173a64cbSPatrick Boettcher 			dib8000_write_word(state, 343 + i, ncoeff[i]);
2270173a64cbSPatrick Boettcher 	}
2271173a64cbSPatrick Boettcher }
2272173a64cbSPatrick Boettcher 
2273173a64cbSPatrick Boettcher static const u16 coff_thres_1seg[3] = {300, 150, 80};
2274173a64cbSPatrick Boettcher static const u16 coff_thres_3seg[3] = {350, 300, 250};
2275173a64cbSPatrick Boettcher static void dib8000_set_sb_channel(struct dib8000_state *state)
2276173a64cbSPatrick Boettcher {
2277c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2278173a64cbSPatrick Boettcher 	const u16 *coff;
2279173a64cbSPatrick Boettcher 	u16 i;
2280173a64cbSPatrick Boettcher 
2281c82056d0SMauro Carvalho Chehab 	if (c->transmission_mode == TRANSMISSION_MODE_2K || c->transmission_mode == TRANSMISSION_MODE_4K) {
2282173a64cbSPatrick Boettcher 		dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */
2283173a64cbSPatrick Boettcher 		dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */
2284173a64cbSPatrick Boettcher 	} else {
2285173a64cbSPatrick Boettcher 		dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */
2286173a64cbSPatrick Boettcher 		dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */
2287173a64cbSPatrick Boettcher 	}
2288173a64cbSPatrick Boettcher 
2289c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 1) /* 3-segments */
2290173a64cbSPatrick Boettcher 		state->seg_mask = 0x00E0;
2291173a64cbSPatrick Boettcher 	else /* 1-segment */
2292173a64cbSPatrick Boettcher 		state->seg_mask = 0x0040;
2293173a64cbSPatrick Boettcher 
2294173a64cbSPatrick Boettcher 	dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2295173a64cbSPatrick Boettcher 
2296173a64cbSPatrick Boettcher 	/* ---- COFF ---- Carloff, the most robust --- */
2297173a64cbSPatrick 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 */
2298c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 187, (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~c->isdbt_partial_reception & 1) << 2) | 0x3);
2299173a64cbSPatrick Boettcher 
2300173a64cbSPatrick Boettcher 	dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */
2301173a64cbSPatrick 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 */
2302173a64cbSPatrick Boettcher 
2303173a64cbSPatrick Boettcher 	/* Sound Broadcasting mode 1 seg */
2304c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 0) {
2305173a64cbSPatrick 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) */
2306173a64cbSPatrick Boettcher 		if (state->mode == 3)
2307173a64cbSPatrick Boettcher 			dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14));
23089a0bf528SMauro Carvalho Chehab 		else
2309173a64cbSPatrick Boettcher 			dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14));
2310173a64cbSPatrick Boettcher 
2311173a64cbSPatrick 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 */
2312173a64cbSPatrick Boettcher 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
2313173a64cbSPatrick Boettcher 		coff = &coff_thres_1seg[0];
2314173a64cbSPatrick Boettcher 	} else {   /* Sound Broadcasting mode 3 seg */
2315173a64cbSPatrick Boettcher 		dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
2316173a64cbSPatrick 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 */
2317173a64cbSPatrick Boettcher 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
2318173a64cbSPatrick Boettcher 		coff = &coff_thres_3seg[0];
2319173a64cbSPatrick Boettcher 	}
2320173a64cbSPatrick Boettcher 
2321173a64cbSPatrick Boettcher 	dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */
2322173a64cbSPatrick Boettcher 	dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */
2323173a64cbSPatrick Boettcher 
2324c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 0 && c->transmission_mode == TRANSMISSION_MODE_2K)
2325173a64cbSPatrick Boettcher 		dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */
2326173a64cbSPatrick Boettcher 
2327173a64cbSPatrick Boettcher 	/* Write COFF thres */
2328173a64cbSPatrick Boettcher 	for (i = 0 ; i < 3; i++) {
2329173a64cbSPatrick Boettcher 		dib8000_write_word(state, 181+i, coff[i]);
2330173a64cbSPatrick Boettcher 		dib8000_write_word(state, 184+i, coff[i]);
2331173a64cbSPatrick Boettcher 	}
2332173a64cbSPatrick Boettcher 
2333173a64cbSPatrick Boettcher 	/*
2334173a64cbSPatrick Boettcher 	 * make the cpil_coff_lock more robust but slower p_coff_winlen
2335173a64cbSPatrick Boettcher 	 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2336173a64cbSPatrick Boettcher 	 */
2337173a64cbSPatrick Boettcher 
2338173a64cbSPatrick Boettcher 	dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */
2339173a64cbSPatrick Boettcher 
2340c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 0)
2341173a64cbSPatrick Boettcher 		dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */
2342173a64cbSPatrick Boettcher 	else
2343173a64cbSPatrick Boettcher 		dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2344173a64cbSPatrick Boettcher }
2345173a64cbSPatrick Boettcher 
2346173a64cbSPatrick Boettcher static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
2347173a64cbSPatrick Boettcher {
2348173a64cbSPatrick Boettcher 	u16 p_cfr_left_edge  = 0, p_cfr_right_edge = 0;
2349173a64cbSPatrick Boettcher 	u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ;
2350173a64cbSPatrick Boettcher 	u16 max_constellation = DQPSK;
2351173a64cbSPatrick Boettcher 	int init_prbs;
2352c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2353173a64cbSPatrick Boettcher 
2354173a64cbSPatrick Boettcher 	/* P_mode */
2355173a64cbSPatrick Boettcher 	dib8000_write_word(state, 10, (seq << 4));
2356173a64cbSPatrick Boettcher 
2357173a64cbSPatrick Boettcher 	/* init mode */
2358173a64cbSPatrick Boettcher 	state->mode = fft_to_mode(state);
2359173a64cbSPatrick Boettcher 
2360173a64cbSPatrick Boettcher 	/* set guard */
2361173a64cbSPatrick Boettcher 	tmp = dib8000_read_word(state, 1);
2362c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3));
2363173a64cbSPatrick Boettcher 
2364c82056d0SMauro 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));
2365173a64cbSPatrick Boettcher 
2366173a64cbSPatrick Boettcher 	/* signal optimization parameter */
2367c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception) {
2368c82056d0SMauro Carvalho Chehab 		state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0];
2369173a64cbSPatrick Boettcher 		for (i = 1; i < 3; i++)
2370c82056d0SMauro Carvalho Chehab 			nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
2371173a64cbSPatrick Boettcher 		for (i = 0; i < nbseg_diff; i++)
2372173a64cbSPatrick Boettcher 			state->seg_diff_mask |= 1 << permu_seg[i+1];
2373173a64cbSPatrick Boettcher 	} else {
2374173a64cbSPatrick Boettcher 		for (i = 0; i < 3; i++)
2375c82056d0SMauro Carvalho Chehab 			nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
2376173a64cbSPatrick Boettcher 		for (i = 0; i < nbseg_diff; i++)
2377173a64cbSPatrick Boettcher 			state->seg_diff_mask |= 1 << permu_seg[i];
2378173a64cbSPatrick Boettcher 	}
2379173a64cbSPatrick Boettcher 
2380173a64cbSPatrick Boettcher 	if (state->seg_diff_mask)
2381173a64cbSPatrick Boettcher 		dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2382173a64cbSPatrick Boettcher 	else
2383173a64cbSPatrick Boettcher 		dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */
2384173a64cbSPatrick Boettcher 
2385173a64cbSPatrick Boettcher 	for (i = 0; i < 3; i++)
2386173a64cbSPatrick Boettcher 		max_constellation = dib8000_set_layer(state, i, max_constellation);
2387173a64cbSPatrick Boettcher 	if (autosearching == 0) {
2388c82056d0SMauro Carvalho Chehab 		state->layer_b_nb_seg = c->layer[1].segment_count;
2389c82056d0SMauro Carvalho Chehab 		state->layer_c_nb_seg = c->layer[2].segment_count;
2390173a64cbSPatrick Boettcher 	}
2391173a64cbSPatrick Boettcher 
2392173a64cbSPatrick Boettcher 	/* WRITE: Mode & Diff mask */
2393173a64cbSPatrick Boettcher 	dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask);
2394173a64cbSPatrick Boettcher 
2395173a64cbSPatrick Boettcher 	state->differential_constellation = (state->seg_diff_mask != 0);
23969a0bf528SMauro Carvalho Chehab 
23979a0bf528SMauro Carvalho Chehab 	/* channel estimation fine configuration */
2398173a64cbSPatrick Boettcher 	ana_gain = dib8000_adp_fine_tune(state, max_constellation);
23999a0bf528SMauro Carvalho Chehab 
2400173a64cbSPatrick Boettcher 	/* update ana_gain depending on max constellation */
2401173a64cbSPatrick Boettcher 	dib8000_update_ana_gain(state, ana_gain);
24029a0bf528SMauro Carvalho Chehab 
2403173a64cbSPatrick Boettcher 	/* ---- ANA_FE ---- */
2404c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception) /* 3-segments */
2405173a64cbSPatrick Boettcher 		dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg);
2406173a64cbSPatrick Boettcher 	else
2407173a64cbSPatrick Boettcher 		dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */
2408173a64cbSPatrick Boettcher 
2409173a64cbSPatrick Boettcher 	/* TSB or ISDBT ? apply it now */
2410c82056d0SMauro Carvalho Chehab 	if (c->isdbt_sb_mode) {
2411173a64cbSPatrick Boettcher 		dib8000_set_sb_channel(state);
2412746f7ae0SMauro Carvalho Chehab 		if (c->isdbt_sb_subchannel < 14)
2413c82056d0SMauro Carvalho Chehab 			init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel);
2414173a64cbSPatrick Boettcher 		else
2415173a64cbSPatrick Boettcher 			init_prbs = 0;
2416173a64cbSPatrick Boettcher 	} else {
2417173a64cbSPatrick Boettcher 		dib8000_set_13seg_channel(state);
2418173a64cbSPatrick Boettcher 		init_prbs = 0xfff;
2419173a64cbSPatrick Boettcher 	}
24209a0bf528SMauro Carvalho Chehab 
2421173a64cbSPatrick Boettcher 	/* SMALL */
2422173a64cbSPatrick Boettcher 	dib8000_small_fine_tune(state);
24239a0bf528SMauro Carvalho Chehab 
2424173a64cbSPatrick Boettcher 	dib8000_set_subchannel_prbs(state, init_prbs);
2425173a64cbSPatrick Boettcher 
2426173a64cbSPatrick Boettcher 	/* ---- CHAN_BLK ---- */
24279a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 13; i++) {
2428173a64cbSPatrick Boettcher 		if ((((~state->seg_diff_mask) >> i) & 1) == 1) {
2429173a64cbSPatrick Boettcher 			p_cfr_left_edge  += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0));
2430173a64cbSPatrick Boettcher 			p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0));
24319a0bf528SMauro Carvalho Chehab 		}
24329a0bf528SMauro Carvalho Chehab 	}
2433173a64cbSPatrick Boettcher 	dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */
2434173a64cbSPatrick Boettcher 	dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */
2435173a64cbSPatrick Boettcher 	/* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */
24369a0bf528SMauro Carvalho Chehab 
2437173a64cbSPatrick Boettcher 	dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */
2438173a64cbSPatrick Boettcher 	dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */
2439173a64cbSPatrick Boettcher 	dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */
2440173a64cbSPatrick Boettcher 
2441173a64cbSPatrick Boettcher 	if (!autosearching)
2442173a64cbSPatrick Boettcher 		dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
2443173a64cbSPatrick Boettcher 	else
2444173a64cbSPatrick Boettcher 		dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */
2445173a64cbSPatrick Boettcher 
2446173a64cbSPatrick Boettcher 	dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */
2447173a64cbSPatrick Boettcher 	dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */
2448173a64cbSPatrick Boettcher 
2449173a64cbSPatrick Boettcher 	dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2450173a64cbSPatrick Boettcher 
2451173a64cbSPatrick Boettcher 	/* ---- TMCC ---- */
24529a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 3; i++)
2453c82056d0SMauro Carvalho Chehab 		tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ;
2454173a64cbSPatrick Boettcher 
2455173a64cbSPatrick Boettcher 	/* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */
2456173a64cbSPatrick Boettcher 	/* Threshold is set at 1/4 of max power. */
24579a0bf528SMauro Carvalho Chehab 	tmcc_pow *= (1 << (9-2));
2458173a64cbSPatrick Boettcher 	dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */
2459173a64cbSPatrick Boettcher 	dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */
2460173a64cbSPatrick Boettcher 	dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */
2461173a64cbSPatrick Boettcher 	/*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */
24629a0bf528SMauro Carvalho Chehab 
2463173a64cbSPatrick Boettcher 	/* ---- PHA3 ---- */
24649a0bf528SMauro Carvalho Chehab 	if (state->isdbt_cfg_loaded == 0)
24659a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */
24669a0bf528SMauro Carvalho Chehab 
24679a0bf528SMauro Carvalho Chehab 	state->isdbt_cfg_loaded = 0;
2468173a64cbSPatrick Boettcher }
24699a0bf528SMauro Carvalho Chehab 
24706f7ee06fSMauro Carvalho Chehab static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal,
24716f7ee06fSMauro Carvalho Chehab 			     u32 wait0_ms, u32 wait1_ms, u32 wait2_ms)
2472173a64cbSPatrick Boettcher {
247313122f98SMauro Carvalho Chehab 	u32 value = 0;	/* P_search_end0 wait time */
2474173a64cbSPatrick Boettcher 	u16 reg = 11;	/* P_search_end0 start addr */
2475173a64cbSPatrick Boettcher 
2476173a64cbSPatrick Boettcher 	for (reg = 11; reg < 16; reg += 2) {
2477173a64cbSPatrick Boettcher 		if (reg == 11) {
2478173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
247913122f98SMauro Carvalho Chehab 				value = internal * wait1_ms;
2480173a64cbSPatrick Boettcher 			else
248113122f98SMauro Carvalho Chehab 				value = internal * wait0_ms;
2482173a64cbSPatrick Boettcher 		} else if (reg == 13)
248313122f98SMauro Carvalho Chehab 			value = internal * wait1_ms;
2484173a64cbSPatrick Boettcher 		else if (reg == 15)
248513122f98SMauro Carvalho Chehab 			value = internal * wait2_ms;
2486173a64cbSPatrick Boettcher 		dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff));
2487173a64cbSPatrick Boettcher 		dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff));
2488173a64cbSPatrick Boettcher 	}
2489173a64cbSPatrick Boettcher 	return value;
24909a0bf528SMauro Carvalho Chehab }
24919a0bf528SMauro Carvalho Chehab 
24929a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_start(struct dvb_frontend *fe)
24939a0bf528SMauro Carvalho Chehab {
24949a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
2495c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2496173a64cbSPatrick Boettcher 	u8 slist = 0;
2497173a64cbSPatrick Boettcher 	u32 value, internal = state->cfg.pll->internal;
24989a0bf528SMauro Carvalho Chehab 
2499173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
2500173a64cbSPatrick Boettcher 		internal = dib8000_read32(state, 23) / 1000;
25019a0bf528SMauro Carvalho Chehab 
2502d67350f8SOlivier Grenie 	if ((state->revision >= 0x8002) &&
2503d67350f8SOlivier Grenie 	    (state->autosearch_state == AS_SEARCHING_FFT)) {
2504173a64cbSPatrick Boettcher 		dib8000_write_word(state,  37, 0x0065); /* P_ctrl_pha_off_max default values */
2505173a64cbSPatrick Boettcher 		dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
2506173a64cbSPatrick Boettcher 
2507173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */
2508173a64cbSPatrick Boettcher 		dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */
2509173a64cbSPatrick Boettcher 		dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */
2510173a64cbSPatrick Boettcher 		dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */
2511173a64cbSPatrick Boettcher 		dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */
2512173a64cbSPatrick Boettcher 		dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */
2513173a64cbSPatrick Boettcher 
2514173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2515173a64cbSPatrick Boettcher 			value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2516173a64cbSPatrick Boettcher 		else
2517173a64cbSPatrick Boettcher 			value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2518173a64cbSPatrick Boettcher 
2519173a64cbSPatrick Boettcher 		dib8000_write_word(state, 17, 0);
2520173a64cbSPatrick Boettcher 		dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */
2521173a64cbSPatrick Boettcher 		dib8000_write_word(state, 19, 0);
2522173a64cbSPatrick Boettcher 		dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */
2523173a64cbSPatrick Boettcher 		dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */
2524173a64cbSPatrick Boettcher 		dib8000_write_word(state, 22, value & 0xffff);
2525173a64cbSPatrick Boettcher 
2526173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2527173a64cbSPatrick Boettcher 			dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */
2528173a64cbSPatrick Boettcher 		else
2529173a64cbSPatrick Boettcher 			dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */
2530173a64cbSPatrick Boettcher 		dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */
2531173a64cbSPatrick Boettcher 
2532173a64cbSPatrick Boettcher 		/* P_search_param_select = (1 | 1<<4 | 1 << 8) */
2533173a64cbSPatrick Boettcher 		dib8000_write_word(state, 356, 0);
2534173a64cbSPatrick Boettcher 		dib8000_write_word(state, 357, 0x111);
2535173a64cbSPatrick Boettcher 
2536173a64cbSPatrick Boettcher 		dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
2537173a64cbSPatrick Boettcher 		dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
2538173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */
2539d67350f8SOlivier Grenie 	} else if ((state->revision >= 0x8002) &&
2540d67350f8SOlivier Grenie 		   (state->autosearch_state == AS_SEARCHING_GUARD)) {
2541c82056d0SMauro Carvalho Chehab 		c->transmission_mode = TRANSMISSION_MODE_8K;
2542c82056d0SMauro Carvalho Chehab 		c->guard_interval = GUARD_INTERVAL_1_8;
2543c82056d0SMauro Carvalho Chehab 		c->inversion = 0;
2544c82056d0SMauro Carvalho Chehab 		c->layer[0].modulation = QAM_64;
2545c82056d0SMauro Carvalho Chehab 		c->layer[0].fec = FEC_2_3;
2546c82056d0SMauro Carvalho Chehab 		c->layer[0].interleaving = 0;
2547c82056d0SMauro Carvalho Chehab 		c->layer[0].segment_count = 13;
25489a0bf528SMauro Carvalho Chehab 
2549173a64cbSPatrick Boettcher 		slist = 16;
2550c82056d0SMauro Carvalho Chehab 		c->transmission_mode = state->found_nfft;
2551173a64cbSPatrick Boettcher 
2552173a64cbSPatrick Boettcher 		dib8000_set_isdbt_common_channel(state, slist, 1);
2553173a64cbSPatrick Boettcher 
2554173a64cbSPatrick Boettcher 		/* set lock_mask values */
2555173a64cbSPatrick Boettcher 		dib8000_write_word(state, 6, 0x4);
2556173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2557173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */
2558173a64cbSPatrick Boettcher 		else
2559173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, 0x8);
2560173a64cbSPatrick Boettcher 		dib8000_write_word(state, 8, 0x1000);
2561173a64cbSPatrick Boettcher 
2562173a64cbSPatrick Boettcher 		/* set lock_mask wait time values */
2563173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2564173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2565173a64cbSPatrick Boettcher 		else
2566173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2567173a64cbSPatrick Boettcher 
2568173a64cbSPatrick Boettcher 		dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */
2569173a64cbSPatrick Boettcher 
2570173a64cbSPatrick Boettcher 		/* P_search_param_select = 0xf; look for the 4 different guard intervals */
2571173a64cbSPatrick Boettcher 		dib8000_write_word(state, 356, 0);
2572173a64cbSPatrick Boettcher 		dib8000_write_word(state, 357, 0xf);
2573173a64cbSPatrick Boettcher 
2574173a64cbSPatrick Boettcher 		value = dib8000_read_word(state, 0);
2575173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2576173a64cbSPatrick Boettcher 		dib8000_read_word(state, 1284);  /* reset the INT. n_irq_pending */
2577173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (u16)value);
2578173a64cbSPatrick Boettcher 	} else {
2579c82056d0SMauro Carvalho Chehab 		c->inversion = 0;
2580c82056d0SMauro Carvalho Chehab 		c->layer[0].modulation = QAM_64;
2581c82056d0SMauro Carvalho Chehab 		c->layer[0].fec = FEC_2_3;
2582c82056d0SMauro Carvalho Chehab 		c->layer[0].interleaving = 0;
2583c82056d0SMauro Carvalho Chehab 		c->layer[0].segment_count = 13;
2584c82056d0SMauro Carvalho Chehab 		if (!c->isdbt_sb_mode)
2585c82056d0SMauro Carvalho Chehab 			c->layer[0].segment_count = 13;
2586173a64cbSPatrick Boettcher 
2587173a64cbSPatrick Boettcher 		/* choose the right list, in sb, always do everything */
2588c82056d0SMauro Carvalho Chehab 		if (c->isdbt_sb_mode) {
25899a0bf528SMauro Carvalho Chehab 			slist = 7;
25909a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
25919a0bf528SMauro Carvalho Chehab 		} else {
2592c82056d0SMauro Carvalho Chehab 			if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2593c82056d0SMauro Carvalho Chehab 				if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2594c82056d0SMauro Carvalho Chehab 					c->transmission_mode = TRANSMISSION_MODE_8K;
2595c82056d0SMauro Carvalho Chehab 					c->guard_interval = GUARD_INTERVAL_1_8;
25969a0bf528SMauro Carvalho Chehab 					slist = 7;
2597173a64cbSPatrick Boettcher 					dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));  /* P_mode = 1 to have autosearch start ok with mode2 */
2598173a64cbSPatrick Boettcher 				} else {
2599c82056d0SMauro Carvalho Chehab 					c->guard_interval = GUARD_INTERVAL_1_8;
26009a0bf528SMauro Carvalho Chehab 					slist = 3;
2601173a64cbSPatrick Boettcher 				}
26029a0bf528SMauro Carvalho Chehab 			} else {
2603c82056d0SMauro Carvalho Chehab 				if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2604c82056d0SMauro Carvalho Chehab 					c->transmission_mode = TRANSMISSION_MODE_8K;
26059a0bf528SMauro Carvalho Chehab 					slist = 2;
2606173a64cbSPatrick Boettcher 					dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));  /* P_mode = 1 */
26079a0bf528SMauro Carvalho Chehab 				} else
26089a0bf528SMauro Carvalho Chehab 					slist = 0;
26099a0bf528SMauro Carvalho Chehab 			}
2610173a64cbSPatrick Boettcher 		}
2611173a64cbSPatrick Boettcher 		dprintk("Using list for autosearch : %d", slist);
26129a0bf528SMauro Carvalho Chehab 
2613173a64cbSPatrick Boettcher 		dib8000_set_isdbt_common_channel(state, slist, 1);
26149a0bf528SMauro Carvalho Chehab 
2615173a64cbSPatrick Boettcher 		/* set lock_mask values */
26169a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 6, 0x4);
2617173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2618173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10));
2619173a64cbSPatrick Boettcher 		else
26209a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 7, 0x8);
26219a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 8, 0x1000);
26229a0bf528SMauro Carvalho Chehab 
2623173a64cbSPatrick Boettcher 		/* set lock_mask wait time values */
2624173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2625173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2626173a64cbSPatrick Boettcher 		else
2627173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
26289a0bf528SMauro Carvalho Chehab 
26299a0bf528SMauro Carvalho Chehab 		value = dib8000_read_word(state, 0);
26309a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2631173a64cbSPatrick Boettcher 		dib8000_read_word(state, 1284);  /* reset the INT. n_irq_pending */
26329a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 0, (u16)value);
26339a0bf528SMauro Carvalho Chehab 	}
26349a0bf528SMauro Carvalho Chehab 	return 0;
26359a0bf528SMauro Carvalho Chehab }
26369a0bf528SMauro Carvalho Chehab 
26379a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_irq(struct dvb_frontend *fe)
26389a0bf528SMauro Carvalho Chehab {
26399a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
26409a0bf528SMauro Carvalho Chehab 	u16 irq_pending = dib8000_read_word(state, 1284);
26419a0bf528SMauro Carvalho Chehab 
2642d67350f8SOlivier Grenie 	if ((state->revision >= 0x8002) &&
2643d67350f8SOlivier Grenie 	    (state->autosearch_state == AS_SEARCHING_FFT)) {
2644173a64cbSPatrick Boettcher 		if (irq_pending & 0x1) {
2645173a64cbSPatrick Boettcher 			dprintk("dib8000_autosearch_irq: max correlation result available");
2646173a64cbSPatrick Boettcher 			return 3;
2647173a64cbSPatrick Boettcher 		}
2648173a64cbSPatrick Boettcher 	} else {
2649173a64cbSPatrick Boettcher 		if (irq_pending & 0x1) {	/* failed */
26509a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_autosearch_irq failed");
26519a0bf528SMauro Carvalho Chehab 			return 1;
26529a0bf528SMauro Carvalho Chehab 		}
26539a0bf528SMauro Carvalho Chehab 
2654173a64cbSPatrick Boettcher 		if (irq_pending & 0x2) {	/* succeeded */
26559a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_autosearch_irq succeeded");
26569a0bf528SMauro Carvalho Chehab 			return 2;
26579a0bf528SMauro Carvalho Chehab 		}
2658173a64cbSPatrick Boettcher 	}
26599a0bf528SMauro Carvalho Chehab 
26609a0bf528SMauro Carvalho Chehab 	return 0;		// still pending
26619a0bf528SMauro Carvalho Chehab }
26629a0bf528SMauro Carvalho Chehab 
2663173a64cbSPatrick Boettcher static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
2664173a64cbSPatrick Boettcher {
2665173a64cbSPatrick Boettcher 	u16 tmp;
2666173a64cbSPatrick Boettcher 
2667173a64cbSPatrick Boettcher 	tmp = dib8000_read_word(state, 771);
2668173a64cbSPatrick Boettcher 	if (onoff) /* start P_restart_chd : channel_decoder */
2669173a64cbSPatrick Boettcher 		dib8000_write_word(state, 771, tmp & 0xfffd);
2670173a64cbSPatrick Boettcher 	else /* stop P_restart_chd : channel_decoder */
2671173a64cbSPatrick Boettcher 		dib8000_write_word(state, 771, tmp | (1<<1));
2672173a64cbSPatrick Boettcher }
2673173a64cbSPatrick Boettcher 
2674173a64cbSPatrick Boettcher static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
2675173a64cbSPatrick Boettcher {
2676173a64cbSPatrick Boettcher 	s16 unit_khz_dds_val;
2677173a64cbSPatrick Boettcher 	u32 abs_offset_khz = ABS(offset_khz);
2678173a64cbSPatrick Boettcher 	u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
2679173a64cbSPatrick Boettcher 	u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
2680173a64cbSPatrick Boettcher 	u8 ratio;
2681173a64cbSPatrick Boettcher 
2682173a64cbSPatrick Boettcher 	if (state->revision == 0x8090) {
2683173a64cbSPatrick Boettcher 		ratio = 4;
2684173a64cbSPatrick Boettcher 		unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000);
2685173a64cbSPatrick Boettcher 		if (offset_khz < 0)
2686173a64cbSPatrick Boettcher 			dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
2687173a64cbSPatrick Boettcher 		else
2688173a64cbSPatrick Boettcher 			dds = (abs_offset_khz * unit_khz_dds_val);
2689173a64cbSPatrick Boettcher 
2690173a64cbSPatrick Boettcher 		if (invert)
2691173a64cbSPatrick Boettcher 			dds = (1<<26) - dds;
2692173a64cbSPatrick Boettcher 	} else {
2693173a64cbSPatrick Boettcher 		ratio = 2;
2694173a64cbSPatrick Boettcher 		unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
2695173a64cbSPatrick Boettcher 
2696173a64cbSPatrick Boettcher 		if (offset_khz < 0)
2697173a64cbSPatrick Boettcher 			unit_khz_dds_val *= -1;
2698173a64cbSPatrick Boettcher 
2699173a64cbSPatrick Boettcher 		/* IF tuner */
2700173a64cbSPatrick Boettcher 		if (invert)
2701173a64cbSPatrick Boettcher 			dds -= abs_offset_khz * unit_khz_dds_val;
2702173a64cbSPatrick Boettcher 		else
2703173a64cbSPatrick Boettcher 			dds += abs_offset_khz * unit_khz_dds_val;
2704173a64cbSPatrick Boettcher 	}
2705173a64cbSPatrick Boettcher 
2706173a64cbSPatrick Boettcher 	dprintk("setting a DDS frequency offset of %c%dkHz", invert ? '-' : ' ', dds / unit_khz_dds_val);
2707173a64cbSPatrick Boettcher 
2708173a64cbSPatrick Boettcher 	if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) {
2709173a64cbSPatrick Boettcher 		/* Max dds offset is the half of the demod freq */
2710173a64cbSPatrick Boettcher 		dib8000_write_word(state, 26, invert);
2711173a64cbSPatrick Boettcher 		dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff);
2712173a64cbSPatrick Boettcher 		dib8000_write_word(state, 28, (u16)(dds & 0xffff));
2713173a64cbSPatrick Boettcher 	}
2714173a64cbSPatrick Boettcher }
2715173a64cbSPatrick Boettcher 
2716173a64cbSPatrick Boettcher static void dib8000_set_frequency_offset(struct dib8000_state *state)
2717173a64cbSPatrick Boettcher {
2718c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2719173a64cbSPatrick Boettcher 	int i;
2720173a64cbSPatrick Boettcher 	u32 current_rf;
2721173a64cbSPatrick Boettcher 	int total_dds_offset_khz;
2722173a64cbSPatrick Boettcher 
2723173a64cbSPatrick Boettcher 	if (state->fe[0]->ops.tuner_ops.get_frequency)
2724173a64cbSPatrick Boettcher 		state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], &current_rf);
2725173a64cbSPatrick Boettcher 	else
2726c82056d0SMauro Carvalho Chehab 		current_rf = c->frequency;
2727173a64cbSPatrick Boettcher 	current_rf /= 1000;
2728c82056d0SMauro Carvalho Chehab 	total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000;
2729173a64cbSPatrick Boettcher 
2730c82056d0SMauro Carvalho Chehab 	if (c->isdbt_sb_mode) {
2731c82056d0SMauro Carvalho Chehab 		state->subchannel = c->isdbt_sb_subchannel;
2732173a64cbSPatrick Boettcher 
2733173a64cbSPatrick Boettcher 		i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */
2734c82056d0SMauro Carvalho Chehab 		dib8000_write_word(state, 26, c->inversion ^ i);
2735173a64cbSPatrick Boettcher 
2736173a64cbSPatrick Boettcher 		if (state->cfg.pll->ifreq == 0) { /* low if tuner */
2737c82056d0SMauro Carvalho Chehab 			if ((c->inversion ^ i) == 0)
2738173a64cbSPatrick Boettcher 				dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
2739173a64cbSPatrick Boettcher 		} else {
2740c82056d0SMauro Carvalho Chehab 			if ((c->inversion ^ i) == 0)
2741173a64cbSPatrick Boettcher 				total_dds_offset_khz *= -1;
2742173a64cbSPatrick Boettcher 		}
2743173a64cbSPatrick Boettcher 	}
2744173a64cbSPatrick Boettcher 
2745c82056d0SMauro 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);
2746173a64cbSPatrick Boettcher 
2747173a64cbSPatrick Boettcher 	/* apply dds offset now */
2748173a64cbSPatrick Boettcher 	dib8000_set_dds(state, total_dds_offset_khz);
2749173a64cbSPatrick Boettcher }
2750173a64cbSPatrick Boettcher 
2751173a64cbSPatrick Boettcher static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 };
27526f7ee06fSMauro Carvalho Chehab 
27536f7ee06fSMauro Carvalho Chehab static u32 dib8000_get_symbol_duration(struct dib8000_state *state)
2754173a64cbSPatrick Boettcher {
2755c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2756173a64cbSPatrick Boettcher 	u16 i;
2757173a64cbSPatrick Boettcher 
2758c82056d0SMauro Carvalho Chehab 	switch (c->transmission_mode) {
2759173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_2K:
2760173a64cbSPatrick Boettcher 			i = 0;
2761173a64cbSPatrick Boettcher 			break;
2762173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_4K:
2763173a64cbSPatrick Boettcher 			i = 2;
2764173a64cbSPatrick Boettcher 			break;
2765173a64cbSPatrick Boettcher 	default:
2766173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_AUTO:
2767173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2768173a64cbSPatrick Boettcher 			i = 1;
2769173a64cbSPatrick Boettcher 			break;
2770173a64cbSPatrick Boettcher 	}
2771173a64cbSPatrick Boettcher 
2772c82056d0SMauro Carvalho Chehab 	return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1;
2773173a64cbSPatrick Boettcher }
2774173a64cbSPatrick Boettcher 
2775173a64cbSPatrick Boettcher static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step)
2776173a64cbSPatrick Boettcher {
2777c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2778173a64cbSPatrick Boettcher 	u16 reg_32 = 0, reg_37 = 0;
2779173a64cbSPatrick Boettcher 
2780173a64cbSPatrick Boettcher 	switch (loop_step) {
2781173a64cbSPatrick Boettcher 	case LOOP_TUNE_1:
2782c82056d0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode)  {
2783c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) {
2784173a64cbSPatrick Boettcher 					reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */
2785173a64cbSPatrick 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)  */
2786173a64cbSPatrick Boettcher 				} else { /* Sound Broadcasting mode 3 seg */
2787173a64cbSPatrick Boettcher 					reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */
2788173a64cbSPatrick 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)  */
2789173a64cbSPatrick Boettcher 				}
2790173a64cbSPatrick Boettcher 			} else { /* 13-seg start conf offset loop parameters */
2791173a64cbSPatrick Boettcher 				reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
2792173a64cbSPatrick 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  */
2793173a64cbSPatrick Boettcher 			}
2794173a64cbSPatrick Boettcher 			break;
2795173a64cbSPatrick Boettcher 	case LOOP_TUNE_2:
2796c82056d0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode)  {
2797c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) {  /* Sound Broadcasting mode 1 seg */
2798173a64cbSPatrick Boettcher 					reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/
2799173a64cbSPatrick Boettcher 					reg_37 = (12-state->mode) | ((5 + state->mode) << 5);
2800173a64cbSPatrick Boettcher 				} else {  /* Sound Broadcasting mode 3 seg */
2801173a64cbSPatrick Boettcher 					reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */
2802173a64cbSPatrick Boettcher 					reg_37 = (11-state->mode) | ((5 + state->mode) << 5);
2803173a64cbSPatrick Boettcher 				}
2804173a64cbSPatrick Boettcher 			} else {  /* 13 seg */
2805173a64cbSPatrick Boettcher 				reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */
2806173a64cbSPatrick Boettcher 				reg_37 = ((5+state->mode) << 5) | (10 - state->mode);
2807173a64cbSPatrick Boettcher 			}
2808173a64cbSPatrick Boettcher 			break;
2809173a64cbSPatrick Boettcher 	}
2810173a64cbSPatrick Boettcher 	dib8000_write_word(state, 32, reg_32);
2811173a64cbSPatrick Boettcher 	dib8000_write_word(state, 37, reg_37);
2812173a64cbSPatrick Boettcher }
2813173a64cbSPatrick Boettcher 
2814173a64cbSPatrick Boettcher static void dib8000_demod_restart(struct dib8000_state *state)
2815173a64cbSPatrick Boettcher {
2816173a64cbSPatrick Boettcher 	dib8000_write_word(state, 770, 0x4000);
2817173a64cbSPatrick Boettcher 	dib8000_write_word(state, 770, 0x0000);
2818173a64cbSPatrick Boettcher 	return;
2819173a64cbSPatrick Boettcher }
2820173a64cbSPatrick Boettcher 
2821173a64cbSPatrick Boettcher static void dib8000_set_sync_wait(struct dib8000_state *state)
2822173a64cbSPatrick Boettcher {
2823c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2824173a64cbSPatrick Boettcher 	u16 sync_wait = 64;
2825173a64cbSPatrick Boettcher 
2826173a64cbSPatrick Boettcher 	/* P_dvsy_sync_wait - reuse mode */
2827c82056d0SMauro Carvalho Chehab 	switch (c->transmission_mode) {
2828173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2829173a64cbSPatrick Boettcher 			sync_wait = 256;
2830173a64cbSPatrick Boettcher 			break;
2831173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_4K:
2832173a64cbSPatrick Boettcher 			sync_wait = 128;
2833173a64cbSPatrick Boettcher 			break;
2834173a64cbSPatrick Boettcher 	default:
2835173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_2K:
2836173a64cbSPatrick Boettcher 			sync_wait =  64;
2837173a64cbSPatrick Boettcher 			break;
2838173a64cbSPatrick Boettcher 	}
2839173a64cbSPatrick Boettcher 
2840173a64cbSPatrick Boettcher 	if (state->cfg.diversity_delay == 0)
2841c82056d0SMauro Carvalho Chehab 		sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */
2842173a64cbSPatrick Boettcher 	else
2843c82056d0SMauro Carvalho Chehab 		sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */
2844173a64cbSPatrick Boettcher 
2845173a64cbSPatrick Boettcher 	dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
2846173a64cbSPatrick Boettcher }
2847173a64cbSPatrick Boettcher 
2848173a64cbSPatrick Boettcher static u32 dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
2849173a64cbSPatrick Boettcher {
2850173a64cbSPatrick Boettcher 	if (mode == SYMBOL_DEPENDENT_ON)
2851173a64cbSPatrick Boettcher 		return systime() + (delay * state->symbol_duration);
2852173a64cbSPatrick Boettcher 	else
2853173a64cbSPatrick Boettcher 		return systime() + delay;
2854173a64cbSPatrick Boettcher }
2855173a64cbSPatrick Boettcher 
2856173a64cbSPatrick Boettcher static s32 dib8000_get_status(struct dvb_frontend *fe)
2857173a64cbSPatrick Boettcher {
2858173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2859173a64cbSPatrick Boettcher 	return state->status;
2860173a64cbSPatrick Boettcher }
2861173a64cbSPatrick Boettcher 
2862d44913c1SMauro Carvalho Chehab static enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
2863173a64cbSPatrick Boettcher {
2864173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2865173a64cbSPatrick Boettcher 	return state->tune_state;
2866173a64cbSPatrick Boettcher }
2867173a64cbSPatrick Boettcher 
2868d44913c1SMauro Carvalho Chehab static int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2869173a64cbSPatrick Boettcher {
2870173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2871173a64cbSPatrick Boettcher 
2872173a64cbSPatrick Boettcher 	state->tune_state = tune_state;
2873173a64cbSPatrick Boettcher 	return 0;
2874173a64cbSPatrick Boettcher }
2875173a64cbSPatrick Boettcher 
2876173a64cbSPatrick Boettcher static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
2877173a64cbSPatrick Boettcher {
2878173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2879173a64cbSPatrick Boettcher 
2880173a64cbSPatrick Boettcher 	state->status = FE_STATUS_TUNE_PENDING;
2881173a64cbSPatrick Boettcher 	state->tune_state = CT_DEMOD_START;
2882173a64cbSPatrick Boettcher 	return 0;
2883173a64cbSPatrick Boettcher }
2884173a64cbSPatrick Boettcher 
2885173a64cbSPatrick Boettcher static u16 dib8000_read_lock(struct dvb_frontend *fe)
2886173a64cbSPatrick Boettcher {
2887173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2888173a64cbSPatrick Boettcher 
2889173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
2890173a64cbSPatrick Boettcher 		return dib8000_read_word(state, 570);
2891173a64cbSPatrick Boettcher 	return dib8000_read_word(state, 568);
2892173a64cbSPatrick Boettcher }
2893173a64cbSPatrick Boettcher 
2894173a64cbSPatrick Boettcher static int dib8090p_init_sdram(struct dib8000_state *state)
2895173a64cbSPatrick Boettcher {
2896173a64cbSPatrick Boettcher 	u16 reg = 0;
2897173a64cbSPatrick Boettcher 	dprintk("init sdram");
2898173a64cbSPatrick Boettcher 
2899173a64cbSPatrick Boettcher 	reg = dib8000_read_word(state, 274) & 0xfff0;
2900173a64cbSPatrick Boettcher 	dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */
2901173a64cbSPatrick Boettcher 
2902173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1803, (7 << 2));
2903173a64cbSPatrick Boettcher 
2904173a64cbSPatrick Boettcher 	reg = dib8000_read_word(state, 1280);
2905173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1280,  reg | (1 << 2)); /* force restart P_restart_sdram */
2906173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1280,  reg); /* release restart P_restart_sdram */
2907173a64cbSPatrick Boettcher 
2908173a64cbSPatrick Boettcher 	return 0;
2909173a64cbSPatrick Boettcher }
2910173a64cbSPatrick Boettcher 
2911ad976187SMauro Carvalho Chehab /**
2912ad976187SMauro Carvalho Chehab  * is_manual_mode - Check if TMCC should be used for parameters settings
2913ad976187SMauro Carvalho Chehab  * @c:	struct dvb_frontend_properties
2914ad976187SMauro Carvalho Chehab  *
2915ad976187SMauro Carvalho Chehab  * By default, TMCC table should be used for parameter settings on most
2916ad976187SMauro Carvalho Chehab  * usercases. However, sometimes it is desirable to lock the demod to
2917ad976187SMauro Carvalho Chehab  * use the manual parameters.
2918ad976187SMauro Carvalho Chehab  *
2919ad976187SMauro Carvalho Chehab  * On manual mode, the current dib8000_tune state machine is very restrict:
2920ad976187SMauro Carvalho Chehab  * It requires that both per-layer and per-transponder parameters to be
2921ad976187SMauro Carvalho Chehab  * properly specified, otherwise the device won't lock.
2922ad976187SMauro Carvalho Chehab  *
2923ad976187SMauro Carvalho Chehab  * Check if all those conditions are properly satisfied before allowing
2924ad976187SMauro Carvalho Chehab  * the device to use the manual frequency lock mode.
2925ad976187SMauro Carvalho Chehab  */
2926ad976187SMauro Carvalho Chehab static int is_manual_mode(struct dtv_frontend_properties *c)
2927ad976187SMauro Carvalho Chehab {
2928ad976187SMauro Carvalho Chehab 	int i, n_segs = 0;
2929ad976187SMauro Carvalho Chehab 
2930ad976187SMauro Carvalho Chehab 	/* Use auto mode on DVB-T compat mode */
2931ad976187SMauro Carvalho Chehab 	if (c->delivery_system != SYS_ISDBT)
2932ad976187SMauro Carvalho Chehab 		return 0;
2933ad976187SMauro Carvalho Chehab 
2934ad976187SMauro Carvalho Chehab 	/*
2935ad976187SMauro Carvalho Chehab 	 * Transmission mode is only detected on auto mode, currently
2936ad976187SMauro Carvalho Chehab 	 */
2937ad976187SMauro Carvalho Chehab 	if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2938ad976187SMauro Carvalho Chehab 		dprintk("transmission mode auto");
2939ad976187SMauro Carvalho Chehab 		return 0;
2940ad976187SMauro Carvalho Chehab 	}
2941ad976187SMauro Carvalho Chehab 
2942ad976187SMauro Carvalho Chehab 	/*
2943ad976187SMauro Carvalho Chehab 	 * Guard interval is only detected on auto mode, currently
2944ad976187SMauro Carvalho Chehab 	 */
2945ad976187SMauro Carvalho Chehab 	if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2946ad976187SMauro Carvalho Chehab 		dprintk("guard interval auto");
2947ad976187SMauro Carvalho Chehab 		return 0;
2948ad976187SMauro Carvalho Chehab 	}
2949ad976187SMauro Carvalho Chehab 
2950ad976187SMauro Carvalho Chehab 	/*
2951ad976187SMauro Carvalho Chehab 	 * If no layer is enabled, assume auto mode, as at least one
2952ad976187SMauro Carvalho Chehab 	 * layer should be enabled
2953ad976187SMauro Carvalho Chehab 	 */
2954ad976187SMauro Carvalho Chehab 	if (!c->isdbt_layer_enabled) {
2955ad976187SMauro Carvalho Chehab 		dprintk("no layer modulation specified");
2956ad976187SMauro Carvalho Chehab 		return 0;
2957ad976187SMauro Carvalho Chehab 	}
2958ad976187SMauro Carvalho Chehab 
2959ad976187SMauro Carvalho Chehab 	/*
2960ad976187SMauro Carvalho Chehab 	 * Check if the per-layer parameters aren't auto and
2961ad976187SMauro Carvalho Chehab 	 * disable a layer if segment count is 0 or invalid.
2962ad976187SMauro Carvalho Chehab 	 */
2963ad976187SMauro Carvalho Chehab 	for (i = 0; i < 3; i++) {
2964ad976187SMauro Carvalho Chehab 		if (!(c->isdbt_layer_enabled & 1 << i))
2965ad976187SMauro Carvalho Chehab 			continue;
2966ad976187SMauro Carvalho Chehab 
2967ad976187SMauro Carvalho Chehab 		if ((c->layer[i].segment_count > 13) ||
2968ad976187SMauro Carvalho Chehab 		    (c->layer[i].segment_count == 0)) {
2969ad976187SMauro Carvalho Chehab 			c->isdbt_layer_enabled &= ~(1 << i);
2970ad976187SMauro Carvalho Chehab 			continue;
2971ad976187SMauro Carvalho Chehab 		}
2972ad976187SMauro Carvalho Chehab 
2973ad976187SMauro Carvalho Chehab 		n_segs += c->layer[i].segment_count;
2974ad976187SMauro Carvalho Chehab 
2975ad976187SMauro Carvalho Chehab 		if ((c->layer[i].modulation == QAM_AUTO) ||
2976ad976187SMauro Carvalho Chehab 		    (c->layer[i].fec == FEC_AUTO)) {
2977ad976187SMauro Carvalho Chehab 			dprintk("layer %c has either modulation or FEC auto",
2978ad976187SMauro Carvalho Chehab 				'A' + i);
2979ad976187SMauro Carvalho Chehab 			return 0;
2980ad976187SMauro Carvalho Chehab 		}
2981ad976187SMauro Carvalho Chehab 	}
2982ad976187SMauro Carvalho Chehab 
2983ad976187SMauro Carvalho Chehab 	/*
2984ad976187SMauro Carvalho Chehab 	 * Userspace specified a wrong number of segments.
2985ad976187SMauro Carvalho Chehab 	 *	fallback to auto mode.
2986ad976187SMauro Carvalho Chehab 	 */
2987ad976187SMauro Carvalho Chehab 	if (n_segs == 0 || n_segs > 13) {
2988ad976187SMauro Carvalho Chehab 		dprintk("number of segments is invalid");
2989ad976187SMauro Carvalho Chehab 		return 0;
2990ad976187SMauro Carvalho Chehab 	}
2991ad976187SMauro Carvalho Chehab 
2992ad976187SMauro Carvalho Chehab 	/* Everything looks ok for manual mode */
2993ad976187SMauro Carvalho Chehab 	return 1;
2994ad976187SMauro Carvalho Chehab }
2995ad976187SMauro Carvalho Chehab 
29969a0bf528SMauro Carvalho Chehab static int dib8000_tune(struct dvb_frontend *fe)
29979a0bf528SMauro Carvalho Chehab {
29989a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
2999c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3000173a64cbSPatrick Boettcher 	enum frontend_tune_state *tune_state = &state->tune_state;
30019a0bf528SMauro Carvalho Chehab 
3002173a64cbSPatrick Boettcher 	u16 locks, deeper_interleaver = 0, i;
3003173a64cbSPatrick Boettcher 	int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
30049a0bf528SMauro Carvalho Chehab 
3005173a64cbSPatrick Boettcher 	u32 *timeout = &state->timeout;
3006173a64cbSPatrick Boettcher 	u32 now = systime();
3007173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3008173a64cbSPatrick Boettcher 	u16 agc1, agc2;
3009173a64cbSPatrick Boettcher #endif
30109a0bf528SMauro Carvalho Chehab 
3011173a64cbSPatrick Boettcher 	u32 corm[4] = {0, 0, 0, 0};
3012173a64cbSPatrick Boettcher 	u8 find_index, max_value;
30139a0bf528SMauro Carvalho Chehab 
3014173a64cbSPatrick Boettcher #if 0
3015173a64cbSPatrick Boettcher 	if (*tune_state < CT_DEMOD_STOP)
3016173a64cbSPatrick Boettcher 		dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u systime = %u", state->channel_parameters_set, *tune_state, state->autosearch_state, now);
3017173a64cbSPatrick Boettcher #endif
30189a0bf528SMauro Carvalho Chehab 
3019173a64cbSPatrick Boettcher 	switch (*tune_state) {
3020173a64cbSPatrick Boettcher 	case CT_DEMOD_START: /* 30 */
30216ef06e78SMauro Carvalho Chehab 			dib8000_reset_stats(fe);
30226ef06e78SMauro Carvalho Chehab 
3023173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
3024173a64cbSPatrick Boettcher 				dib8090p_init_sdram(state);
3025173a64cbSPatrick Boettcher 			state->status = FE_STATUS_TUNE_PENDING;
3026ad976187SMauro Carvalho Chehab 			state->channel_parameters_set = is_manual_mode(c);
3027ad976187SMauro Carvalho Chehab 
3028ad976187SMauro Carvalho Chehab 			dprintk("Tuning channel on %s search mode",
3029ad976187SMauro Carvalho Chehab 				state->channel_parameters_set ? "manual" : "auto");
30309a0bf528SMauro Carvalho Chehab 
3031173a64cbSPatrick Boettcher 			dib8000_viterbi_state(state, 0); /* force chan dec in restart */
30329a0bf528SMauro Carvalho Chehab 
3033ad976187SMauro Carvalho Chehab 			/* Layer monitor */
3034173a64cbSPatrick Boettcher 			dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
3035173a64cbSPatrick Boettcher 
3036173a64cbSPatrick Boettcher 			dib8000_set_frequency_offset(state);
3037c82056d0SMauro Carvalho Chehab 			dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
3038173a64cbSPatrick Boettcher 
3039173a64cbSPatrick Boettcher 			if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
3040173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3041173a64cbSPatrick Boettcher 				if (state->revision != 0x8090) {
3042173a64cbSPatrick Boettcher 					state->agc1_max = dib8000_read_word(state, 108);
3043173a64cbSPatrick Boettcher 					state->agc1_min = dib8000_read_word(state, 109);
3044173a64cbSPatrick Boettcher 					state->agc2_max = dib8000_read_word(state, 110);
3045173a64cbSPatrick Boettcher 					state->agc2_min = dib8000_read_word(state, 111);
3046173a64cbSPatrick Boettcher 					agc1 = dib8000_read_word(state, 388);
3047173a64cbSPatrick Boettcher 					agc2 = dib8000_read_word(state, 389);
3048173a64cbSPatrick Boettcher 					dib8000_write_word(state, 108, agc1);
3049173a64cbSPatrick Boettcher 					dib8000_write_word(state, 109, agc1);
3050173a64cbSPatrick Boettcher 					dib8000_write_word(state, 110, agc2);
3051173a64cbSPatrick Boettcher 					dib8000_write_word(state, 111, agc2);
3052173a64cbSPatrick Boettcher 				}
3053173a64cbSPatrick Boettcher #endif
3054173a64cbSPatrick Boettcher 				state->autosearch_state = AS_SEARCHING_FFT;
3055173a64cbSPatrick Boettcher 				state->found_nfft = TRANSMISSION_MODE_AUTO;
3056173a64cbSPatrick Boettcher 				state->found_guard = GUARD_INTERVAL_AUTO;
3057173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_SEARCH_NEXT;
3058173a64cbSPatrick Boettcher 			} else { /* we already know the channel struct so TUNE only ! */
3059173a64cbSPatrick Boettcher 				state->autosearch_state = AS_DONE;
3060173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_3;
3061173a64cbSPatrick Boettcher 			}
3062173a64cbSPatrick Boettcher 			state->symbol_duration = dib8000_get_symbol_duration(state);
3063173a64cbSPatrick Boettcher 			break;
3064173a64cbSPatrick Boettcher 
3065173a64cbSPatrick Boettcher 	case CT_DEMOD_SEARCH_NEXT: /* 51 */
3066173a64cbSPatrick Boettcher 			dib8000_autosearch_start(fe);
3067173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
3068173a64cbSPatrick Boettcher 				ret = 50;
3069173a64cbSPatrick Boettcher 			else
3070173a64cbSPatrick Boettcher 				ret = 15;
3071173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_1;
3072173a64cbSPatrick Boettcher 			break;
3073173a64cbSPatrick Boettcher 
3074173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_1: /* 31 */
3075173a64cbSPatrick Boettcher 			switch (dib8000_autosearch_irq(fe)) {
3076173a64cbSPatrick Boettcher 			case 1: /* fail */
3077173a64cbSPatrick Boettcher 					state->status = FE_STATUS_TUNE_FAILED;
3078173a64cbSPatrick Boettcher 					state->autosearch_state = AS_DONE;
3079173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STOP; /* else we are done here */
3080173a64cbSPatrick Boettcher 					break;
3081173a64cbSPatrick Boettcher 			case 2: /* Succes */
3082173a64cbSPatrick Boettcher 					state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
3083173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_3;
3084173a64cbSPatrick Boettcher 					if (state->autosearch_state == AS_SEARCHING_GUARD)
3085173a64cbSPatrick Boettcher 						*tune_state = CT_DEMOD_STEP_2;
3086173a64cbSPatrick Boettcher 					else
3087173a64cbSPatrick Boettcher 						state->autosearch_state = AS_DONE;
3088173a64cbSPatrick Boettcher 					break;
3089173a64cbSPatrick Boettcher 			case 3: /* Autosearch FFT max correlation endded */
3090173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_2;
3091173a64cbSPatrick Boettcher 					break;
3092173a64cbSPatrick Boettcher 			}
3093173a64cbSPatrick Boettcher 			break;
3094173a64cbSPatrick Boettcher 
3095173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_2:
3096173a64cbSPatrick Boettcher 			switch (state->autosearch_state) {
3097173a64cbSPatrick Boettcher 			case AS_SEARCHING_FFT:
3098173a64cbSPatrick Boettcher 					/* searching for the correct FFT */
3099173a64cbSPatrick Boettcher 				if (state->revision == 0x8090) {
3100173a64cbSPatrick Boettcher 					corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3101173a64cbSPatrick Boettcher 					corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3102173a64cbSPatrick Boettcher 					corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
3103173a64cbSPatrick Boettcher 				} else {
3104173a64cbSPatrick Boettcher 					corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
3105173a64cbSPatrick Boettcher 					corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3106173a64cbSPatrick Boettcher 					corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3107173a64cbSPatrick Boettcher 				}
3108173a64cbSPatrick Boettcher 					/* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */
3109173a64cbSPatrick Boettcher 
3110173a64cbSPatrick Boettcher 					max_value = 0;
3111173a64cbSPatrick Boettcher 					for (find_index = 1 ; find_index < 3 ; find_index++) {
3112173a64cbSPatrick Boettcher 						if (corm[max_value] < corm[find_index])
3113173a64cbSPatrick Boettcher 							max_value = find_index ;
31149a0bf528SMauro Carvalho Chehab 					}
31159a0bf528SMauro Carvalho Chehab 
3116173a64cbSPatrick Boettcher 					switch (max_value) {
3117173a64cbSPatrick Boettcher 					case 0:
3118173a64cbSPatrick Boettcher 							state->found_nfft = TRANSMISSION_MODE_2K;
3119173a64cbSPatrick Boettcher 							break;
3120173a64cbSPatrick Boettcher 					case 1:
3121173a64cbSPatrick Boettcher 							state->found_nfft = TRANSMISSION_MODE_4K;
3122173a64cbSPatrick Boettcher 							break;
3123173a64cbSPatrick Boettcher 					case 2:
3124173a64cbSPatrick Boettcher 					default:
3125173a64cbSPatrick Boettcher 							state->found_nfft = TRANSMISSION_MODE_8K;
3126173a64cbSPatrick Boettcher 							break;
3127173a64cbSPatrick Boettcher 					}
3128173a64cbSPatrick Boettcher 					/* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */
3129173a64cbSPatrick Boettcher 
3130173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_SEARCH_NEXT;
3131173a64cbSPatrick Boettcher 					state->autosearch_state = AS_SEARCHING_GUARD;
3132173a64cbSPatrick Boettcher 					if (state->revision == 0x8090)
3133173a64cbSPatrick Boettcher 						ret = 50;
3134173a64cbSPatrick Boettcher 					else
3135173a64cbSPatrick Boettcher 						ret = 10;
3136173a64cbSPatrick Boettcher 					break;
3137173a64cbSPatrick Boettcher 			case AS_SEARCHING_GUARD:
3138173a64cbSPatrick Boettcher 					/* searching for the correct guard interval */
3139173a64cbSPatrick Boettcher 					if (state->revision == 0x8090)
3140173a64cbSPatrick Boettcher 						state->found_guard = dib8000_read_word(state, 572) & 0x3;
3141173a64cbSPatrick Boettcher 					else
3142173a64cbSPatrick Boettcher 						state->found_guard = dib8000_read_word(state, 570) & 0x3;
3143173a64cbSPatrick Boettcher 					/* dprintk("guard interval found=%i", state->found_guard); */
3144173a64cbSPatrick Boettcher 
3145173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_3;
3146173a64cbSPatrick Boettcher 					break;
3147173a64cbSPatrick Boettcher 			default:
3148173a64cbSPatrick Boettcher 					/* the demod should never be in this state */
3149173a64cbSPatrick Boettcher 					state->status = FE_STATUS_TUNE_FAILED;
3150173a64cbSPatrick Boettcher 					state->autosearch_state = AS_DONE;
3151173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STOP; /* else we are done here */
3152173a64cbSPatrick Boettcher 					break;
3153173a64cbSPatrick Boettcher 			}
3154173a64cbSPatrick Boettcher 			break;
3155173a64cbSPatrick Boettcher 
3156173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_3: /* 33 */
3157173a64cbSPatrick Boettcher 			state->symbol_duration = dib8000_get_symbol_duration(state);
3158173a64cbSPatrick Boettcher 			dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
3159173a64cbSPatrick Boettcher 			dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
3160173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_4;
3161173a64cbSPatrick Boettcher 			break;
3162173a64cbSPatrick Boettcher 
3163173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_4: /* (34) */
3164173a64cbSPatrick Boettcher 			dib8000_demod_restart(state);
3165173a64cbSPatrick Boettcher 
3166173a64cbSPatrick Boettcher 			dib8000_set_sync_wait(state);
3167173a64cbSPatrick Boettcher 			dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
3168173a64cbSPatrick Boettcher 
3169173a64cbSPatrick Boettcher 			locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
317039c1cb2bSJonathan McCrohan 			/* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */
3171173a64cbSPatrick Boettcher 			*timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
3172173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_5;
3173173a64cbSPatrick Boettcher 			break;
3174173a64cbSPatrick Boettcher 
3175173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_5: /* (35) */
3176173a64cbSPatrick Boettcher 			locks = dib8000_read_lock(fe);
3177173a64cbSPatrick Boettcher 			if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
3178173a64cbSPatrick Boettcher 				dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
3179173a64cbSPatrick Boettcher 				if (!state->differential_constellation) {
3180173a64cbSPatrick Boettcher 					/* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
3181173a64cbSPatrick Boettcher 					*timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
3182173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_7;
3183173a64cbSPatrick Boettcher 				} else {
3184173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_8;
3185173a64cbSPatrick Boettcher 				}
3186173a64cbSPatrick Boettcher 			} else if (now > *timeout) {
3187173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3188173a64cbSPatrick Boettcher 			}
3189173a64cbSPatrick Boettcher 			break;
3190173a64cbSPatrick Boettcher 
3191173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_6: /* (36)  if there is an input (diversity) */
3192173a64cbSPatrick Boettcher 			if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
3193173a64cbSPatrick 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 */
3194173a64cbSPatrick Boettcher 				if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
3195173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
3196173a64cbSPatrick Boettcher 				else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */
3197173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3198173a64cbSPatrick Boettcher 					dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3199173a64cbSPatrick Boettcher 					dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3200173a64cbSPatrick Boettcher 					state->status = FE_STATUS_TUNE_FAILED;
3201173a64cbSPatrick Boettcher 				}
3202173a64cbSPatrick Boettcher 			} else {
3203173a64cbSPatrick Boettcher 				dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3204173a64cbSPatrick Boettcher 				dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3205173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3206173a64cbSPatrick Boettcher 				state->status = FE_STATUS_TUNE_FAILED;
3207173a64cbSPatrick Boettcher 			}
3208173a64cbSPatrick Boettcher 			break;
3209173a64cbSPatrick Boettcher 
3210173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_7: /* 37 */
3211173a64cbSPatrick Boettcher 			locks = dib8000_read_lock(fe);
3212173a64cbSPatrick Boettcher 			if (locks & (1<<10)) { /* lmod4_lock */
3213173a64cbSPatrick Boettcher 				ret = 14; /* wait for 14 symbols */
3214173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_8;
3215173a64cbSPatrick Boettcher 			} else if (now > *timeout)
3216173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3217173a64cbSPatrick Boettcher 			break;
3218173a64cbSPatrick Boettcher 
3219173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_8: /* 38 */
3220173a64cbSPatrick Boettcher 			dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3221173a64cbSPatrick Boettcher 			dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3222173a64cbSPatrick Boettcher 
3223173a64cbSPatrick Boettcher 			/* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
3224746f7ae0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode
3225746f7ae0SMauro Carvalho Chehab 			    && c->isdbt_sb_subchannel < 14
3226746f7ae0SMauro Carvalho Chehab 			    && !state->differential_constellation) {
3227173a64cbSPatrick Boettcher 				state->subchannel = 0;
3228173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_11;
3229173a64cbSPatrick Boettcher 			} else {
3230173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_9;
3231173a64cbSPatrick Boettcher 				state->status = FE_STATUS_LOCKED;
3232173a64cbSPatrick Boettcher 			}
3233173a64cbSPatrick Boettcher 			break;
3234173a64cbSPatrick Boettcher 
3235173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_9: /* 39 */
3236173a64cbSPatrick Boettcher 			if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
323739c1cb2bSJonathan McCrohan 				/* defines timeout for mpeg lock depending on interleaver length of longest layer */
3238173a64cbSPatrick Boettcher 				for (i = 0; i < 3; i++) {
3239c82056d0SMauro Carvalho Chehab 					if (c->layer[i].interleaving >= deeper_interleaver) {
3240c82056d0SMauro Carvalho Chehab 						dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving);
3241c82056d0SMauro Carvalho Chehab 						if (c->layer[i].segment_count > 0) { /* valid layer */
3242c82056d0SMauro Carvalho Chehab 							deeper_interleaver = c->layer[0].interleaving;
3243173a64cbSPatrick Boettcher 							state->longest_intlv_layer = i;
3244173a64cbSPatrick Boettcher 						}
3245173a64cbSPatrick Boettcher 					}
3246173a64cbSPatrick Boettcher 				}
3247173a64cbSPatrick Boettcher 
3248173a64cbSPatrick Boettcher 				if (deeper_interleaver == 0)
3249173a64cbSPatrick Boettcher 					locks = 2; /* locks is the tmp local variable name */
3250173a64cbSPatrick Boettcher 				else if (deeper_interleaver == 3)
3251173a64cbSPatrick Boettcher 					locks = 8;
3252173a64cbSPatrick Boettcher 				else
3253173a64cbSPatrick Boettcher 					locks = 2 * deeper_interleaver;
3254173a64cbSPatrick Boettcher 
3255173a64cbSPatrick Boettcher 				if (state->diversity_onoff != 0) /* because of diversity sync */
3256173a64cbSPatrick Boettcher 					locks *= 2;
3257173a64cbSPatrick Boettcher 
3258173a64cbSPatrick Boettcher 				*timeout = now + (2000 * locks); /* give the mpeg lock 800ms if sram is present */
3259173a64cbSPatrick 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);
3260173a64cbSPatrick Boettcher 
3261173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_10;
3262173a64cbSPatrick Boettcher 			} else
3263173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP;
3264173a64cbSPatrick Boettcher 			break;
3265173a64cbSPatrick Boettcher 
3266173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_10: /* 40 */
3267173a64cbSPatrick Boettcher 			locks = dib8000_read_lock(fe);
3268173a64cbSPatrick Boettcher 			if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
3269173a64cbSPatrick Boettcher 				dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
3270746f7ae0SMauro Carvalho Chehab 				if (c->isdbt_sb_mode
3271746f7ae0SMauro Carvalho Chehab 				    && c->isdbt_sb_subchannel < 14
3272746f7ae0SMauro Carvalho Chehab 				    && !state->differential_constellation)
3273173a64cbSPatrick Boettcher 					/* signal to the upper layer, that there was a channel found and the parameters can be read */
3274173a64cbSPatrick Boettcher 					state->status = FE_STATUS_DEMOD_SUCCESS;
3275173a64cbSPatrick Boettcher 				else
3276173a64cbSPatrick Boettcher 					state->status = FE_STATUS_DATA_LOCKED;
3277173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP;
3278173a64cbSPatrick Boettcher 			} else if (now > *timeout) {
3279746f7ae0SMauro Carvalho Chehab 				if (c->isdbt_sb_mode
3280746f7ae0SMauro Carvalho Chehab 				    && c->isdbt_sb_subchannel < 14
3281746f7ae0SMauro Carvalho Chehab 				    && !state->differential_constellation) { /* continue to try init prbs autosearch */
3282173a64cbSPatrick Boettcher 					state->subchannel += 3;
3283173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_11;
3284173a64cbSPatrick 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 */
3285173a64cbSPatrick Boettcher 					if (locks & (0x7<<5)) {
3286173a64cbSPatrick Boettcher 						dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
3287173a64cbSPatrick Boettcher 						state->status = FE_STATUS_DATA_LOCKED;
3288173a64cbSPatrick Boettcher 					} else
3289173a64cbSPatrick Boettcher 						state->status = FE_STATUS_TUNE_FAILED;
3290173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STOP;
3291173a64cbSPatrick Boettcher 				}
3292173a64cbSPatrick Boettcher 			}
3293173a64cbSPatrick Boettcher 			break;
3294173a64cbSPatrick Boettcher 
3295173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_11:  /* 41 : init prbs autosearch */
3296173a64cbSPatrick Boettcher 			if (state->subchannel <= 41) {
3297173a64cbSPatrick Boettcher 				dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
3298173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_9;
3299173a64cbSPatrick Boettcher 			} else {
3300173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP;
3301173a64cbSPatrick Boettcher 				state->status = FE_STATUS_TUNE_FAILED;
3302173a64cbSPatrick Boettcher 			}
3303173a64cbSPatrick Boettcher 			break;
3304173a64cbSPatrick Boettcher 
3305173a64cbSPatrick Boettcher 	default:
3306173a64cbSPatrick Boettcher 			break;
3307173a64cbSPatrick Boettcher 	}
3308173a64cbSPatrick Boettcher 
3309173a64cbSPatrick Boettcher 	/* tuning is finished - cleanup the demod */
3310173a64cbSPatrick Boettcher 	switch (*tune_state) {
3311173a64cbSPatrick Boettcher 	case CT_DEMOD_STOP: /* (42) */
3312173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3313173a64cbSPatrick Boettcher 			if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
3314173a64cbSPatrick Boettcher 				dib8000_write_word(state, 108, state->agc1_max);
3315173a64cbSPatrick Boettcher 				dib8000_write_word(state, 109, state->agc1_min);
3316173a64cbSPatrick Boettcher 				dib8000_write_word(state, 110, state->agc2_max);
3317173a64cbSPatrick Boettcher 				dib8000_write_word(state, 111, state->agc2_min);
3318173a64cbSPatrick Boettcher 				state->agc1_max = 0;
3319173a64cbSPatrick Boettcher 				state->agc1_min = 0;
3320173a64cbSPatrick Boettcher 				state->agc2_max = 0;
3321173a64cbSPatrick Boettcher 				state->agc2_min = 0;
3322173a64cbSPatrick Boettcher 			}
3323173a64cbSPatrick Boettcher #endif
3324173a64cbSPatrick Boettcher 			ret = FE_CALLBACK_TIME_NEVER;
3325173a64cbSPatrick Boettcher 			break;
3326173a64cbSPatrick Boettcher 	default:
3327173a64cbSPatrick Boettcher 			break;
3328173a64cbSPatrick Boettcher 	}
3329173a64cbSPatrick Boettcher 
3330173a64cbSPatrick Boettcher 	if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
3331173a64cbSPatrick Boettcher 		return ret * state->symbol_duration;
3332173a64cbSPatrick Boettcher 	if ((ret > 0) && (ret < state->symbol_duration))
3333173a64cbSPatrick Boettcher 		return state->symbol_duration; /* at least one symbol */
33349a0bf528SMauro Carvalho Chehab 	return ret;
33359a0bf528SMauro Carvalho Chehab }
33369a0bf528SMauro Carvalho Chehab 
33379a0bf528SMauro Carvalho Chehab static int dib8000_wakeup(struct dvb_frontend *fe)
33389a0bf528SMauro Carvalho Chehab {
33399a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
33409a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
33419a0bf528SMauro Carvalho Chehab 	int ret;
33429a0bf528SMauro Carvalho Chehab 
33439a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
33449a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_ADC_ON);
33459a0bf528SMauro Carvalho Chehab 	if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
33469a0bf528SMauro Carvalho Chehab 		dprintk("could not start Slow ADC");
33479a0bf528SMauro Carvalho Chehab 
3348173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
33499a0bf528SMauro Carvalho Chehab 		dib8000_sad_calib(state);
33509a0bf528SMauro Carvalho Chehab 
33519a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
33529a0bf528SMauro Carvalho Chehab 		ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
33539a0bf528SMauro Carvalho Chehab 		if (ret < 0)
33549a0bf528SMauro Carvalho Chehab 			return ret;
33559a0bf528SMauro Carvalho Chehab 	}
33569a0bf528SMauro Carvalho Chehab 
33579a0bf528SMauro Carvalho Chehab 	return 0;
33589a0bf528SMauro Carvalho Chehab }
33599a0bf528SMauro Carvalho Chehab 
33609a0bf528SMauro Carvalho Chehab static int dib8000_sleep(struct dvb_frontend *fe)
33619a0bf528SMauro Carvalho Chehab {
33629a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
33639a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
33649a0bf528SMauro Carvalho Chehab 	int ret;
33659a0bf528SMauro Carvalho Chehab 
33669a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
33679a0bf528SMauro Carvalho Chehab 		ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
33689a0bf528SMauro Carvalho Chehab 		if (ret < 0)
33699a0bf528SMauro Carvalho Chehab 			return ret;
33709a0bf528SMauro Carvalho Chehab 	}
33719a0bf528SMauro Carvalho Chehab 
33729a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
33739a0bf528SMauro Carvalho Chehab 		dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
33749a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
33759a0bf528SMauro Carvalho Chehab 	return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
33769a0bf528SMauro Carvalho Chehab }
33779a0bf528SMauro Carvalho Chehab 
337870315b3eSMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat);
337970315b3eSMauro Carvalho Chehab 
33809a0bf528SMauro Carvalho Chehab static int dib8000_get_frontend(struct dvb_frontend *fe)
33819a0bf528SMauro Carvalho Chehab {
33829a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
33839a0bf528SMauro Carvalho Chehab 	u16 i, val = 0;
338470315b3eSMauro Carvalho Chehab 	fe_status_t stat = 0;
33859a0bf528SMauro Carvalho Chehab 	u8 index_frontend, sub_index_frontend;
33869a0bf528SMauro Carvalho Chehab 
33879a0bf528SMauro Carvalho Chehab 	fe->dtv_property_cache.bandwidth_hz = 6000000;
33889a0bf528SMauro Carvalho Chehab 
338970315b3eSMauro Carvalho Chehab 	/*
339070315b3eSMauro Carvalho Chehab 	 * If called to early, get_frontend makes dib8000_tune to either
339170315b3eSMauro Carvalho Chehab 	 * not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail.
339270315b3eSMauro Carvalho Chehab 	 * So, let's just return if frontend 0 has not locked.
339370315b3eSMauro Carvalho Chehab 	 */
339470315b3eSMauro Carvalho Chehab 	dib8000_read_status(fe, &stat);
339570315b3eSMauro Carvalho Chehab 	if (!(stat & FE_HAS_SYNC))
339670315b3eSMauro Carvalho Chehab 		return 0;
339770315b3eSMauro Carvalho Chehab 
339870315b3eSMauro Carvalho Chehab 	dprintk("TMCC lock");
33999a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
34009a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
34019a0bf528SMauro Carvalho Chehab 		if (stat&FE_HAS_SYNC) {
34029a0bf528SMauro Carvalho Chehab 			dprintk("TMCC lock on the slave%i", index_frontend);
34039a0bf528SMauro Carvalho Chehab 			/* synchronize the cache with the other frontends */
34049a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
34059a0bf528SMauro Carvalho Chehab 			for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {
34069a0bf528SMauro Carvalho Chehab 				if (sub_index_frontend != index_frontend) {
34079a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
34089a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
34099a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
34109a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
34119a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
34129a0bf528SMauro Carvalho Chehab 					for (i = 0; i < 3; i++) {
34139a0bf528SMauro 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;
34149a0bf528SMauro Carvalho Chehab 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
34159a0bf528SMauro Carvalho Chehab 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
34169a0bf528SMauro Carvalho Chehab 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
34179a0bf528SMauro Carvalho Chehab 					}
34189a0bf528SMauro Carvalho Chehab 				}
34199a0bf528SMauro Carvalho Chehab 			}
34209a0bf528SMauro Carvalho Chehab 			return 0;
34219a0bf528SMauro Carvalho Chehab 		}
34229a0bf528SMauro Carvalho Chehab 	}
34239a0bf528SMauro Carvalho Chehab 
34249a0bf528SMauro Carvalho Chehab 	fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
34259a0bf528SMauro Carvalho Chehab 
34269a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
34279a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 572);
34289a0bf528SMauro Carvalho Chehab 	else
34299a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 570);
34309a0bf528SMauro Carvalho Chehab 	fe->dtv_property_cache.inversion = (val & 0x40) >> 6;
34319a0bf528SMauro Carvalho Chehab 	switch ((val & 0x30) >> 4) {
34329a0bf528SMauro Carvalho Chehab 	case 1:
34339a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
34349a0bf528SMauro Carvalho Chehab 		break;
34359a0bf528SMauro Carvalho Chehab 	case 3:
34369a0bf528SMauro Carvalho Chehab 	default:
34379a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
34389a0bf528SMauro Carvalho Chehab 		break;
34399a0bf528SMauro Carvalho Chehab 	}
34409a0bf528SMauro Carvalho Chehab 
34419a0bf528SMauro Carvalho Chehab 	switch (val & 0x3) {
34429a0bf528SMauro Carvalho Chehab 	case 0:
34439a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
34449a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend GI = 1/32 ");
34459a0bf528SMauro Carvalho Chehab 		break;
34469a0bf528SMauro Carvalho Chehab 	case 1:
34479a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
34489a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend GI = 1/16 ");
34499a0bf528SMauro Carvalho Chehab 		break;
34509a0bf528SMauro Carvalho Chehab 	case 2:
34519a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend GI = 1/8 ");
34529a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
34539a0bf528SMauro Carvalho Chehab 		break;
34549a0bf528SMauro Carvalho Chehab 	case 3:
34559a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend GI = 1/4 ");
34569a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
34579a0bf528SMauro Carvalho Chehab 		break;
34589a0bf528SMauro Carvalho Chehab 	}
34599a0bf528SMauro Carvalho Chehab 
34609a0bf528SMauro Carvalho Chehab 	val = dib8000_read_word(state, 505);
34619a0bf528SMauro Carvalho Chehab 	fe->dtv_property_cache.isdbt_partial_reception = val & 1;
34629a0bf528SMauro Carvalho Chehab 	dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
34639a0bf528SMauro Carvalho Chehab 
34649a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 3; i++) {
34659a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 493 + i);
34669a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;
34679a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);
34689a0bf528SMauro Carvalho Chehab 
346951fea113SMauro Carvalho Chehab 		val = dib8000_read_word(state, 499 + i) & 0x3;
347051fea113SMauro Carvalho Chehab 		/* Interleaving can be 0, 1, 2 or 4 */
347151fea113SMauro Carvalho Chehab 		if (val == 3)
347251fea113SMauro Carvalho Chehab 			val = 4;
347351fea113SMauro Carvalho Chehab 		fe->dtv_property_cache.layer[i].interleaving = val;
347451fea113SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ",
347551fea113SMauro Carvalho Chehab 			i, fe->dtv_property_cache.layer[i].interleaving);
34769a0bf528SMauro Carvalho Chehab 
34779a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 481 + i);
34789a0bf528SMauro Carvalho Chehab 		switch (val & 0x7) {
34799a0bf528SMauro Carvalho Chehab 		case 1:
34809a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_1_2;
34819a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i);
34829a0bf528SMauro Carvalho Chehab 			break;
34839a0bf528SMauro Carvalho Chehab 		case 2:
34849a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_2_3;
34859a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i);
34869a0bf528SMauro Carvalho Chehab 			break;
34879a0bf528SMauro Carvalho Chehab 		case 3:
34889a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_3_4;
34899a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i);
34909a0bf528SMauro Carvalho Chehab 			break;
34919a0bf528SMauro Carvalho Chehab 		case 5:
34929a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_5_6;
34939a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i);
34949a0bf528SMauro Carvalho Chehab 			break;
34959a0bf528SMauro Carvalho Chehab 		default:
34969a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_7_8;
34979a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i);
34989a0bf528SMauro Carvalho Chehab 			break;
34999a0bf528SMauro Carvalho Chehab 		}
35009a0bf528SMauro Carvalho Chehab 
35019a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 487 + i);
35029a0bf528SMauro Carvalho Chehab 		switch (val & 0x3) {
35039a0bf528SMauro Carvalho Chehab 		case 0:
35049a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d DQPSK ", i);
35059a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].modulation = DQPSK;
35069a0bf528SMauro Carvalho Chehab 			break;
35079a0bf528SMauro Carvalho Chehab 		case 1:
35089a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].modulation = QPSK;
35099a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d QPSK ", i);
35109a0bf528SMauro Carvalho Chehab 			break;
35119a0bf528SMauro Carvalho Chehab 		case 2:
35129a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].modulation = QAM_16;
35139a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d QAM16 ", i);
35149a0bf528SMauro Carvalho Chehab 			break;
35159a0bf528SMauro Carvalho Chehab 		case 3:
35169a0bf528SMauro Carvalho Chehab 		default:
35179a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d QAM64 ", i);
35189a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].modulation = QAM_64;
35199a0bf528SMauro Carvalho Chehab 			break;
35209a0bf528SMauro Carvalho Chehab 		}
35219a0bf528SMauro Carvalho Chehab 	}
35229a0bf528SMauro Carvalho Chehab 
35239a0bf528SMauro Carvalho Chehab 	/* synchronize the cache with the other frontends */
35249a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
35259a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode;
35269a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
35279a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
35289a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
35299a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception;
35309a0bf528SMauro Carvalho Chehab 		for (i = 0; i < 3; i++) {
35319a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count;
35329a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving;
35339a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec;
35349a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation;
35359a0bf528SMauro Carvalho Chehab 		}
35369a0bf528SMauro Carvalho Chehab 	}
35379a0bf528SMauro Carvalho Chehab 	return 0;
35389a0bf528SMauro Carvalho Chehab }
35399a0bf528SMauro Carvalho Chehab 
35409a0bf528SMauro Carvalho Chehab static int dib8000_set_frontend(struct dvb_frontend *fe)
35419a0bf528SMauro Carvalho Chehab {
35429a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
3543c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
35444d8d5d92SGeert Uytterhoeven 	int l, i, active, time, time_slave = FE_CALLBACK_TIME_NEVER;
3545173a64cbSPatrick Boettcher 	u8 exit_condition, index_frontend;
3546173a64cbSPatrick Boettcher 	u32 delay, callback_time;
35479a0bf528SMauro Carvalho Chehab 
3548c82056d0SMauro Carvalho Chehab 	if (c->frequency == 0) {
35499a0bf528SMauro Carvalho Chehab 		dprintk("dib8000: must at least specify frequency ");
35509a0bf528SMauro Carvalho Chehab 		return 0;
35519a0bf528SMauro Carvalho Chehab 	}
35529a0bf528SMauro Carvalho Chehab 
3553c82056d0SMauro Carvalho Chehab 	if (c->bandwidth_hz == 0) {
35549a0bf528SMauro Carvalho Chehab 		dprintk("dib8000: no bandwidth specified, set to default ");
3555c82056d0SMauro Carvalho Chehab 		c->bandwidth_hz = 6000000;
35569a0bf528SMauro Carvalho Chehab 	}
35579a0bf528SMauro Carvalho Chehab 
35589a0bf528SMauro Carvalho Chehab 	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
35599a0bf528SMauro Carvalho Chehab 		/* synchronization of the cache */
35609a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
35619a0bf528SMauro Carvalho Chehab 		memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
35629a0bf528SMauro Carvalho Chehab 
3563173a64cbSPatrick Boettcher 		/* set output mode and diversity input */
3564173a64cbSPatrick Boettcher 		if (state->revision != 0x8090) {
3565173a64cbSPatrick Boettcher 			dib8000_set_diversity_in(state->fe[index_frontend], 1);
3566173a64cbSPatrick Boettcher 			if (index_frontend != 0)
35679a0bf528SMauro Carvalho Chehab 				dib8000_set_output_mode(state->fe[index_frontend],
3568173a64cbSPatrick Boettcher 						OUTMODE_DIVERSITY);
35699a0bf528SMauro Carvalho Chehab 			else
3570173a64cbSPatrick Boettcher 				dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3571173a64cbSPatrick Boettcher 		} else {
3572173a64cbSPatrick Boettcher 			dib8096p_set_diversity_in(state->fe[index_frontend], 1);
3573173a64cbSPatrick Boettcher 			if (index_frontend != 0)
35749a0bf528SMauro Carvalho Chehab 				dib8096p_set_output_mode(state->fe[index_frontend],
3575173a64cbSPatrick Boettcher 						OUTMODE_DIVERSITY);
3576173a64cbSPatrick Boettcher 			else
3577173a64cbSPatrick Boettcher 				dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3578173a64cbSPatrick Boettcher 		}
3579173a64cbSPatrick Boettcher 
3580173a64cbSPatrick Boettcher 		/* tune the tuner */
35819a0bf528SMauro Carvalho Chehab 		if (state->fe[index_frontend]->ops.tuner_ops.set_params)
35829a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
35839a0bf528SMauro Carvalho Chehab 
35849a0bf528SMauro Carvalho Chehab 		dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
35859a0bf528SMauro Carvalho Chehab 	}
35869a0bf528SMauro Carvalho Chehab 
3587173a64cbSPatrick Boettcher 	/* turn off the diversity of the last chip */
3588173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
3589173a64cbSPatrick Boettcher 		dib8000_set_diversity_in(state->fe[index_frontend - 1], 0);
3590173a64cbSPatrick Boettcher 	else
3591173a64cbSPatrick Boettcher 		dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0);
3592173a64cbSPatrick Boettcher 
35939a0bf528SMauro Carvalho Chehab 	/* start up the AGC */
35949a0bf528SMauro Carvalho Chehab 	do {
35959a0bf528SMauro Carvalho Chehab 		time = dib8000_agc_startup(state->fe[0]);
35969a0bf528SMauro Carvalho Chehab 		for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
35979a0bf528SMauro Carvalho Chehab 			time_slave = dib8000_agc_startup(state->fe[index_frontend]);
35989a0bf528SMauro Carvalho Chehab 			if (time == FE_CALLBACK_TIME_NEVER)
35999a0bf528SMauro Carvalho Chehab 				time = time_slave;
36009a0bf528SMauro Carvalho Chehab 			else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time))
36019a0bf528SMauro Carvalho Chehab 				time = time_slave;
36029a0bf528SMauro Carvalho Chehab 		}
36039a0bf528SMauro Carvalho Chehab 		if (time != FE_CALLBACK_TIME_NEVER)
36049a0bf528SMauro Carvalho Chehab 			msleep(time / 10);
36059a0bf528SMauro Carvalho Chehab 		else
36069a0bf528SMauro Carvalho Chehab 			break;
36079a0bf528SMauro Carvalho Chehab 		exit_condition = 1;
36089a0bf528SMauro Carvalho Chehab 		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
36099a0bf528SMauro Carvalho Chehab 			if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
36109a0bf528SMauro Carvalho Chehab 				exit_condition = 0;
36119a0bf528SMauro Carvalho Chehab 				break;
36129a0bf528SMauro Carvalho Chehab 			}
36139a0bf528SMauro Carvalho Chehab 		}
36149a0bf528SMauro Carvalho Chehab 	} while (exit_condition == 0);
36159a0bf528SMauro Carvalho Chehab 
36169a0bf528SMauro Carvalho Chehab 	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
36179a0bf528SMauro Carvalho Chehab 		dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
36189a0bf528SMauro Carvalho Chehab 
3619173a64cbSPatrick Boettcher 	active = 1;
36209a0bf528SMauro Carvalho Chehab 	do {
3621173a64cbSPatrick Boettcher 		callback_time = FE_CALLBACK_TIME_NEVER;
36229a0bf528SMauro Carvalho Chehab 		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3623173a64cbSPatrick Boettcher 			delay = dib8000_tune(state->fe[index_frontend]);
3624173a64cbSPatrick Boettcher 			if (delay != FE_CALLBACK_TIME_NEVER)
3625173a64cbSPatrick Boettcher 				delay += systime();
3626173a64cbSPatrick Boettcher 
3627173a64cbSPatrick Boettcher 			/* we are in autosearch */
3628173a64cbSPatrick Boettcher 			if (state->channel_parameters_set == 0) { /* searching */
3629173a64cbSPatrick Boettcher 				if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) {
3630173a64cbSPatrick Boettcher 					dprintk("autosearch succeeded on fe%i", index_frontend);
3631173a64cbSPatrick Boettcher 					dib8000_get_frontend(state->fe[index_frontend]); /* we read the channel parameters from the frontend which was successful */
3632173a64cbSPatrick Boettcher 					state->channel_parameters_set = 1;
3633173a64cbSPatrick Boettcher 
3634173a64cbSPatrick Boettcher 					for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
3635173a64cbSPatrick Boettcher 						if (l != index_frontend) { /* and for all frontend except the successful one */
3636173a64cbSPatrick Boettcher 							dib8000_tune_restart_from_demod(state->fe[l]);
3637173a64cbSPatrick Boettcher 
3638173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3639173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3640173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3641173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3642173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3643173a64cbSPatrick Boettcher 							for (i = 0; i < 3; i++) {
3644173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3645173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3646173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3647173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3648173a64cbSPatrick Boettcher 							}
3649173a64cbSPatrick Boettcher 
36509a0bf528SMauro Carvalho Chehab 						}
36519a0bf528SMauro Carvalho Chehab 					}
36529a0bf528SMauro Carvalho Chehab 				}
3653173a64cbSPatrick Boettcher 			}
3654173a64cbSPatrick Boettcher 			if (delay < callback_time)
3655173a64cbSPatrick Boettcher 				callback_time = delay;
3656173a64cbSPatrick Boettcher 		}
3657173a64cbSPatrick Boettcher 		/* tuning is done when the master frontend is done (failed or success) */
3658173a64cbSPatrick Boettcher 		if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
3659173a64cbSPatrick Boettcher 				dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED ||
3660173a64cbSPatrick Boettcher 				dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) {
3661173a64cbSPatrick Boettcher 			active = 0;
3662173a64cbSPatrick Boettcher 			/* we need to wait for all frontends to be finished */
3663173a64cbSPatrick Boettcher 			for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3664173a64cbSPatrick Boettcher 				if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP)
3665173a64cbSPatrick Boettcher 					active = 1;
3666173a64cbSPatrick Boettcher 			}
3667173a64cbSPatrick Boettcher 			if (active == 0)
3668173a64cbSPatrick Boettcher 				dprintk("tuning done with status %d", dib8000_get_status(state->fe[0]));
36699a0bf528SMauro Carvalho Chehab 		}
36709a0bf528SMauro Carvalho Chehab 
3671173a64cbSPatrick Boettcher 		if ((active == 1) && (callback_time == FE_CALLBACK_TIME_NEVER)) {
3672173a64cbSPatrick Boettcher 			dprintk("strange callback time something went wrong");
3673173a64cbSPatrick Boettcher 			active = 0;
36749a0bf528SMauro Carvalho Chehab 		}
36759a0bf528SMauro Carvalho Chehab 
3676173a64cbSPatrick Boettcher 		while ((active == 1) && (systime() < callback_time))
3677173a64cbSPatrick Boettcher 			msleep(100);
3678173a64cbSPatrick Boettcher 	} while (active);
36799a0bf528SMauro Carvalho Chehab 
3680173a64cbSPatrick Boettcher 	/* set output mode */
3681173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
36829a0bf528SMauro Carvalho Chehab 		dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
3683173a64cbSPatrick Boettcher 	else {
36849a0bf528SMauro Carvalho Chehab 		dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
36859a0bf528SMauro Carvalho Chehab 		if (state->cfg.enMpegOutput == 0) {
36869a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
36879a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
36889a0bf528SMauro Carvalho Chehab 		}
36899a0bf528SMauro Carvalho Chehab 	}
36909a0bf528SMauro Carvalho Chehab 
36914d8d5d92SGeert Uytterhoeven 	return 0;
36929a0bf528SMauro Carvalho Chehab }
36939a0bf528SMauro Carvalho Chehab 
36946ef06e78SMauro Carvalho Chehab static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat);
36956ef06e78SMauro Carvalho Chehab 
36969a0bf528SMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
36979a0bf528SMauro Carvalho Chehab {
36989a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
36999a0bf528SMauro Carvalho Chehab 	u16 lock_slave = 0, lock;
37009a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
37019a0bf528SMauro Carvalho Chehab 
3702173a64cbSPatrick Boettcher 	lock = dib8000_read_lock(fe);
37039a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
37049a0bf528SMauro Carvalho Chehab 		lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
37059a0bf528SMauro Carvalho Chehab 
37069a0bf528SMauro Carvalho Chehab 	*stat = 0;
37079a0bf528SMauro Carvalho Chehab 
37089a0bf528SMauro Carvalho Chehab 	if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
37099a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SIGNAL;
37109a0bf528SMauro Carvalho Chehab 
37119a0bf528SMauro Carvalho Chehab 	if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
37129a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_CARRIER;
37139a0bf528SMauro Carvalho Chehab 
37149a0bf528SMauro Carvalho Chehab 	if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
37159a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SYNC;
37169a0bf528SMauro Carvalho Chehab 
37179a0bf528SMauro Carvalho Chehab 	if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
37189a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_LOCK;
37199a0bf528SMauro Carvalho Chehab 
37209a0bf528SMauro Carvalho Chehab 	if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
37219a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
37229a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
37239a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
37249a0bf528SMauro Carvalho Chehab 
37259a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
37269a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
37279a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
37289a0bf528SMauro Carvalho Chehab 
37299a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
37309a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
37319a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
37329a0bf528SMauro Carvalho Chehab 	}
37336ef06e78SMauro Carvalho Chehab 	dib8000_get_stats(fe, *stat);
37349a0bf528SMauro Carvalho Chehab 
37359a0bf528SMauro Carvalho Chehab 	return 0;
37369a0bf528SMauro Carvalho Chehab }
37379a0bf528SMauro Carvalho Chehab 
37389a0bf528SMauro Carvalho Chehab static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
37399a0bf528SMauro Carvalho Chehab {
37409a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37419a0bf528SMauro Carvalho Chehab 
37429a0bf528SMauro Carvalho Chehab 	/* 13 segments */
37439a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
37449a0bf528SMauro Carvalho Chehab 		*ber = (dib8000_read_word(state, 562) << 16) |
37459a0bf528SMauro Carvalho Chehab 			dib8000_read_word(state, 563);
37469a0bf528SMauro Carvalho Chehab 	else
37479a0bf528SMauro Carvalho Chehab 		*ber = (dib8000_read_word(state, 560) << 16) |
37489a0bf528SMauro Carvalho Chehab 			dib8000_read_word(state, 561);
37499a0bf528SMauro Carvalho Chehab 	return 0;
37509a0bf528SMauro Carvalho Chehab }
37519a0bf528SMauro Carvalho Chehab 
37529a0bf528SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
37539a0bf528SMauro Carvalho Chehab {
37549a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37559a0bf528SMauro Carvalho Chehab 
37569a0bf528SMauro Carvalho Chehab 	/* packet error on 13 seg */
37579a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
37589a0bf528SMauro Carvalho Chehab 		*unc = dib8000_read_word(state, 567);
37599a0bf528SMauro Carvalho Chehab 	else
37609a0bf528SMauro Carvalho Chehab 		*unc = dib8000_read_word(state, 565);
37619a0bf528SMauro Carvalho Chehab 	return 0;
37629a0bf528SMauro Carvalho Chehab }
37639a0bf528SMauro Carvalho Chehab 
37649a0bf528SMauro Carvalho Chehab static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
37659a0bf528SMauro Carvalho Chehab {
37669a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37679a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
37689a0bf528SMauro Carvalho Chehab 	u16 val;
37699a0bf528SMauro Carvalho Chehab 
37709a0bf528SMauro Carvalho Chehab 	*strength = 0;
37719a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
37729a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
37739a0bf528SMauro Carvalho Chehab 		if (val > 65535 - *strength)
37749a0bf528SMauro Carvalho Chehab 			*strength = 65535;
37759a0bf528SMauro Carvalho Chehab 		else
37769a0bf528SMauro Carvalho Chehab 			*strength += val;
37779a0bf528SMauro Carvalho Chehab 	}
37789a0bf528SMauro Carvalho Chehab 
37799a0bf528SMauro Carvalho Chehab 	val = 65535 - dib8000_read_word(state, 390);
37809a0bf528SMauro Carvalho Chehab 	if (val > 65535 - *strength)
37819a0bf528SMauro Carvalho Chehab 		*strength = 65535;
37829a0bf528SMauro Carvalho Chehab 	else
37839a0bf528SMauro Carvalho Chehab 		*strength += val;
37849a0bf528SMauro Carvalho Chehab 	return 0;
37859a0bf528SMauro Carvalho Chehab }
37869a0bf528SMauro Carvalho Chehab 
37879a0bf528SMauro Carvalho Chehab static u32 dib8000_get_snr(struct dvb_frontend *fe)
37889a0bf528SMauro Carvalho Chehab {
37899a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37909a0bf528SMauro Carvalho Chehab 	u32 n, s, exp;
37919a0bf528SMauro Carvalho Chehab 	u16 val;
37929a0bf528SMauro Carvalho Chehab 
37939a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
37949a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 542);
37959a0bf528SMauro Carvalho Chehab 	else
37969a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 544);
37979a0bf528SMauro Carvalho Chehab 	n = (val >> 6) & 0xff;
37989a0bf528SMauro Carvalho Chehab 	exp = (val & 0x3f);
37999a0bf528SMauro Carvalho Chehab 	if ((exp & 0x20) != 0)
38009a0bf528SMauro Carvalho Chehab 		exp -= 0x40;
38019a0bf528SMauro Carvalho Chehab 	n <<= exp+16;
38029a0bf528SMauro Carvalho Chehab 
38039a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
38049a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 543);
38059a0bf528SMauro Carvalho Chehab 	else
38069a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 545);
38079a0bf528SMauro Carvalho Chehab 	s = (val >> 6) & 0xff;
38089a0bf528SMauro Carvalho Chehab 	exp = (val & 0x3f);
38099a0bf528SMauro Carvalho Chehab 	if ((exp & 0x20) != 0)
38109a0bf528SMauro Carvalho Chehab 		exp -= 0x40;
38119a0bf528SMauro Carvalho Chehab 	s <<= exp+16;
38129a0bf528SMauro Carvalho Chehab 
38139a0bf528SMauro Carvalho Chehab 	if (n > 0) {
38149a0bf528SMauro Carvalho Chehab 		u32 t = (s/n) << 16;
38159a0bf528SMauro Carvalho Chehab 		return t + ((s << 16) - n*t) / n;
38169a0bf528SMauro Carvalho Chehab 	}
38179a0bf528SMauro Carvalho Chehab 	return 0xffffffff;
38189a0bf528SMauro Carvalho Chehab }
38199a0bf528SMauro Carvalho Chehab 
38209a0bf528SMauro Carvalho Chehab static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
38219a0bf528SMauro Carvalho Chehab {
38229a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
38239a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
38249a0bf528SMauro Carvalho Chehab 	u32 snr_master;
38259a0bf528SMauro Carvalho Chehab 
38269a0bf528SMauro Carvalho Chehab 	snr_master = dib8000_get_snr(fe);
38279a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
38289a0bf528SMauro Carvalho Chehab 		snr_master += dib8000_get_snr(state->fe[index_frontend]);
38299a0bf528SMauro Carvalho Chehab 
38309a0bf528SMauro Carvalho Chehab 	if ((snr_master >> 16) != 0) {
38319a0bf528SMauro Carvalho Chehab 		snr_master = 10*intlog10(snr_master>>16);
38329a0bf528SMauro Carvalho Chehab 		*snr = snr_master / ((1 << 24) / 10);
38339a0bf528SMauro Carvalho Chehab 	}
38349a0bf528SMauro Carvalho Chehab 	else
38359a0bf528SMauro Carvalho Chehab 		*snr = 0;
38369a0bf528SMauro Carvalho Chehab 
38379a0bf528SMauro Carvalho Chehab 	return 0;
38389a0bf528SMauro Carvalho Chehab }
38399a0bf528SMauro Carvalho Chehab 
38406ef06e78SMauro Carvalho Chehab struct per_layer_regs {
38416ef06e78SMauro Carvalho Chehab 	u16 lock, ber, per;
38426ef06e78SMauro Carvalho Chehab };
38436ef06e78SMauro Carvalho Chehab 
38446ef06e78SMauro Carvalho Chehab static const struct per_layer_regs per_layer_regs[] = {
38456ef06e78SMauro Carvalho Chehab 	{ 554, 560, 562 },
38466ef06e78SMauro Carvalho Chehab 	{ 555, 576, 578 },
38476ef06e78SMauro Carvalho Chehab 	{ 556, 581, 583 },
38486ef06e78SMauro Carvalho Chehab };
38496ef06e78SMauro Carvalho Chehab 
385042ff76bdSMauro Carvalho Chehab struct linear_segments {
385142ff76bdSMauro Carvalho Chehab 	unsigned x;
385242ff76bdSMauro Carvalho Chehab 	signed y;
385342ff76bdSMauro Carvalho Chehab };
385442ff76bdSMauro Carvalho Chehab 
385542ff76bdSMauro Carvalho Chehab /*
385642ff76bdSMauro Carvalho Chehab  * Table to estimate signal strength in dBm.
385742ff76bdSMauro Carvalho Chehab  * This table was empirically determinated by measuring the signal
385842ff76bdSMauro Carvalho Chehab  * strength generated by a DTA-2111 RF generator directly connected into
385942ff76bdSMauro Carvalho Chehab  * a dib8076 device (a PixelView PV-D231U stick), using a good quality
386042ff76bdSMauro Carvalho Chehab  * 3 meters RC6 cable and good RC6 connectors.
386142ff76bdSMauro Carvalho Chehab  * The real value can actually be different on other devices, depending
386242ff76bdSMauro Carvalho Chehab  * on several factors, like if LNA is enabled or not, if diversity is
386342ff76bdSMauro Carvalho Chehab  * enabled, type of connectors, etc.
386442ff76bdSMauro Carvalho Chehab  * Yet, it is better to use this measure in dB than a random non-linear
386542ff76bdSMauro Carvalho Chehab  * percentage value, especially for antenna adjustments.
386642ff76bdSMauro Carvalho Chehab  * On my tests, the precision of the measure using this table is about
386742ff76bdSMauro Carvalho Chehab  * 0.5 dB, with sounds reasonable enough.
386842ff76bdSMauro Carvalho Chehab  */
386942ff76bdSMauro Carvalho Chehab static struct linear_segments strength_to_db_table[] = {
387042ff76bdSMauro Carvalho Chehab 	{ 55953, 108500 },	/* -22.5 dBm */
387142ff76bdSMauro Carvalho Chehab 	{ 55394, 108000 },
387242ff76bdSMauro Carvalho Chehab 	{ 53834, 107000 },
387342ff76bdSMauro Carvalho Chehab 	{ 52863, 106000 },
387442ff76bdSMauro Carvalho Chehab 	{ 52239, 105000 },
387542ff76bdSMauro Carvalho Chehab 	{ 52012, 104000 },
387642ff76bdSMauro Carvalho Chehab 	{ 51803, 103000 },
387742ff76bdSMauro Carvalho Chehab 	{ 51566, 102000 },
387842ff76bdSMauro Carvalho Chehab 	{ 51356, 101000 },
387942ff76bdSMauro Carvalho Chehab 	{ 51112, 100000 },
388042ff76bdSMauro Carvalho Chehab 	{ 50869,  99000 },
388142ff76bdSMauro Carvalho Chehab 	{ 50600,  98000 },
388242ff76bdSMauro Carvalho Chehab 	{ 50363,  97000 },
388342ff76bdSMauro Carvalho Chehab 	{ 50117,  96000 },	/* -35 dBm */
388442ff76bdSMauro Carvalho Chehab 	{ 49889,  95000 },
388542ff76bdSMauro Carvalho Chehab 	{ 49680,  94000 },
388642ff76bdSMauro Carvalho Chehab 	{ 49493,  93000 },
388742ff76bdSMauro Carvalho Chehab 	{ 49302,  92000 },
388842ff76bdSMauro Carvalho Chehab 	{ 48929,  91000 },
388942ff76bdSMauro Carvalho Chehab 	{ 48416,  90000 },
389042ff76bdSMauro Carvalho Chehab 	{ 48035,  89000 },
389142ff76bdSMauro Carvalho Chehab 	{ 47593,  88000 },
389242ff76bdSMauro Carvalho Chehab 	{ 47282,  87000 },
389342ff76bdSMauro Carvalho Chehab 	{ 46953,  86000 },
389442ff76bdSMauro Carvalho Chehab 	{ 46698,  85000 },
389542ff76bdSMauro Carvalho Chehab 	{ 45617,  84000 },
389642ff76bdSMauro Carvalho Chehab 	{ 44773,  83000 },
389742ff76bdSMauro Carvalho Chehab 	{ 43845,  82000 },
389842ff76bdSMauro Carvalho Chehab 	{ 43020,  81000 },
389942ff76bdSMauro Carvalho Chehab 	{ 42010,  80000 },	/* -51 dBm */
390042ff76bdSMauro Carvalho Chehab 	{     0,      0 },
390142ff76bdSMauro Carvalho Chehab };
390242ff76bdSMauro Carvalho Chehab 
390342ff76bdSMauro Carvalho Chehab static u32 interpolate_value(u32 value, struct linear_segments *segments,
390442ff76bdSMauro Carvalho Chehab 			     unsigned len)
390542ff76bdSMauro Carvalho Chehab {
390642ff76bdSMauro Carvalho Chehab 	u64 tmp64;
390742ff76bdSMauro Carvalho Chehab 	u32 dx;
390842ff76bdSMauro Carvalho Chehab 	s32 dy;
390942ff76bdSMauro Carvalho Chehab 	int i, ret;
391042ff76bdSMauro Carvalho Chehab 
391142ff76bdSMauro Carvalho Chehab 	if (value >= segments[0].x)
391242ff76bdSMauro Carvalho Chehab 		return segments[0].y;
391342ff76bdSMauro Carvalho Chehab 	if (value < segments[len-1].x)
391442ff76bdSMauro Carvalho Chehab 		return segments[len-1].y;
391542ff76bdSMauro Carvalho Chehab 
391642ff76bdSMauro Carvalho Chehab 	for (i = 1; i < len - 1; i++) {
391742ff76bdSMauro Carvalho Chehab 		/* If value is identical, no need to interpolate */
391842ff76bdSMauro Carvalho Chehab 		if (value == segments[i].x)
391942ff76bdSMauro Carvalho Chehab 			return segments[i].y;
392042ff76bdSMauro Carvalho Chehab 		if (value > segments[i].x)
392142ff76bdSMauro Carvalho Chehab 			break;
392242ff76bdSMauro Carvalho Chehab 	}
392342ff76bdSMauro Carvalho Chehab 
392442ff76bdSMauro Carvalho Chehab 	/* Linear interpolation between the two (x,y) points */
392542ff76bdSMauro Carvalho Chehab 	dy = segments[i - 1].y - segments[i].y;
392642ff76bdSMauro Carvalho Chehab 	dx = segments[i - 1].x - segments[i].x;
392742ff76bdSMauro Carvalho Chehab 
392842ff76bdSMauro Carvalho Chehab 	tmp64 = value - segments[i].x;
392942ff76bdSMauro Carvalho Chehab 	tmp64 *= dy;
393042ff76bdSMauro Carvalho Chehab 	do_div(tmp64, dx);
393142ff76bdSMauro Carvalho Chehab 	ret = segments[i].y + tmp64;
393242ff76bdSMauro Carvalho Chehab 
393342ff76bdSMauro Carvalho Chehab 	return ret;
393442ff76bdSMauro Carvalho Chehab }
393542ff76bdSMauro Carvalho Chehab 
3936704f01bbSMauro Carvalho Chehab static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer)
3937704f01bbSMauro Carvalho Chehab {
3938704f01bbSMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
3939704f01bbSMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3940704f01bbSMauro Carvalho Chehab 	int ini_layer, end_layer, i;
39414bf48150SMauro Carvalho Chehab 	u64 time_us, tmp64;
3942704f01bbSMauro Carvalho Chehab 	u32 tmp, denom;
3943e4a3bc1cSMauro Carvalho Chehab 	int guard, rate_num, rate_denum = 1, bits_per_symbol, nsegs;
3944e4a3bc1cSMauro Carvalho Chehab 	int interleaving = 0, fft_div;
3945704f01bbSMauro Carvalho Chehab 
3946704f01bbSMauro Carvalho Chehab 	if (layer >= 0) {
3947704f01bbSMauro Carvalho Chehab 		ini_layer = layer;
3948704f01bbSMauro Carvalho Chehab 		end_layer = layer + 1;
3949704f01bbSMauro Carvalho Chehab 	} else {
3950704f01bbSMauro Carvalho Chehab 		ini_layer = 0;
3951704f01bbSMauro Carvalho Chehab 		end_layer = 3;
3952704f01bbSMauro Carvalho Chehab 	}
3953704f01bbSMauro Carvalho Chehab 
3954704f01bbSMauro Carvalho Chehab 	switch (c->guard_interval) {
3955704f01bbSMauro Carvalho Chehab 	case GUARD_INTERVAL_1_4:
3956704f01bbSMauro Carvalho Chehab 		guard = 4;
3957704f01bbSMauro Carvalho Chehab 		break;
3958704f01bbSMauro Carvalho Chehab 	case GUARD_INTERVAL_1_8:
3959704f01bbSMauro Carvalho Chehab 		guard = 8;
3960704f01bbSMauro Carvalho Chehab 		break;
3961704f01bbSMauro Carvalho Chehab 	case GUARD_INTERVAL_1_16:
3962704f01bbSMauro Carvalho Chehab 		guard = 16;
3963704f01bbSMauro Carvalho Chehab 		break;
3964704f01bbSMauro Carvalho Chehab 	default:
3965704f01bbSMauro Carvalho Chehab 	case GUARD_INTERVAL_1_32:
3966704f01bbSMauro Carvalho Chehab 		guard = 32;
3967704f01bbSMauro Carvalho Chehab 		break;
3968704f01bbSMauro Carvalho Chehab 	}
3969704f01bbSMauro Carvalho Chehab 
3970704f01bbSMauro Carvalho Chehab 	switch (c->transmission_mode) {
3971704f01bbSMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
3972704f01bbSMauro Carvalho Chehab 		fft_div = 4;
3973704f01bbSMauro Carvalho Chehab 		break;
3974704f01bbSMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
3975704f01bbSMauro Carvalho Chehab 		fft_div = 2;
3976704f01bbSMauro Carvalho Chehab 		break;
3977704f01bbSMauro Carvalho Chehab 	default:
3978704f01bbSMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
3979704f01bbSMauro Carvalho Chehab 		fft_div = 1;
3980704f01bbSMauro Carvalho Chehab 		break;
3981704f01bbSMauro Carvalho Chehab 	}
3982704f01bbSMauro Carvalho Chehab 
3983704f01bbSMauro Carvalho Chehab 	denom = 0;
3984704f01bbSMauro Carvalho Chehab 	for (i = ini_layer; i < end_layer; i++) {
3985704f01bbSMauro Carvalho Chehab 		nsegs = c->layer[i].segment_count;
3986704f01bbSMauro Carvalho Chehab 		if (nsegs == 0 || nsegs > 13)
3987704f01bbSMauro Carvalho Chehab 			continue;
3988704f01bbSMauro Carvalho Chehab 
3989704f01bbSMauro Carvalho Chehab 		switch (c->layer[i].modulation) {
3990704f01bbSMauro Carvalho Chehab 		case DQPSK:
3991704f01bbSMauro Carvalho Chehab 		case QPSK:
3992704f01bbSMauro Carvalho Chehab 			bits_per_symbol = 2;
3993704f01bbSMauro Carvalho Chehab 			break;
3994704f01bbSMauro Carvalho Chehab 		case QAM_16:
3995704f01bbSMauro Carvalho Chehab 			bits_per_symbol = 4;
3996704f01bbSMauro Carvalho Chehab 			break;
3997704f01bbSMauro Carvalho Chehab 		default:
3998704f01bbSMauro Carvalho Chehab 		case QAM_64:
3999704f01bbSMauro Carvalho Chehab 			bits_per_symbol = 6;
4000704f01bbSMauro Carvalho Chehab 			break;
4001704f01bbSMauro Carvalho Chehab 		}
4002704f01bbSMauro Carvalho Chehab 
4003704f01bbSMauro Carvalho Chehab 		switch (c->layer[i].fec) {
4004704f01bbSMauro Carvalho Chehab 		case FEC_1_2:
4005704f01bbSMauro Carvalho Chehab 			rate_num = 1;
4006704f01bbSMauro Carvalho Chehab 			rate_denum = 2;
4007704f01bbSMauro Carvalho Chehab 			break;
4008704f01bbSMauro Carvalho Chehab 		case FEC_2_3:
4009704f01bbSMauro Carvalho Chehab 			rate_num = 2;
4010704f01bbSMauro Carvalho Chehab 			rate_denum = 3;
4011704f01bbSMauro Carvalho Chehab 			break;
4012704f01bbSMauro Carvalho Chehab 		case FEC_3_4:
4013704f01bbSMauro Carvalho Chehab 			rate_num = 3;
4014704f01bbSMauro Carvalho Chehab 			rate_denum = 4;
4015704f01bbSMauro Carvalho Chehab 			break;
4016704f01bbSMauro Carvalho Chehab 		case FEC_5_6:
4017704f01bbSMauro Carvalho Chehab 			rate_num = 5;
4018704f01bbSMauro Carvalho Chehab 			rate_denum = 6;
4019704f01bbSMauro Carvalho Chehab 			break;
4020704f01bbSMauro Carvalho Chehab 		default:
4021704f01bbSMauro Carvalho Chehab 		case FEC_7_8:
4022704f01bbSMauro Carvalho Chehab 			rate_num = 7;
4023704f01bbSMauro Carvalho Chehab 			rate_denum = 8;
4024704f01bbSMauro Carvalho Chehab 			break;
4025704f01bbSMauro Carvalho Chehab 		}
4026704f01bbSMauro Carvalho Chehab 
4027704f01bbSMauro Carvalho Chehab 		interleaving = c->layer[i].interleaving;
4028704f01bbSMauro Carvalho Chehab 
4029704f01bbSMauro Carvalho Chehab 		denom += bits_per_symbol * rate_num * fft_div * nsegs * 384;
4030704f01bbSMauro Carvalho Chehab 	}
4031704f01bbSMauro Carvalho Chehab 
4032704f01bbSMauro Carvalho Chehab 	/* If all goes wrong, wait for 1s for the next stats */
4033704f01bbSMauro Carvalho Chehab 	if (!denom)
4034704f01bbSMauro Carvalho Chehab 		return 0;
4035704f01bbSMauro Carvalho Chehab 
4036704f01bbSMauro Carvalho Chehab 	/* Estimate the period for the total bit rate */
4037704f01bbSMauro Carvalho Chehab 	time_us = rate_denum * (1008 * 1562500L);
40384bf48150SMauro Carvalho Chehab 	tmp64 = time_us;
40394bf48150SMauro Carvalho Chehab 	do_div(tmp64, guard);
40404bf48150SMauro Carvalho Chehab 	time_us = time_us + tmp64;
4041704f01bbSMauro Carvalho Chehab 	time_us += denom / 2;
4042704f01bbSMauro Carvalho Chehab 	do_div(time_us, denom);
4043704f01bbSMauro Carvalho Chehab 
4044704f01bbSMauro Carvalho Chehab 	tmp = 1008 * 96 * interleaving;
4045704f01bbSMauro Carvalho Chehab 	time_us += tmp + tmp / guard;
4046704f01bbSMauro Carvalho Chehab 
4047704f01bbSMauro Carvalho Chehab 	return time_us;
4048704f01bbSMauro Carvalho Chehab }
4049704f01bbSMauro Carvalho Chehab 
40506ef06e78SMauro Carvalho Chehab static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
40516ef06e78SMauro Carvalho Chehab {
40526ef06e78SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
40536ef06e78SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
4054704f01bbSMauro Carvalho Chehab 	int i;
40550400c535SMauro Carvalho Chehab 	int show_per_stats = 0;
40560400c535SMauro Carvalho Chehab 	u32 time_us = 0, snr, val;
40570400c535SMauro Carvalho Chehab 	u64 blocks;
405842ff76bdSMauro Carvalho Chehab 	s32 db;
40596ef06e78SMauro Carvalho Chehab 	u16 strength;
40606ef06e78SMauro Carvalho Chehab 
40616ef06e78SMauro Carvalho Chehab 	/* Get Signal strength */
40626ef06e78SMauro Carvalho Chehab 	dib8000_read_signal_strength(fe, &strength);
406342ff76bdSMauro Carvalho Chehab 	val = strength;
406442ff76bdSMauro Carvalho Chehab 	db = interpolate_value(val,
406542ff76bdSMauro Carvalho Chehab 			       strength_to_db_table,
406642ff76bdSMauro Carvalho Chehab 			       ARRAY_SIZE(strength_to_db_table)) - 131000;
406742ff76bdSMauro Carvalho Chehab 	c->strength.stat[0].svalue = db;
40686ef06e78SMauro Carvalho Chehab 
4069704f01bbSMauro Carvalho Chehab 	/* UCB/BER/CNR measures require lock */
4070704f01bbSMauro Carvalho Chehab 	if (!(stat & FE_HAS_LOCK)) {
4071704f01bbSMauro Carvalho Chehab 		c->cnr.len = 1;
40720400c535SMauro Carvalho Chehab 		c->block_count.len = 1;
4073704f01bbSMauro Carvalho Chehab 		c->block_error.len = 1;
4074704f01bbSMauro Carvalho Chehab 		c->post_bit_error.len = 1;
4075704f01bbSMauro Carvalho Chehab 		c->post_bit_count.len = 1;
4076704f01bbSMauro Carvalho Chehab 		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4077704f01bbSMauro Carvalho Chehab 		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4078704f01bbSMauro Carvalho Chehab 		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4079704f01bbSMauro Carvalho Chehab 		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
40800400c535SMauro Carvalho Chehab 		c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
40816ef06e78SMauro Carvalho Chehab 		return 0;
4082704f01bbSMauro Carvalho Chehab 	}
4083704f01bbSMauro Carvalho Chehab 
4084704f01bbSMauro Carvalho Chehab 	/* Check if time for stats was elapsed */
40850400c535SMauro Carvalho Chehab 	if (time_after(jiffies, state->per_jiffies_stats)) {
40860400c535SMauro Carvalho Chehab 		state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
40876ef06e78SMauro Carvalho Chehab 
40886ef06e78SMauro Carvalho Chehab 		/* Get SNR */
40896ef06e78SMauro Carvalho Chehab 		snr = dib8000_get_snr(fe);
40906ef06e78SMauro Carvalho Chehab 		for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) {
40916ef06e78SMauro Carvalho Chehab 			if (state->fe[i])
40926ef06e78SMauro Carvalho Chehab 				snr += dib8000_get_snr(state->fe[i]);
40936ef06e78SMauro Carvalho Chehab 		}
40946ef06e78SMauro Carvalho Chehab 		snr = snr >> 16;
40956ef06e78SMauro Carvalho Chehab 
40966ef06e78SMauro Carvalho Chehab 		if (snr) {
40976ef06e78SMauro Carvalho Chehab 			snr = 10 * intlog10(snr);
40986ef06e78SMauro Carvalho Chehab 			snr = (1000L * snr) >> 24;
40996ef06e78SMauro Carvalho Chehab 		} else {
41006ef06e78SMauro Carvalho Chehab 			snr = 0;
41016ef06e78SMauro Carvalho Chehab 		}
41026ef06e78SMauro Carvalho Chehab 		c->cnr.stat[0].svalue = snr;
41036ef06e78SMauro Carvalho Chehab 		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
41046ef06e78SMauro Carvalho Chehab 
41050400c535SMauro Carvalho Chehab 		/* Get UCB measures */
41060400c535SMauro Carvalho Chehab 		dib8000_read_unc_blocks(fe, &val);
41070400c535SMauro Carvalho Chehab 		if (val < state->init_ucb)
41085dc8526bSMauro Carvalho Chehab 			state->init_ucb += 0x100000000LL;
41090400c535SMauro Carvalho Chehab 
41100400c535SMauro Carvalho Chehab 		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
41110400c535SMauro Carvalho Chehab 		c->block_error.stat[0].uvalue = val + state->init_ucb;
41120400c535SMauro Carvalho Chehab 
41130400c535SMauro Carvalho Chehab 		/* Estimate the number of packets based on bitrate */
41140400c535SMauro Carvalho Chehab 		if (!time_us)
41150400c535SMauro Carvalho Chehab 			time_us = dib8000_get_time_us(fe, -1);
41160400c535SMauro Carvalho Chehab 
41170400c535SMauro Carvalho Chehab 		if (time_us) {
41185dc8526bSMauro Carvalho Chehab 			blocks = 1250000ULL * 1000000ULL;
41190400c535SMauro Carvalho Chehab 			do_div(blocks, time_us * 8 * 204);
41200400c535SMauro Carvalho Chehab 			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
41210400c535SMauro Carvalho Chehab 			c->block_count.stat[0].uvalue += blocks;
41220400c535SMauro Carvalho Chehab 		}
41230400c535SMauro Carvalho Chehab 
41240400c535SMauro Carvalho Chehab 		show_per_stats = 1;
41250400c535SMauro Carvalho Chehab 	}
41260400c535SMauro Carvalho Chehab 
41270400c535SMauro Carvalho Chehab 	/* Get post-BER measures */
41280400c535SMauro Carvalho Chehab 	if (time_after(jiffies, state->ber_jiffies_stats)) {
41290400c535SMauro Carvalho Chehab 		time_us = dib8000_get_time_us(fe, -1);
41300400c535SMauro Carvalho Chehab 		state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
41310400c535SMauro Carvalho Chehab 
41320400c535SMauro Carvalho Chehab 		dprintk("Next all layers stats available in %u us.", time_us);
41336ef06e78SMauro Carvalho Chehab 
41346ef06e78SMauro Carvalho Chehab 		dib8000_read_ber(fe, &val);
41356ef06e78SMauro Carvalho Chehab 		c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
41366ef06e78SMauro Carvalho Chehab 		c->post_bit_error.stat[0].uvalue += val;
41376ef06e78SMauro Carvalho Chehab 
41386ef06e78SMauro Carvalho Chehab 		c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
41396ef06e78SMauro Carvalho Chehab 		c->post_bit_count.stat[0].uvalue += 100000000;
4140704f01bbSMauro Carvalho Chehab 	}
41416ef06e78SMauro Carvalho Chehab 
41426ef06e78SMauro Carvalho Chehab 	if (state->revision < 0x8002)
41436ef06e78SMauro Carvalho Chehab 		return 0;
41446ef06e78SMauro Carvalho Chehab 
41456ef06e78SMauro Carvalho Chehab 	c->block_error.len = 4;
41466ef06e78SMauro Carvalho Chehab 	c->post_bit_error.len = 4;
41476ef06e78SMauro Carvalho Chehab 	c->post_bit_count.len = 4;
41486ef06e78SMauro Carvalho Chehab 
41496ef06e78SMauro Carvalho Chehab 	for (i = 0; i < 3; i++) {
41500400c535SMauro Carvalho Chehab 		unsigned nsegs = c->layer[i].segment_count;
41510400c535SMauro Carvalho Chehab 
41520400c535SMauro Carvalho Chehab 		if (nsegs == 0 || nsegs > 13)
4153704f01bbSMauro Carvalho Chehab 			continue;
4154704f01bbSMauro Carvalho Chehab 
41550400c535SMauro Carvalho Chehab 		time_us = 0;
41560400c535SMauro Carvalho Chehab 
41570400c535SMauro Carvalho Chehab 		if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) {
41580400c535SMauro Carvalho Chehab 			time_us = dib8000_get_time_us(fe, i);
41590400c535SMauro Carvalho Chehab 
41600400c535SMauro Carvalho Chehab 			state->ber_jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
4161704f01bbSMauro Carvalho Chehab 			dprintk("Next layer %c  stats will be available in %u us\n",
4162704f01bbSMauro Carvalho Chehab 				'A' + i, time_us);
4163704f01bbSMauro Carvalho Chehab 
41646ef06e78SMauro Carvalho Chehab 			val = dib8000_read_word(state, per_layer_regs[i].ber);
41656ef06e78SMauro Carvalho Chehab 			c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
41666ef06e78SMauro Carvalho Chehab 			c->post_bit_error.stat[1 + i].uvalue += val;
41676ef06e78SMauro Carvalho Chehab 
41686ef06e78SMauro Carvalho Chehab 			c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
41696ef06e78SMauro Carvalho Chehab 			c->post_bit_count.stat[1 + i].uvalue += 100000000;
41700400c535SMauro Carvalho Chehab 		}
41716ef06e78SMauro Carvalho Chehab 
41720400c535SMauro Carvalho Chehab 		if (show_per_stats) {
41736ef06e78SMauro Carvalho Chehab 			val = dib8000_read_word(state, per_layer_regs[i].per);
41746ef06e78SMauro Carvalho Chehab 
41756ef06e78SMauro Carvalho Chehab 			c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
41766ef06e78SMauro Carvalho Chehab 			c->block_error.stat[1 + i].uvalue += val;
41770400c535SMauro Carvalho Chehab 
41780400c535SMauro Carvalho Chehab 			if (!time_us)
41790400c535SMauro Carvalho Chehab 				time_us = dib8000_get_time_us(fe, i);
41800400c535SMauro Carvalho Chehab 			if (time_us) {
41815dc8526bSMauro Carvalho Chehab 				blocks = 1250000ULL * 1000000ULL;
41820400c535SMauro Carvalho Chehab 				do_div(blocks, time_us * 8 * 204);
41830400c535SMauro Carvalho Chehab 				c->block_count.stat[0].scale = FE_SCALE_COUNTER;
41840400c535SMauro Carvalho Chehab 				c->block_count.stat[0].uvalue += blocks;
41850400c535SMauro Carvalho Chehab 			}
41860400c535SMauro Carvalho Chehab 		}
41876ef06e78SMauro Carvalho Chehab 	}
41886ef06e78SMauro Carvalho Chehab 	return 0;
41896ef06e78SMauro Carvalho Chehab }
41906ef06e78SMauro Carvalho Chehab 
4191d44913c1SMauro Carvalho Chehab static int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
41929a0bf528SMauro Carvalho Chehab {
41939a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
41949a0bf528SMauro Carvalho Chehab 	u8 index_frontend = 1;
41959a0bf528SMauro Carvalho Chehab 
41969a0bf528SMauro Carvalho Chehab 	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
41979a0bf528SMauro Carvalho Chehab 		index_frontend++;
41989a0bf528SMauro Carvalho Chehab 	if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
41999a0bf528SMauro Carvalho Chehab 		dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
42009a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend] = fe_slave;
42019a0bf528SMauro Carvalho Chehab 		return 0;
42029a0bf528SMauro Carvalho Chehab 	}
42039a0bf528SMauro Carvalho Chehab 
42049a0bf528SMauro Carvalho Chehab 	dprintk("too many slave frontend");
42059a0bf528SMauro Carvalho Chehab 	return -ENOMEM;
42069a0bf528SMauro Carvalho Chehab }
42079a0bf528SMauro Carvalho Chehab 
4208d44913c1SMauro Carvalho Chehab static int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
42099a0bf528SMauro Carvalho Chehab {
42109a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
42119a0bf528SMauro Carvalho Chehab 	u8 index_frontend = 1;
42129a0bf528SMauro Carvalho Chehab 
42139a0bf528SMauro Carvalho Chehab 	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
42149a0bf528SMauro Carvalho Chehab 		index_frontend++;
42159a0bf528SMauro Carvalho Chehab 	if (index_frontend != 1) {
42169a0bf528SMauro Carvalho Chehab 		dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1);
42179a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend] = NULL;
42189a0bf528SMauro Carvalho Chehab 		return 0;
42199a0bf528SMauro Carvalho Chehab 	}
42209a0bf528SMauro Carvalho Chehab 
42219a0bf528SMauro Carvalho Chehab 	dprintk("no frontend to be removed");
42229a0bf528SMauro Carvalho Chehab 	return -ENODEV;
42239a0bf528SMauro Carvalho Chehab }
42249a0bf528SMauro Carvalho Chehab 
4225d44913c1SMauro Carvalho Chehab static struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
42269a0bf528SMauro Carvalho Chehab {
42279a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
42289a0bf528SMauro Carvalho Chehab 
42299a0bf528SMauro Carvalho Chehab 	if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
42309a0bf528SMauro Carvalho Chehab 		return NULL;
42319a0bf528SMauro Carvalho Chehab 	return state->fe[slave_index];
42329a0bf528SMauro Carvalho Chehab }
42339a0bf528SMauro Carvalho Chehab 
4234d44913c1SMauro Carvalho Chehab static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
42359a0bf528SMauro Carvalho Chehab 		u8 default_addr, u8 first_addr, u8 is_dib8096p)
42369a0bf528SMauro Carvalho Chehab {
42379a0bf528SMauro Carvalho Chehab 	int k = 0, ret = 0;
42389a0bf528SMauro Carvalho Chehab 	u8 new_addr = 0;
42399a0bf528SMauro Carvalho Chehab 	struct i2c_device client = {.adap = host };
42409a0bf528SMauro Carvalho Chehab 
42419a0bf528SMauro Carvalho Chehab 	client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
42429a0bf528SMauro Carvalho Chehab 	if (!client.i2c_write_buffer) {
42439a0bf528SMauro Carvalho Chehab 		dprintk("%s: not enough memory", __func__);
42449a0bf528SMauro Carvalho Chehab 		return -ENOMEM;
42459a0bf528SMauro Carvalho Chehab 	}
42469a0bf528SMauro Carvalho Chehab 	client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
42479a0bf528SMauro Carvalho Chehab 	if (!client.i2c_read_buffer) {
42489a0bf528SMauro Carvalho Chehab 		dprintk("%s: not enough memory", __func__);
42499a0bf528SMauro Carvalho Chehab 		ret = -ENOMEM;
42509a0bf528SMauro Carvalho Chehab 		goto error_memory_read;
42519a0bf528SMauro Carvalho Chehab 	}
42529a0bf528SMauro Carvalho Chehab 	client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
42539a0bf528SMauro Carvalho Chehab 	if (!client.i2c_buffer_lock) {
42549a0bf528SMauro Carvalho Chehab 		dprintk("%s: not enough memory", __func__);
42559a0bf528SMauro Carvalho Chehab 		ret = -ENOMEM;
42569a0bf528SMauro Carvalho Chehab 		goto error_memory_lock;
42579a0bf528SMauro Carvalho Chehab 	}
42589a0bf528SMauro Carvalho Chehab 	mutex_init(client.i2c_buffer_lock);
42599a0bf528SMauro Carvalho Chehab 
42609a0bf528SMauro Carvalho Chehab 	for (k = no_of_demods - 1; k >= 0; k--) {
42619a0bf528SMauro Carvalho Chehab 		/* designated i2c address */
42629a0bf528SMauro Carvalho Chehab 		new_addr = first_addr + (k << 1);
42639a0bf528SMauro Carvalho Chehab 
42649a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
42659a0bf528SMauro Carvalho Chehab 		if (!is_dib8096p)
42669a0bf528SMauro Carvalho Chehab 			dib8000_i2c_write16(&client, 1287, 0x0003);	/* sram lead in, rdy */
42679a0bf528SMauro Carvalho Chehab 		if (dib8000_identify(&client) == 0) {
42689a0bf528SMauro Carvalho Chehab 			/* sram lead in, rdy */
42699a0bf528SMauro Carvalho Chehab 			if (!is_dib8096p)
42709a0bf528SMauro Carvalho Chehab 				dib8000_i2c_write16(&client, 1287, 0x0003);
42719a0bf528SMauro Carvalho Chehab 			client.addr = default_addr;
42729a0bf528SMauro Carvalho Chehab 			if (dib8000_identify(&client) == 0) {
42739a0bf528SMauro Carvalho Chehab 				dprintk("#%d: not identified", k);
42749a0bf528SMauro Carvalho Chehab 				ret  = -EINVAL;
42759a0bf528SMauro Carvalho Chehab 				goto error;
42769a0bf528SMauro Carvalho Chehab 			}
42779a0bf528SMauro Carvalho Chehab 		}
42789a0bf528SMauro Carvalho Chehab 
42799a0bf528SMauro Carvalho Chehab 		/* start diversity to pull_down div_str - just for i2c-enumeration */
42809a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
42819a0bf528SMauro Carvalho Chehab 
42829a0bf528SMauro Carvalho Chehab 		/* set new i2c address and force divstart */
42839a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
42849a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
42859a0bf528SMauro Carvalho Chehab 		dib8000_identify(&client);
42869a0bf528SMauro Carvalho Chehab 
42879a0bf528SMauro Carvalho Chehab 		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
42889a0bf528SMauro Carvalho Chehab 	}
42899a0bf528SMauro Carvalho Chehab 
42909a0bf528SMauro Carvalho Chehab 	for (k = 0; k < no_of_demods; k++) {
42919a0bf528SMauro Carvalho Chehab 		new_addr = first_addr | (k << 1);
42929a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
42939a0bf528SMauro Carvalho Chehab 
42949a0bf528SMauro Carvalho Chehab 		// unforce divstr
42959a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1285, new_addr << 2);
42969a0bf528SMauro Carvalho Chehab 
42979a0bf528SMauro Carvalho Chehab 		/* deactivate div - it was just for i2c-enumeration */
42989a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1286, 0);
42999a0bf528SMauro Carvalho Chehab 	}
43009a0bf528SMauro Carvalho Chehab 
43019a0bf528SMauro Carvalho Chehab error:
43029a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_buffer_lock);
43039a0bf528SMauro Carvalho Chehab error_memory_lock:
43049a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_read_buffer);
43059a0bf528SMauro Carvalho Chehab error_memory_read:
43069a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_write_buffer);
43079a0bf528SMauro Carvalho Chehab 
43089a0bf528SMauro Carvalho Chehab 	return ret;
43099a0bf528SMauro Carvalho Chehab }
43109a0bf528SMauro Carvalho Chehab 
43119a0bf528SMauro Carvalho Chehab static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
43129a0bf528SMauro Carvalho Chehab {
43139a0bf528SMauro Carvalho Chehab 	tune->min_delay_ms = 1000;
43149a0bf528SMauro Carvalho Chehab 	tune->step_size = 0;
43159a0bf528SMauro Carvalho Chehab 	tune->max_drift = 0;
43169a0bf528SMauro Carvalho Chehab 	return 0;
43179a0bf528SMauro Carvalho Chehab }
43189a0bf528SMauro Carvalho Chehab 
43199a0bf528SMauro Carvalho Chehab static void dib8000_release(struct dvb_frontend *fe)
43209a0bf528SMauro Carvalho Chehab {
43219a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
43229a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
43239a0bf528SMauro Carvalho Chehab 
43249a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
43259a0bf528SMauro Carvalho Chehab 		dvb_frontend_detach(st->fe[index_frontend]);
43269a0bf528SMauro Carvalho Chehab 
43279a0bf528SMauro Carvalho Chehab 	dibx000_exit_i2c_master(&st->i2c_master);
43289a0bf528SMauro Carvalho Chehab 	i2c_del_adapter(&st->dib8096p_tuner_adap);
43299a0bf528SMauro Carvalho Chehab 	kfree(st->fe[0]);
43309a0bf528SMauro Carvalho Chehab 	kfree(st);
43319a0bf528SMauro Carvalho Chehab }
43329a0bf528SMauro Carvalho Chehab 
4333d44913c1SMauro Carvalho Chehab static struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
43349a0bf528SMauro Carvalho Chehab {
43359a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
43369a0bf528SMauro Carvalho Chehab 	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
43379a0bf528SMauro Carvalho Chehab }
43389a0bf528SMauro Carvalho Chehab 
4339d44913c1SMauro Carvalho Chehab static int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
43409a0bf528SMauro Carvalho Chehab {
43419a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
43429a0bf528SMauro Carvalho Chehab 	u16 val = dib8000_read_word(st, 299) & 0xffef;
43439a0bf528SMauro Carvalho Chehab 	val |= (onoff & 0x1) << 4;
43449a0bf528SMauro Carvalho Chehab 
43459a0bf528SMauro Carvalho Chehab 	dprintk("pid filter enabled %d", onoff);
43469a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(st, 299, val);
43479a0bf528SMauro Carvalho Chehab }
43489a0bf528SMauro Carvalho Chehab 
4349d44913c1SMauro Carvalho Chehab static int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
43509a0bf528SMauro Carvalho Chehab {
43519a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
43529a0bf528SMauro Carvalho Chehab 	dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
43539a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
43549a0bf528SMauro Carvalho Chehab }
43559a0bf528SMauro Carvalho Chehab 
43569a0bf528SMauro Carvalho Chehab static const struct dvb_frontend_ops dib8000_ops = {
43579a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ISDBT },
43589a0bf528SMauro Carvalho Chehab 	.info = {
43599a0bf528SMauro Carvalho Chehab 		 .name = "DiBcom 8000 ISDB-T",
43609a0bf528SMauro Carvalho Chehab 		 .frequency_min = 44250000,
43619a0bf528SMauro Carvalho Chehab 		 .frequency_max = 867250000,
43629a0bf528SMauro Carvalho Chehab 		 .frequency_stepsize = 62500,
43639a0bf528SMauro Carvalho Chehab 		 .caps = FE_CAN_INVERSION_AUTO |
43649a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
43659a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
43669a0bf528SMauro Carvalho Chehab 		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
43679a0bf528SMauro Carvalho Chehab 		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
43689a0bf528SMauro Carvalho Chehab 		 },
43699a0bf528SMauro Carvalho Chehab 
43709a0bf528SMauro Carvalho Chehab 	.release = dib8000_release,
43719a0bf528SMauro Carvalho Chehab 
43729a0bf528SMauro Carvalho Chehab 	.init = dib8000_wakeup,
43739a0bf528SMauro Carvalho Chehab 	.sleep = dib8000_sleep,
43749a0bf528SMauro Carvalho Chehab 
43759a0bf528SMauro Carvalho Chehab 	.set_frontend = dib8000_set_frontend,
43769a0bf528SMauro Carvalho Chehab 	.get_tune_settings = dib8000_fe_get_tune_settings,
43779a0bf528SMauro Carvalho Chehab 	.get_frontend = dib8000_get_frontend,
43789a0bf528SMauro Carvalho Chehab 
43799a0bf528SMauro Carvalho Chehab 	.read_status = dib8000_read_status,
43809a0bf528SMauro Carvalho Chehab 	.read_ber = dib8000_read_ber,
43819a0bf528SMauro Carvalho Chehab 	.read_signal_strength = dib8000_read_signal_strength,
43829a0bf528SMauro Carvalho Chehab 	.read_snr = dib8000_read_snr,
43839a0bf528SMauro Carvalho Chehab 	.read_ucblocks = dib8000_read_unc_blocks,
43849a0bf528SMauro Carvalho Chehab };
43859a0bf528SMauro Carvalho Chehab 
4386d44913c1SMauro Carvalho Chehab static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
43879a0bf528SMauro Carvalho Chehab {
43889a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *fe;
43899a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state;
43909a0bf528SMauro Carvalho Chehab 
4391b9bc7d59SMauro Carvalho Chehab 	dprintk("dib8000_init");
43929a0bf528SMauro Carvalho Chehab 
43939a0bf528SMauro Carvalho Chehab 	state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
43949a0bf528SMauro Carvalho Chehab 	if (state == NULL)
43959a0bf528SMauro Carvalho Chehab 		return NULL;
43969a0bf528SMauro Carvalho Chehab 	fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
43979a0bf528SMauro Carvalho Chehab 	if (fe == NULL)
43989a0bf528SMauro Carvalho Chehab 		goto error;
43999a0bf528SMauro Carvalho Chehab 
44009a0bf528SMauro Carvalho Chehab 	memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
44019a0bf528SMauro Carvalho Chehab 	state->i2c.adap = i2c_adap;
44029a0bf528SMauro Carvalho Chehab 	state->i2c.addr = i2c_addr;
44039a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_write_buffer = state->i2c_write_buffer;
44049a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_read_buffer = state->i2c_read_buffer;
44059a0bf528SMauro Carvalho Chehab 	mutex_init(&state->i2c_buffer_lock);
44069a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
44079a0bf528SMauro Carvalho Chehab 	state->gpio_val = cfg->gpio_val;
44089a0bf528SMauro Carvalho Chehab 	state->gpio_dir = cfg->gpio_dir;
44099a0bf528SMauro Carvalho Chehab 
44109a0bf528SMauro Carvalho Chehab 	/* Ensure the output mode remains at the previous default if it's
44119a0bf528SMauro Carvalho Chehab 	 * not specifically set by the caller.
44129a0bf528SMauro Carvalho Chehab 	 */
44139a0bf528SMauro Carvalho Chehab 	if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
44149a0bf528SMauro Carvalho Chehab 		state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
44159a0bf528SMauro Carvalho Chehab 
44169a0bf528SMauro Carvalho Chehab 	state->fe[0] = fe;
44179a0bf528SMauro Carvalho Chehab 	fe->demodulator_priv = state;
44189a0bf528SMauro Carvalho Chehab 	memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
44199a0bf528SMauro Carvalho Chehab 
44209a0bf528SMauro Carvalho Chehab 	state->timf_default = cfg->pll->timf;
44219a0bf528SMauro Carvalho Chehab 
44229a0bf528SMauro Carvalho Chehab 	if (dib8000_identify(&state->i2c) == 0)
44239a0bf528SMauro Carvalho Chehab 		goto error;
44249a0bf528SMauro Carvalho Chehab 
44259a0bf528SMauro Carvalho Chehab 	dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
44269a0bf528SMauro Carvalho Chehab 
44279a0bf528SMauro Carvalho Chehab 	/* init 8096p tuner adapter */
44289a0bf528SMauro Carvalho Chehab 	strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
44299a0bf528SMauro Carvalho Chehab 			sizeof(state->dib8096p_tuner_adap.name));
44309a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
44319a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.algo_data = NULL;
44329a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
44339a0bf528SMauro Carvalho Chehab 	i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
44349a0bf528SMauro Carvalho Chehab 	i2c_add_adapter(&state->dib8096p_tuner_adap);
44359a0bf528SMauro Carvalho Chehab 
44369a0bf528SMauro Carvalho Chehab 	dib8000_reset(fe);
44379a0bf528SMauro Carvalho Chehab 
44389a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));	/* ber_rs_len = 3 */
4439173a64cbSPatrick Boettcher 	state->current_demod_bw = 6000;
44409a0bf528SMauro Carvalho Chehab 
44419a0bf528SMauro Carvalho Chehab 	return fe;
44429a0bf528SMauro Carvalho Chehab 
44439a0bf528SMauro Carvalho Chehab error:
44449a0bf528SMauro Carvalho Chehab 	kfree(state);
44459a0bf528SMauro Carvalho Chehab 	return NULL;
44469a0bf528SMauro Carvalho Chehab }
44479a0bf528SMauro Carvalho Chehab 
4448d44913c1SMauro Carvalho Chehab void *dib8000_attach(struct dib8000_ops *ops)
4449d44913c1SMauro Carvalho Chehab {
4450d44913c1SMauro Carvalho Chehab 	if (!ops)
4451d44913c1SMauro Carvalho Chehab 		return NULL;
4452d44913c1SMauro Carvalho Chehab 
4453d44913c1SMauro Carvalho Chehab 	ops->pwm_agc_reset = dib8000_pwm_agc_reset;
4454d44913c1SMauro Carvalho Chehab 	ops->get_dc_power = dib8090p_get_dc_power;
4455d44913c1SMauro Carvalho Chehab 	ops->set_gpio = dib8000_set_gpio;
4456d44913c1SMauro Carvalho Chehab 	ops->get_slave_frontend = dib8000_get_slave_frontend;
4457d44913c1SMauro Carvalho Chehab 	ops->set_tune_state = dib8000_set_tune_state;
4458d44913c1SMauro Carvalho Chehab 	ops->pid_filter_ctrl = dib8000_pid_filter_ctrl;
4459d44913c1SMauro Carvalho Chehab 	ops->remove_slave_frontend = dib8000_remove_slave_frontend;
4460d44913c1SMauro Carvalho Chehab 	ops->get_adc_power = dib8000_get_adc_power;
4461d44913c1SMauro Carvalho Chehab 	ops->update_pll = dib8000_update_pll;
4462d44913c1SMauro Carvalho Chehab 	ops->tuner_sleep = dib8096p_tuner_sleep;
4463d44913c1SMauro Carvalho Chehab 	ops->get_tune_state = dib8000_get_tune_state;
4464d44913c1SMauro Carvalho Chehab 	ops->get_i2c_tuner = dib8096p_get_i2c_tuner;
4465d44913c1SMauro Carvalho Chehab 	ops->set_slave_frontend = dib8000_set_slave_frontend;
4466d44913c1SMauro Carvalho Chehab 	ops->pid_filter = dib8000_pid_filter;
4467d44913c1SMauro Carvalho Chehab 	ops->ctrl_timf = dib8000_ctrl_timf;
4468d44913c1SMauro Carvalho Chehab 	ops->init = dib8000_init;
4469d44913c1SMauro Carvalho Chehab 	ops->get_i2c_master = dib8000_get_i2c_master;
4470d44913c1SMauro Carvalho Chehab 	ops->i2c_enumeration = dib8000_i2c_enumeration;
4471d44913c1SMauro Carvalho Chehab 	ops->set_wbd_ref = dib8000_set_wbd_ref;
4472d44913c1SMauro Carvalho Chehab 
4473d44913c1SMauro Carvalho Chehab 	return ops;
4474d44913c1SMauro Carvalho Chehab }
4475d44913c1SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_attach);
44769a0bf528SMauro Carvalho Chehab 
44779a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>");
44789a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
44799a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
4480