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 
6599a0bf528SMauro Carvalho Chehab 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 }
6679a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_set_wbd_ref);
668173a64cbSPatrick Boettcher 
6699a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
6709a0bf528SMauro Carvalho Chehab {
6719a0bf528SMauro Carvalho Chehab 	dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
6729a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
6739a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23,
6749a0bf528SMauro Carvalho Chehab 				(u16) (((bw->internal * 1000) >> 16) & 0xffff));
6759a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24,
6769a0bf528SMauro Carvalho Chehab 				(u16) ((bw->internal * 1000) & 0xffff));
6779a0bf528SMauro Carvalho Chehab 	} else {
6789a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff));
6799a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24,
6809a0bf528SMauro Carvalho Chehab 				(u16) ((bw->internal  / 2 * 1000) & 0xffff));
6819a0bf528SMauro Carvalho Chehab 	}
6829a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
6839a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
6849a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
6859a0bf528SMauro Carvalho Chehab 
6869a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
6879a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 922, bw->sad_cfg);
6889a0bf528SMauro Carvalho Chehab }
6899a0bf528SMauro Carvalho Chehab 
6909a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll(struct dib8000_state *state)
6919a0bf528SMauro Carvalho Chehab {
6929a0bf528SMauro Carvalho Chehab 	const struct dibx000_bandwidth_config *pll = state->cfg.pll;
6939a0bf528SMauro Carvalho Chehab 	u16 clk_cfg1, reg;
6949a0bf528SMauro Carvalho Chehab 
6959a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
6969a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 901,
6979a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv << 8) | (pll->pll_ratio << 0));
6989a0bf528SMauro Carvalho Chehab 
6999a0bf528SMauro Carvalho Chehab 		clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
7009a0bf528SMauro Carvalho Chehab 			(pll->bypclk_div << 5) | (pll->enable_refdiv << 4) |
7019a0bf528SMauro Carvalho Chehab 			(1 << 3) | (pll->pll_range << 1) |
7029a0bf528SMauro Carvalho Chehab 			(pll->pll_reset << 0);
7039a0bf528SMauro Carvalho Chehab 
7049a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 902, clk_cfg1);
7059a0bf528SMauro Carvalho Chehab 		clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
7069a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 902, clk_cfg1);
7079a0bf528SMauro Carvalho Chehab 
7089a0bf528SMauro Carvalho Chehab 		dprintk("clk_cfg1: 0x%04x", clk_cfg1);
7099a0bf528SMauro Carvalho Chehab 
7109a0bf528SMauro Carvalho Chehab 		/* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
7119a0bf528SMauro Carvalho Chehab 		if (state->cfg.pll->ADClkSrc == 0)
7129a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904,
7139a0bf528SMauro Carvalho Chehab 					(0 << 15) | (0 << 12) | (0 << 10) |
7149a0bf528SMauro Carvalho Chehab 					(pll->modulo << 8) |
7159a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
7169a0bf528SMauro Carvalho Chehab 		else if (state->cfg.refclksel != 0)
7179a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
7189a0bf528SMauro Carvalho Chehab 					((state->cfg.refclksel & 0x3) << 10) |
7199a0bf528SMauro Carvalho Chehab 					(pll->modulo << 8) |
7209a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
7219a0bf528SMauro Carvalho Chehab 		else
7229a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
7239a0bf528SMauro Carvalho Chehab 					(3 << 10) | (pll->modulo << 8) |
7249a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
7259a0bf528SMauro Carvalho Chehab 	} else {
7269a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1856, (!pll->pll_reset<<13) |
7279a0bf528SMauro Carvalho Chehab 				(pll->pll_range<<12) | (pll->pll_ratio<<6) |
7289a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv));
7299a0bf528SMauro Carvalho Chehab 
7309a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 1857);
7319a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15));
7329a0bf528SMauro Carvalho Chehab 
7339a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */
7349a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1858, reg | 1);
7359a0bf528SMauro Carvalho Chehab 
7369a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 904, (pll->modulo << 8));
7379a0bf528SMauro Carvalho Chehab 	}
7389a0bf528SMauro Carvalho Chehab 
7399a0bf528SMauro Carvalho Chehab 	dib8000_reset_pll_common(state, pll);
7409a0bf528SMauro Carvalho Chehab }
7419a0bf528SMauro Carvalho Chehab 
7429a0bf528SMauro Carvalho Chehab int dib8000_update_pll(struct dvb_frontend *fe,
743173a64cbSPatrick Boettcher 		struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
7449a0bf528SMauro Carvalho Chehab {
7459a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
7469a0bf528SMauro Carvalho Chehab 	u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
747173a64cbSPatrick Boettcher 	u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ;
7489a0bf528SMauro Carvalho Chehab 	u32 internal, xtal;
7499a0bf528SMauro Carvalho Chehab 
7509a0bf528SMauro Carvalho Chehab 	/* get back old values */
7519a0bf528SMauro Carvalho Chehab 	prediv = reg_1856 & 0x3f;
7529a0bf528SMauro Carvalho Chehab 	loopdiv = (reg_1856 >> 6) & 0x3f;
7539a0bf528SMauro Carvalho Chehab 
754173a64cbSPatrick Boettcher 	if ((pll == NULL) || (pll->pll_prediv == prediv &&
755173a64cbSPatrick Boettcher 				pll->pll_ratio == loopdiv))
756173a64cbSPatrick Boettcher 		return -EINVAL;
757173a64cbSPatrick Boettcher 
7589a0bf528SMauro Carvalho Chehab 	dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
759173a64cbSPatrick Boettcher 	if (state->revision == 0x8090) {
7609a0bf528SMauro Carvalho Chehab 		reg_1856 &= 0xf000;
7619a0bf528SMauro Carvalho Chehab 		reg_1857 = dib8000_read_word(state, 1857);
7629a0bf528SMauro Carvalho Chehab 		/* disable PLL */
7639a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15));
7649a0bf528SMauro Carvalho Chehab 
7659a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1856, reg_1856 |
7669a0bf528SMauro Carvalho Chehab 				((pll->pll_ratio & 0x3f) << 6) |
7679a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv & 0x3f));
7689a0bf528SMauro Carvalho Chehab 
7699a0bf528SMauro Carvalho Chehab 		/* write new system clk into P_sec_len */
7709a0bf528SMauro Carvalho Chehab 		internal = dib8000_read32(state, 23) / 1000;
7719a0bf528SMauro Carvalho Chehab 		dprintk("Old Internal = %d", internal);
7729a0bf528SMauro Carvalho Chehab 		xtal = 2 * (internal / loopdiv) * prediv;
7739a0bf528SMauro Carvalho Chehab 		internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio;
7749a0bf528SMauro Carvalho Chehab 		dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d", xtal, internal/1000, internal/2000, internal/8000);
7759a0bf528SMauro Carvalho Chehab 		dprintk("New Internal = %d", internal);
7769a0bf528SMauro Carvalho Chehab 
7779a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23,
7789a0bf528SMauro Carvalho Chehab 				(u16) (((internal / 2) >> 16) & 0xffff));
7799a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff));
7809a0bf528SMauro Carvalho Chehab 		/* enable PLL */
7819a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg_1857 | (1 << 15));
7829a0bf528SMauro Carvalho Chehab 
7839a0bf528SMauro Carvalho Chehab 		while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1)
7849a0bf528SMauro Carvalho Chehab 			dprintk("Waiting for PLL to lock");
7859a0bf528SMauro Carvalho Chehab 
7869a0bf528SMauro Carvalho Chehab 		/* verify */
7879a0bf528SMauro Carvalho Chehab 		reg_1856 = dib8000_read_word(state, 1856);
7889a0bf528SMauro Carvalho Chehab 		dprintk("PLL Updated with prediv = %d and loopdiv = %d",
7899a0bf528SMauro Carvalho Chehab 				reg_1856&0x3f, (reg_1856>>6)&0x3f);
790173a64cbSPatrick Boettcher 	} else {
791173a64cbSPatrick Boettcher 		if (bw != state->current_demod_bw) {
792173a64cbSPatrick Boettcher 			/** Bandwidth change => force PLL update **/
793173a64cbSPatrick 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);
794173a64cbSPatrick Boettcher 
795173a64cbSPatrick Boettcher 			if (state->cfg.pll->pll_prediv != oldprediv) {
796173a64cbSPatrick Boettcher 				/** Full PLL change only if prediv is changed **/
797173a64cbSPatrick Boettcher 
798173a64cbSPatrick Boettcher 				/** full update => bypass and reconfigure **/
799173a64cbSPatrick 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);
800173a64cbSPatrick Boettcher 				dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */
801173a64cbSPatrick Boettcher 				dib8000_reset_pll(state);
802173a64cbSPatrick Boettcher 				dib8000_write_word(state, 898, 0x0004); /* sad */
803173a64cbSPatrick Boettcher 			} else
804173a64cbSPatrick Boettcher 				ratio = state->cfg.pll->pll_ratio;
805173a64cbSPatrick Boettcher 
806173a64cbSPatrick Boettcher 			state->current_demod_bw = bw;
807173a64cbSPatrick Boettcher 		}
808173a64cbSPatrick Boettcher 
809173a64cbSPatrick Boettcher 		if (ratio != 0) {
810173a64cbSPatrick Boettcher 			/** ratio update => only change ratio **/
811173a64cbSPatrick Boettcher 			dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio);
812173a64cbSPatrick Boettcher 			dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
813173a64cbSPatrick Boettcher 		}
814173a64cbSPatrick Boettcher 	}
8159a0bf528SMauro Carvalho Chehab 
8169a0bf528SMauro Carvalho Chehab 	return 0;
8179a0bf528SMauro Carvalho Chehab }
8189a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_update_pll);
8199a0bf528SMauro Carvalho Chehab 
8209a0bf528SMauro Carvalho Chehab 
8219a0bf528SMauro Carvalho Chehab static int dib8000_reset_gpio(struct dib8000_state *st)
8229a0bf528SMauro Carvalho Chehab {
8239a0bf528SMauro Carvalho Chehab 	/* reset the GPIOs */
8249a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
8259a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1030, st->cfg.gpio_val);
8269a0bf528SMauro Carvalho Chehab 
8279a0bf528SMauro Carvalho Chehab 	/* TODO 782 is P_gpio_od */
8289a0bf528SMauro Carvalho Chehab 
8299a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
8309a0bf528SMauro Carvalho Chehab 
8319a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
8329a0bf528SMauro Carvalho Chehab 	return 0;
8339a0bf528SMauro Carvalho Chehab }
8349a0bf528SMauro Carvalho Chehab 
8359a0bf528SMauro Carvalho Chehab static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
8369a0bf528SMauro Carvalho Chehab {
8379a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir = dib8000_read_word(st, 1029);
8389a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir &= ~(1 << num);	/* reset the direction bit */
8399a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
8409a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
8419a0bf528SMauro Carvalho Chehab 
8429a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val = dib8000_read_word(st, 1030);
8439a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val &= ~(1 << num);	/* reset the direction bit */
8449a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val |= (val & 0x01) << num;	/* set the new value */
8459a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1030, st->cfg.gpio_val);
8469a0bf528SMauro Carvalho Chehab 
8479a0bf528SMauro Carvalho Chehab 	dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val);
8489a0bf528SMauro Carvalho Chehab 
8499a0bf528SMauro Carvalho Chehab 	return 0;
8509a0bf528SMauro Carvalho Chehab }
8519a0bf528SMauro Carvalho Chehab 
8529a0bf528SMauro Carvalho Chehab int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
8539a0bf528SMauro Carvalho Chehab {
8549a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
8559a0bf528SMauro Carvalho Chehab 	return dib8000_cfg_gpio(state, num, dir, val);
8569a0bf528SMauro Carvalho Chehab }
8579a0bf528SMauro Carvalho Chehab 
8589a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_set_gpio);
8599a0bf528SMauro Carvalho Chehab static const u16 dib8000_defaults[] = {
8609a0bf528SMauro Carvalho Chehab 	/* auto search configuration - lock0 by default waiting
8619a0bf528SMauro Carvalho Chehab 	 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
8629a0bf528SMauro Carvalho Chehab 	3, 7,
8639a0bf528SMauro Carvalho Chehab 	0x0004,
8649a0bf528SMauro Carvalho Chehab 	0x0400,
8659a0bf528SMauro Carvalho Chehab 	0x0814,
8669a0bf528SMauro Carvalho Chehab 
8679a0bf528SMauro Carvalho Chehab 	12, 11,
8689a0bf528SMauro Carvalho Chehab 	0x001b,
8699a0bf528SMauro Carvalho Chehab 	0x7740,
8709a0bf528SMauro Carvalho Chehab 	0x005b,
8719a0bf528SMauro Carvalho Chehab 	0x8d80,
8729a0bf528SMauro Carvalho Chehab 	0x01c9,
8739a0bf528SMauro Carvalho Chehab 	0xc380,
8749a0bf528SMauro Carvalho Chehab 	0x0000,
8759a0bf528SMauro Carvalho Chehab 	0x0080,
8769a0bf528SMauro Carvalho Chehab 	0x0000,
8779a0bf528SMauro Carvalho Chehab 	0x0090,
8789a0bf528SMauro Carvalho Chehab 	0x0001,
8799a0bf528SMauro Carvalho Chehab 	0xd4c0,
8809a0bf528SMauro Carvalho Chehab 
8819a0bf528SMauro Carvalho Chehab 	/*1, 32,
8829a0bf528SMauro Carvalho Chehab 		0x6680 // P_corm_thres Lock algorithms configuration */
8839a0bf528SMauro Carvalho Chehab 
8849a0bf528SMauro Carvalho Chehab 	11, 80,			/* set ADC level to -16 */
8859a0bf528SMauro Carvalho Chehab 	(1 << 13) - 825 - 117,
8869a0bf528SMauro Carvalho Chehab 	(1 << 13) - 837 - 117,
8879a0bf528SMauro Carvalho Chehab 	(1 << 13) - 811 - 117,
8889a0bf528SMauro Carvalho Chehab 	(1 << 13) - 766 - 117,
8899a0bf528SMauro Carvalho Chehab 	(1 << 13) - 737 - 117,
8909a0bf528SMauro Carvalho Chehab 	(1 << 13) - 693 - 117,
8919a0bf528SMauro Carvalho Chehab 	(1 << 13) - 648 - 117,
8929a0bf528SMauro Carvalho Chehab 	(1 << 13) - 619 - 117,
8939a0bf528SMauro Carvalho Chehab 	(1 << 13) - 575 - 117,
8949a0bf528SMauro Carvalho Chehab 	(1 << 13) - 531 - 117,
8959a0bf528SMauro Carvalho Chehab 	(1 << 13) - 501 - 117,
8969a0bf528SMauro Carvalho Chehab 
8979a0bf528SMauro Carvalho Chehab 	4, 108,
8989a0bf528SMauro Carvalho Chehab 	0,
8999a0bf528SMauro Carvalho Chehab 	0,
9009a0bf528SMauro Carvalho Chehab 	0,
9019a0bf528SMauro Carvalho Chehab 	0,
9029a0bf528SMauro Carvalho Chehab 
9039a0bf528SMauro Carvalho Chehab 	1, 175,
9049a0bf528SMauro Carvalho Chehab 	0x0410,
9059a0bf528SMauro Carvalho Chehab 	1, 179,
9069a0bf528SMauro Carvalho Chehab 	8192,			// P_fft_nb_to_cut
9079a0bf528SMauro Carvalho Chehab 
9089a0bf528SMauro Carvalho Chehab 	6, 181,
9099a0bf528SMauro Carvalho Chehab 	0x2800,			// P_coff_corthres_ ( 2k 4k 8k ) 0x2800
9109a0bf528SMauro Carvalho Chehab 	0x2800,
9119a0bf528SMauro Carvalho Chehab 	0x2800,
9129a0bf528SMauro Carvalho Chehab 	0x2800,			// P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
9139a0bf528SMauro Carvalho Chehab 	0x2800,
9149a0bf528SMauro Carvalho Chehab 	0x2800,
9159a0bf528SMauro Carvalho Chehab 
9169a0bf528SMauro Carvalho Chehab 	2, 193,
9179a0bf528SMauro Carvalho Chehab 	0x0666,			// P_pha3_thres
9189a0bf528SMauro Carvalho Chehab 	0x0000,			// P_cti_use_cpe, P_cti_use_prog
9199a0bf528SMauro Carvalho Chehab 
9209a0bf528SMauro Carvalho Chehab 	2, 205,
9219a0bf528SMauro Carvalho Chehab 	0x200f,			// P_cspu_regul, P_cspu_win_cut
9229a0bf528SMauro Carvalho Chehab 	0x000f,			// P_des_shift_work
9239a0bf528SMauro Carvalho Chehab 
9249a0bf528SMauro Carvalho Chehab 	5, 215,
9259a0bf528SMauro Carvalho Chehab 	0x023d,			// P_adp_regul_cnt
9269a0bf528SMauro Carvalho Chehab 	0x00a4,			// P_adp_noise_cnt
9279a0bf528SMauro Carvalho Chehab 	0x00a4,			// P_adp_regul_ext
9289a0bf528SMauro Carvalho Chehab 	0x7ff0,			// P_adp_noise_ext
9299a0bf528SMauro Carvalho Chehab 	0x3ccc,			// P_adp_fil
9309a0bf528SMauro Carvalho Chehab 
9319a0bf528SMauro Carvalho Chehab 	1, 230,
9329a0bf528SMauro Carvalho Chehab 	0x0000,			// P_2d_byp_ti_num
9339a0bf528SMauro Carvalho Chehab 
9349a0bf528SMauro Carvalho Chehab 	1, 263,
9359a0bf528SMauro Carvalho Chehab 	0x800,			//P_equal_thres_wgn
9369a0bf528SMauro Carvalho Chehab 
9379a0bf528SMauro Carvalho Chehab 	1, 268,
9389a0bf528SMauro Carvalho Chehab 	(2 << 9) | 39,		// P_equal_ctrl_synchro, P_equal_speedmode
9399a0bf528SMauro Carvalho Chehab 
9409a0bf528SMauro Carvalho Chehab 	1, 270,
9419a0bf528SMauro Carvalho Chehab 	0x0001,			// P_div_lock0_wait
9429a0bf528SMauro Carvalho Chehab 	1, 285,
9439a0bf528SMauro Carvalho Chehab 	0x0020,			//p_fec_
9449a0bf528SMauro Carvalho Chehab 	1, 299,
9459a0bf528SMauro Carvalho Chehab 	0x0062,			/* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */
9469a0bf528SMauro Carvalho Chehab 
9479a0bf528SMauro Carvalho Chehab 	1, 338,
9489a0bf528SMauro Carvalho Chehab 	(1 << 12) |		// P_ctrl_corm_thres4pre_freq_inh=1
9499a0bf528SMauro Carvalho Chehab 		(1 << 10) |
9509a0bf528SMauro Carvalho Chehab 		(0 << 9) |		/* P_ctrl_pre_freq_inh=0 */
9519a0bf528SMauro Carvalho Chehab 		(3 << 5) |		/* P_ctrl_pre_freq_step=3 */
9529a0bf528SMauro Carvalho Chehab 		(1 << 0),		/* P_pre_freq_win_len=1 */
9539a0bf528SMauro Carvalho Chehab 
9549a0bf528SMauro Carvalho Chehab 	0,
9559a0bf528SMauro Carvalho Chehab };
9569a0bf528SMauro Carvalho Chehab 
9579a0bf528SMauro Carvalho Chehab static u16 dib8000_identify(struct i2c_device *client)
9589a0bf528SMauro Carvalho Chehab {
9599a0bf528SMauro Carvalho Chehab 	u16 value;
9609a0bf528SMauro Carvalho Chehab 
9619a0bf528SMauro Carvalho Chehab 	//because of glitches sometimes
9629a0bf528SMauro Carvalho Chehab 	value = dib8000_i2c_read16(client, 896);
9639a0bf528SMauro Carvalho Chehab 
9649a0bf528SMauro Carvalho Chehab 	if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
9659a0bf528SMauro Carvalho Chehab 		dprintk("wrong Vendor ID (read=0x%x)", value);
9669a0bf528SMauro Carvalho Chehab 		return 0;
9679a0bf528SMauro Carvalho Chehab 	}
9689a0bf528SMauro Carvalho Chehab 
9699a0bf528SMauro Carvalho Chehab 	value = dib8000_i2c_read16(client, 897);
9709a0bf528SMauro Carvalho Chehab 	if (value != 0x8000 && value != 0x8001 &&
9719a0bf528SMauro Carvalho Chehab 			value != 0x8002 && value != 0x8090) {
9729a0bf528SMauro Carvalho Chehab 		dprintk("wrong Device ID (%x)", value);
9739a0bf528SMauro Carvalho Chehab 		return 0;
9749a0bf528SMauro Carvalho Chehab 	}
9759a0bf528SMauro Carvalho Chehab 
9769a0bf528SMauro Carvalho Chehab 	switch (value) {
9779a0bf528SMauro Carvalho Chehab 	case 0x8000:
9789a0bf528SMauro Carvalho Chehab 		dprintk("found DiB8000A");
9799a0bf528SMauro Carvalho Chehab 		break;
9809a0bf528SMauro Carvalho Chehab 	case 0x8001:
9819a0bf528SMauro Carvalho Chehab 		dprintk("found DiB8000B");
9829a0bf528SMauro Carvalho Chehab 		break;
9839a0bf528SMauro Carvalho Chehab 	case 0x8002:
9849a0bf528SMauro Carvalho Chehab 		dprintk("found DiB8000C");
9859a0bf528SMauro Carvalho Chehab 		break;
9869a0bf528SMauro Carvalho Chehab 	case 0x8090:
9879a0bf528SMauro Carvalho Chehab 		dprintk("found DiB8096P");
9889a0bf528SMauro Carvalho Chehab 		break;
9899a0bf528SMauro Carvalho Chehab 	}
9909a0bf528SMauro Carvalho Chehab 	return value;
9919a0bf528SMauro Carvalho Chehab }
9929a0bf528SMauro Carvalho Chehab 
9937a9d85d5SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 *unc);
9947a9d85d5SMauro Carvalho Chehab 
9956ef06e78SMauro Carvalho Chehab static void dib8000_reset_stats(struct dvb_frontend *fe)
9966ef06e78SMauro Carvalho Chehab {
9976ef06e78SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
9986ef06e78SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
9997a9d85d5SMauro Carvalho Chehab 	u32 ucb;
10006ef06e78SMauro Carvalho Chehab 
10016ef06e78SMauro Carvalho Chehab 	memset(&c->strength, 0, sizeof(c->strength));
10026ef06e78SMauro Carvalho Chehab 	memset(&c->cnr, 0, sizeof(c->cnr));
10036ef06e78SMauro Carvalho Chehab 	memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
10046ef06e78SMauro Carvalho Chehab 	memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
10056ef06e78SMauro Carvalho Chehab 	memset(&c->block_error, 0, sizeof(c->block_error));
10066ef06e78SMauro Carvalho Chehab 
10076ef06e78SMauro Carvalho Chehab 	c->strength.len = 1;
10086ef06e78SMauro Carvalho Chehab 	c->cnr.len = 1;
10096ef06e78SMauro Carvalho Chehab 	c->block_error.len = 1;
10100400c535SMauro Carvalho Chehab 	c->block_count.len = 1;
10116ef06e78SMauro Carvalho Chehab 	c->post_bit_error.len = 1;
10126ef06e78SMauro Carvalho Chehab 	c->post_bit_count.len = 1;
10136ef06e78SMauro Carvalho Chehab 
1014b4600d70SMauro Carvalho Chehab 	c->strength.stat[0].scale = FE_SCALE_DECIBEL;
10156ef06e78SMauro Carvalho Chehab 	c->strength.stat[0].uvalue = 0;
10166ef06e78SMauro Carvalho Chehab 
10176ef06e78SMauro Carvalho Chehab 	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10186ef06e78SMauro Carvalho Chehab 	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10190400c535SMauro Carvalho Chehab 	c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10206ef06e78SMauro Carvalho Chehab 	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10216ef06e78SMauro Carvalho Chehab 	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10227a9d85d5SMauro Carvalho Chehab 
10237a9d85d5SMauro Carvalho Chehab 	dib8000_read_unc_blocks(fe, &ucb);
1024704f01bbSMauro Carvalho Chehab 
10257a9d85d5SMauro Carvalho Chehab 	state->init_ucb = -ucb;
10260400c535SMauro Carvalho Chehab 	state->ber_jiffies_stats = 0;
10270400c535SMauro Carvalho Chehab 	state->per_jiffies_stats = 0;
10280400c535SMauro Carvalho Chehab 	memset(&state->ber_jiffies_stats_layer, 0,
10290400c535SMauro Carvalho Chehab 	       sizeof(state->ber_jiffies_stats_layer));
10306ef06e78SMauro Carvalho Chehab }
10316ef06e78SMauro Carvalho Chehab 
10329a0bf528SMauro Carvalho Chehab static int dib8000_reset(struct dvb_frontend *fe)
10339a0bf528SMauro Carvalho Chehab {
10349a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
10359a0bf528SMauro Carvalho Chehab 
10369a0bf528SMauro Carvalho Chehab 	if ((state->revision = dib8000_identify(&state->i2c)) == 0)
10379a0bf528SMauro Carvalho Chehab 		return -EINVAL;
10389a0bf528SMauro Carvalho Chehab 
10399a0bf528SMauro Carvalho Chehab 	/* sram lead in, rdy */
10409a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
10419a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1287, 0x0003);
10429a0bf528SMauro Carvalho Chehab 
10439a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8000)
10449a0bf528SMauro Carvalho Chehab 		dprintk("error : dib8000 MA not supported");
10459a0bf528SMauro Carvalho Chehab 
10469a0bf528SMauro Carvalho Chehab 	dibx000_reset_i2c_master(&state->i2c_master);
10479a0bf528SMauro Carvalho Chehab 
10489a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
10499a0bf528SMauro Carvalho Chehab 
10509a0bf528SMauro Carvalho Chehab 	/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
1051173a64cbSPatrick Boettcher 	dib8000_set_adc_state(state, DIBX000_ADC_OFF);
10529a0bf528SMauro Carvalho Chehab 
10539a0bf528SMauro Carvalho Chehab 	/* restart all parts */
10549a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0xffff);
10559a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 771, 0xffff);
10569a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 772, 0xfffc);
10579a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
10589a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1280, 0x0045);
10599a0bf528SMauro Carvalho Chehab 	else
10609a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1280, 0x004d);
10619a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1281, 0x000c);
10629a0bf528SMauro Carvalho Chehab 
10639a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0000);
10649a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 771, 0x0000);
10659a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 772, 0x0000);
10669a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 898, 0x0004);	// sad
10679a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1280, 0x0000);
10689a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1281, 0x0000);
10699a0bf528SMauro Carvalho Chehab 
10709a0bf528SMauro Carvalho Chehab 	/* drives */
10719a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
10729a0bf528SMauro Carvalho Chehab 		if (state->cfg.drives)
10739a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 906, state->cfg.drives);
10749a0bf528SMauro Carvalho Chehab 		else {
10759a0bf528SMauro Carvalho Chehab 			dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
10769a0bf528SMauro Carvalho Chehab 			/* min drive SDRAM - not optimal - adjust */
10779a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 906, 0x2d98);
10789a0bf528SMauro Carvalho Chehab 		}
10799a0bf528SMauro Carvalho Chehab 	}
10809a0bf528SMauro Carvalho Chehab 
10819a0bf528SMauro Carvalho Chehab 	dib8000_reset_pll(state);
10829a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
10839a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 898, 0x0004);
10849a0bf528SMauro Carvalho Chehab 
10859a0bf528SMauro Carvalho Chehab 	if (dib8000_reset_gpio(state) != 0)
10869a0bf528SMauro Carvalho Chehab 		dprintk("GPIO reset was not successful.");
10879a0bf528SMauro Carvalho Chehab 
10889a0bf528SMauro Carvalho Chehab 	if ((state->revision != 0x8090) &&
10899a0bf528SMauro Carvalho Chehab 			(dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
10909a0bf528SMauro Carvalho Chehab 		dprintk("OUTPUT_MODE could not be resetted.");
10919a0bf528SMauro Carvalho Chehab 
10929a0bf528SMauro Carvalho Chehab 	state->current_agc = NULL;
10939a0bf528SMauro Carvalho Chehab 
10949a0bf528SMauro Carvalho Chehab 	// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
10959a0bf528SMauro Carvalho Chehab 	/* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
10969a0bf528SMauro Carvalho Chehab 	if (state->cfg.pll->ifreq == 0)
10979a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 40, 0x0755);	/* P_iqc_corr_inh = 0 enable IQcorr block */
10989a0bf528SMauro Carvalho Chehab 	else
10999a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 40, 0x1f55);	/* P_iqc_corr_inh = 1 disable IQcorr block */
11009a0bf528SMauro Carvalho Chehab 
11019a0bf528SMauro Carvalho Chehab 	{
11029a0bf528SMauro Carvalho Chehab 		u16 l = 0, r;
11039a0bf528SMauro Carvalho Chehab 		const u16 *n;
11049a0bf528SMauro Carvalho Chehab 		n = dib8000_defaults;
11059a0bf528SMauro Carvalho Chehab 		l = *n++;
11069a0bf528SMauro Carvalho Chehab 		while (l) {
11079a0bf528SMauro Carvalho Chehab 			r = *n++;
11089a0bf528SMauro Carvalho Chehab 			do {
11099a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, r, *n++);
11109a0bf528SMauro Carvalho Chehab 				r++;
11119a0bf528SMauro Carvalho Chehab 			} while (--l);
11129a0bf528SMauro Carvalho Chehab 			l = *n++;
11139a0bf528SMauro Carvalho Chehab 		}
11149a0bf528SMauro Carvalho Chehab 	}
1115173a64cbSPatrick Boettcher 
11169a0bf528SMauro Carvalho Chehab 	state->isdbt_cfg_loaded = 0;
11179a0bf528SMauro Carvalho Chehab 
11189a0bf528SMauro Carvalho Chehab 	//div_cfg override for special configs
1119173a64cbSPatrick Boettcher 	if ((state->revision != 8090) && (state->cfg.div_cfg != 0))
11209a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 903, state->cfg.div_cfg);
11219a0bf528SMauro Carvalho Chehab 
11229a0bf528SMauro Carvalho Chehab 	/* unforce divstr regardless whether i2c enumeration was done or not */
11239a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
11249a0bf528SMauro Carvalho Chehab 
11259a0bf528SMauro Carvalho Chehab 	dib8000_set_bandwidth(fe, 6000);
11269a0bf528SMauro Carvalho Chehab 
11279a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
11289a0bf528SMauro Carvalho Chehab 	dib8000_sad_calib(state);
1129173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
11309a0bf528SMauro Carvalho Chehab 		dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
1131173a64cbSPatrick Boettcher 
1132173a64cbSPatrick Boettcher 	/* ber_rs_len = 3 */
1133173a64cbSPatrick Boettcher 	dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));
11349a0bf528SMauro Carvalho Chehab 
11359a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
11369a0bf528SMauro Carvalho Chehab 
11376ef06e78SMauro Carvalho Chehab 	dib8000_reset_stats(fe);
11386ef06e78SMauro Carvalho Chehab 
11399a0bf528SMauro Carvalho Chehab 	return 0;
11409a0bf528SMauro Carvalho Chehab }
11419a0bf528SMauro Carvalho Chehab 
11429a0bf528SMauro Carvalho Chehab static void dib8000_restart_agc(struct dib8000_state *state)
11439a0bf528SMauro Carvalho Chehab {
11449a0bf528SMauro Carvalho Chehab 	// P_restart_iqc & P_restart_agc
11459a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0a00);
11469a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0000);
11479a0bf528SMauro Carvalho Chehab }
11489a0bf528SMauro Carvalho Chehab 
11499a0bf528SMauro Carvalho Chehab static int dib8000_update_lna(struct dib8000_state *state)
11509a0bf528SMauro Carvalho Chehab {
11519a0bf528SMauro Carvalho Chehab 	u16 dyn_gain;
11529a0bf528SMauro Carvalho Chehab 
11539a0bf528SMauro Carvalho Chehab 	if (state->cfg.update_lna) {
11549a0bf528SMauro Carvalho Chehab 		// read dyn_gain here (because it is demod-dependent and not tuner)
11559a0bf528SMauro Carvalho Chehab 		dyn_gain = dib8000_read_word(state, 390);
11569a0bf528SMauro Carvalho Chehab 
11579a0bf528SMauro Carvalho Chehab 		if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
11589a0bf528SMauro Carvalho Chehab 			dib8000_restart_agc(state);
11599a0bf528SMauro Carvalho Chehab 			return 1;
11609a0bf528SMauro Carvalho Chehab 		}
11619a0bf528SMauro Carvalho Chehab 	}
11629a0bf528SMauro Carvalho Chehab 	return 0;
11639a0bf528SMauro Carvalho Chehab }
11649a0bf528SMauro Carvalho Chehab 
11659a0bf528SMauro Carvalho Chehab static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
11669a0bf528SMauro Carvalho Chehab {
11679a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *agc = NULL;
11689a0bf528SMauro Carvalho Chehab 	int i;
11699a0bf528SMauro Carvalho Chehab 	u16 reg;
11709a0bf528SMauro Carvalho Chehab 
11719a0bf528SMauro Carvalho Chehab 	if (state->current_band == band && state->current_agc != NULL)
11729a0bf528SMauro Carvalho Chehab 		return 0;
11739a0bf528SMauro Carvalho Chehab 	state->current_band = band;
11749a0bf528SMauro Carvalho Chehab 
11759a0bf528SMauro Carvalho Chehab 	for (i = 0; i < state->cfg.agc_config_count; i++)
11769a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc[i].band_caps & band) {
11779a0bf528SMauro Carvalho Chehab 			agc = &state->cfg.agc[i];
11789a0bf528SMauro Carvalho Chehab 			break;
11799a0bf528SMauro Carvalho Chehab 		}
11809a0bf528SMauro Carvalho Chehab 
11819a0bf528SMauro Carvalho Chehab 	if (agc == NULL) {
11829a0bf528SMauro Carvalho Chehab 		dprintk("no valid AGC configuration found for band 0x%02x", band);
11839a0bf528SMauro Carvalho Chehab 		return -EINVAL;
11849a0bf528SMauro Carvalho Chehab 	}
11859a0bf528SMauro Carvalho Chehab 
11869a0bf528SMauro Carvalho Chehab 	state->current_agc = agc;
11879a0bf528SMauro Carvalho Chehab 
11889a0bf528SMauro Carvalho Chehab 	/* AGC */
11899a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 76, agc->setup);
11909a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 77, agc->inv_gain);
11919a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 78, agc->time_stabiliz);
11929a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
11939a0bf528SMauro Carvalho Chehab 
11949a0bf528SMauro Carvalho Chehab 	// Demod AGC loop configuration
11959a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
11969a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
11979a0bf528SMauro Carvalho Chehab 
11989a0bf528SMauro Carvalho Chehab 	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
11999a0bf528SMauro Carvalho Chehab 		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
12009a0bf528SMauro Carvalho Chehab 
12019a0bf528SMauro Carvalho Chehab 	/* AGC continued */
12029a0bf528SMauro Carvalho Chehab 	if (state->wbd_ref != 0)
12039a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 106, state->wbd_ref);
12049a0bf528SMauro Carvalho Chehab 	else			// use default
12059a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 106, agc->wbd_ref);
12069a0bf528SMauro Carvalho Chehab 
12079a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090) {
12089a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 922) & (0x3 << 2);
12099a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
12109a0bf528SMauro Carvalho Chehab 	}
12119a0bf528SMauro Carvalho Chehab 
12129a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
12139a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 108, agc->agc1_max);
12149a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 109, agc->agc1_min);
12159a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 110, agc->agc2_max);
12169a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 111, agc->agc2_min);
12179a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
12189a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
12199a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
12209a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
12219a0bf528SMauro Carvalho Chehab 
12229a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 75, agc->agc1_pt3);
12239a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
12249a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923,
12259a0bf528SMauro Carvalho Chehab 				(dib8000_read_word(state, 923) & 0xffe3) |
12269a0bf528SMauro Carvalho Chehab 				(agc->wbd_inv << 4) | (agc->wbd_sel << 2));
12279a0bf528SMauro Carvalho Chehab 
12289a0bf528SMauro Carvalho Chehab 	return 0;
12299a0bf528SMauro Carvalho Chehab }
12309a0bf528SMauro Carvalho Chehab 
12319a0bf528SMauro Carvalho Chehab void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
12329a0bf528SMauro Carvalho Chehab {
12339a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
12349a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_ADC_ON);
12359a0bf528SMauro Carvalho Chehab 	dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
12369a0bf528SMauro Carvalho Chehab }
12379a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_pwm_agc_reset);
12389a0bf528SMauro Carvalho Chehab 
12399a0bf528SMauro Carvalho Chehab static int dib8000_agc_soft_split(struct dib8000_state *state)
12409a0bf528SMauro Carvalho Chehab {
12419a0bf528SMauro Carvalho Chehab 	u16 agc, split_offset;
12429a0bf528SMauro Carvalho Chehab 
12439a0bf528SMauro Carvalho Chehab 	if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
12449a0bf528SMauro Carvalho Chehab 		return FE_CALLBACK_TIME_NEVER;
12459a0bf528SMauro Carvalho Chehab 
12469a0bf528SMauro Carvalho Chehab 	// n_agc_global
12479a0bf528SMauro Carvalho Chehab 	agc = dib8000_read_word(state, 390);
12489a0bf528SMauro Carvalho Chehab 
12499a0bf528SMauro Carvalho Chehab 	if (agc > state->current_agc->split.min_thres)
12509a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.min;
12519a0bf528SMauro Carvalho Chehab 	else if (agc < state->current_agc->split.max_thres)
12529a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.max;
12539a0bf528SMauro Carvalho Chehab 	else
12549a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.max *
12559a0bf528SMauro Carvalho Chehab 			(agc - state->current_agc->split.min_thres) /
12569a0bf528SMauro Carvalho Chehab 			(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
12579a0bf528SMauro Carvalho Chehab 
12589a0bf528SMauro Carvalho Chehab 	dprintk("AGC split_offset: %d", split_offset);
12599a0bf528SMauro Carvalho Chehab 
12609a0bf528SMauro Carvalho Chehab 	// P_agc_force_split and P_agc_split_offset
12619a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
12629a0bf528SMauro Carvalho Chehab 	return 5000;
12639a0bf528SMauro Carvalho Chehab }
12649a0bf528SMauro Carvalho Chehab 
12659a0bf528SMauro Carvalho Chehab static int dib8000_agc_startup(struct dvb_frontend *fe)
12669a0bf528SMauro Carvalho Chehab {
12679a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
12689a0bf528SMauro Carvalho Chehab 	enum frontend_tune_state *tune_state = &state->tune_state;
12699a0bf528SMauro Carvalho Chehab 	int ret = 0;
12709a0bf528SMauro Carvalho Chehab 	u16 reg, upd_demod_gain_period = 0x8000;
12719a0bf528SMauro Carvalho Chehab 
12729a0bf528SMauro Carvalho Chehab 	switch (*tune_state) {
12739a0bf528SMauro Carvalho Chehab 	case CT_AGC_START:
12749a0bf528SMauro Carvalho Chehab 		// set power-up level: interf+analog+AGC
12759a0bf528SMauro Carvalho Chehab 
12769a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090)
12779a0bf528SMauro Carvalho Chehab 			dib8000_set_adc_state(state, DIBX000_ADC_ON);
12789a0bf528SMauro Carvalho Chehab 		else {
12799a0bf528SMauro Carvalho Chehab 			dib8000_set_power_mode(state, DIB8000_POWER_ALL);
12809a0bf528SMauro Carvalho Chehab 
12819a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1947)&0xff00;
12829a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1946,
12839a0bf528SMauro Carvalho Chehab 					upd_demod_gain_period & 0xFFFF);
12849a0bf528SMauro Carvalho Chehab 			/* bit 14 = enDemodGain */
12859a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1947, reg | (1<<14) |
12869a0bf528SMauro Carvalho Chehab 					((upd_demod_gain_period >> 16) & 0xFF));
12879a0bf528SMauro Carvalho Chehab 
12889a0bf528SMauro Carvalho Chehab 			/* enable adc i & q */
12899a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1920);
12909a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1920, (reg | 0x3) &
12919a0bf528SMauro Carvalho Chehab 					(~(1 << 7)));
12929a0bf528SMauro Carvalho Chehab 		}
12939a0bf528SMauro Carvalho Chehab 
12949a0bf528SMauro Carvalho Chehab 		if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
12959a0bf528SMauro Carvalho Chehab 			*tune_state = CT_AGC_STOP;
12969a0bf528SMauro Carvalho Chehab 			state->status = FE_STATUS_TUNE_FAILED;
12979a0bf528SMauro Carvalho Chehab 			break;
12989a0bf528SMauro Carvalho Chehab 		}
12999a0bf528SMauro Carvalho Chehab 
13009a0bf528SMauro Carvalho Chehab 		ret = 70;
13019a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STEP_0;
13029a0bf528SMauro Carvalho Chehab 		break;
13039a0bf528SMauro Carvalho Chehab 
13049a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_0:
13059a0bf528SMauro Carvalho Chehab 		//AGC initialization
13069a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
13079a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(fe, 1);
13089a0bf528SMauro Carvalho Chehab 
13099a0bf528SMauro Carvalho Chehab 		dib8000_restart_agc(state);
13109a0bf528SMauro Carvalho Chehab 
13119a0bf528SMauro Carvalho Chehab 		// wait AGC rough lock time
13129a0bf528SMauro Carvalho Chehab 		ret = 50;
13139a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STEP_1;
13149a0bf528SMauro Carvalho Chehab 		break;
13159a0bf528SMauro Carvalho Chehab 
13169a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_1:
13179a0bf528SMauro Carvalho Chehab 		// wait AGC accurate lock time
13189a0bf528SMauro Carvalho Chehab 		ret = 70;
13199a0bf528SMauro Carvalho Chehab 
13209a0bf528SMauro Carvalho Chehab 		if (dib8000_update_lna(state))
13219a0bf528SMauro Carvalho Chehab 			// wait only AGC rough lock time
13229a0bf528SMauro Carvalho Chehab 			ret = 50;
13239a0bf528SMauro Carvalho Chehab 		else
13249a0bf528SMauro Carvalho Chehab 			*tune_state = CT_AGC_STEP_2;
13259a0bf528SMauro Carvalho Chehab 		break;
13269a0bf528SMauro Carvalho Chehab 
13279a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_2:
13289a0bf528SMauro Carvalho Chehab 		dib8000_agc_soft_split(state);
13299a0bf528SMauro Carvalho Chehab 
13309a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
13319a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(fe, 0);
13329a0bf528SMauro Carvalho Chehab 
13339a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STOP;
13349a0bf528SMauro Carvalho Chehab 		break;
13359a0bf528SMauro Carvalho Chehab 	default:
13369a0bf528SMauro Carvalho Chehab 		ret = dib8000_agc_soft_split(state);
13379a0bf528SMauro Carvalho Chehab 		break;
13389a0bf528SMauro Carvalho Chehab 	}
13399a0bf528SMauro Carvalho Chehab 	return ret;
13409a0bf528SMauro Carvalho Chehab 
13419a0bf528SMauro Carvalho Chehab }
13429a0bf528SMauro Carvalho Chehab 
13439a0bf528SMauro Carvalho Chehab static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
13449a0bf528SMauro Carvalho Chehab {
13459a0bf528SMauro Carvalho Chehab 	u16 reg;
13469a0bf528SMauro Carvalho Chehab 
13479a0bf528SMauro Carvalho Chehab 	drive &= 0x7;
13489a0bf528SMauro Carvalho Chehab 
13499a0bf528SMauro Carvalho Chehab 	/* drive host bus 2, 3, 4 */
13509a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1798) &
13519a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
13529a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
13539a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1798, reg);
13549a0bf528SMauro Carvalho Chehab 
13559a0bf528SMauro Carvalho Chehab 	/* drive host bus 5,6 */
13569a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
13579a0bf528SMauro Carvalho Chehab 	reg |= (drive<<8) | (drive<<2);
13589a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1799, reg);
13599a0bf528SMauro Carvalho Chehab 
13609a0bf528SMauro Carvalho Chehab 	/* drive host bus 7, 8, 9 */
13619a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1800) &
13629a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
13639a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
13649a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1800, reg);
13659a0bf528SMauro Carvalho Chehab 
13669a0bf528SMauro Carvalho Chehab 	/* drive host bus 10, 11 */
13679a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
13689a0bf528SMauro Carvalho Chehab 	reg |= (drive<<8) | (drive<<2);
13699a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1801, reg);
13709a0bf528SMauro Carvalho Chehab 
13719a0bf528SMauro Carvalho Chehab 	/* drive host bus 12, 13, 14 */
13729a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1802) &
13739a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
13749a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
13759a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1802, reg);
13769a0bf528SMauro Carvalho Chehab }
13779a0bf528SMauro Carvalho Chehab 
13789a0bf528SMauro Carvalho Chehab static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
13799a0bf528SMauro Carvalho Chehab 		u32 insertExtSynchro, u32 syncSize)
13809a0bf528SMauro Carvalho Chehab {
13819a0bf528SMauro Carvalho Chehab 	u32 quantif = 3;
13829a0bf528SMauro Carvalho Chehab 	u32 nom = (insertExtSynchro * P_Kin+syncSize);
13839a0bf528SMauro Carvalho Chehab 	u32 denom = P_Kout;
13849a0bf528SMauro Carvalho Chehab 	u32 syncFreq = ((nom << quantif) / denom);
13859a0bf528SMauro Carvalho Chehab 
13869a0bf528SMauro Carvalho Chehab 	if ((syncFreq & ((1 << quantif) - 1)) != 0)
13879a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif) + 1;
13889a0bf528SMauro Carvalho Chehab 	else
13899a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif);
13909a0bf528SMauro Carvalho Chehab 
13919a0bf528SMauro Carvalho Chehab 	if (syncFreq != 0)
13929a0bf528SMauro Carvalho Chehab 		syncFreq = syncFreq - 1;
13939a0bf528SMauro Carvalho Chehab 
13949a0bf528SMauro Carvalho Chehab 	return syncFreq;
13959a0bf528SMauro Carvalho Chehab }
13969a0bf528SMauro Carvalho Chehab 
13979a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
13989a0bf528SMauro Carvalho Chehab 		u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
13999a0bf528SMauro Carvalho Chehab 		u32 syncWord, u32 syncSize)
14009a0bf528SMauro Carvalho Chehab {
14019a0bf528SMauro Carvalho Chehab 	dprintk("Configure DibStream Tx");
14029a0bf528SMauro Carvalho Chehab 
14039a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1615, 1);
14049a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1603, P_Kin);
14059a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1605, P_Kout);
14069a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1606, insertExtSynchro);
14079a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1608, synchroMode);
14089a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
14099a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1610, syncWord & 0xffff);
14109a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1612, syncSize);
14119a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1615, 0);
14129a0bf528SMauro Carvalho Chehab }
14139a0bf528SMauro Carvalho Chehab 
14149a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
14159a0bf528SMauro Carvalho Chehab 		u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
14169a0bf528SMauro Carvalho Chehab 		u32 syncWord, u32 syncSize, u32 dataOutRate)
14179a0bf528SMauro Carvalho Chehab {
14189a0bf528SMauro Carvalho Chehab 	u32 syncFreq;
14199a0bf528SMauro Carvalho Chehab 
14209a0bf528SMauro Carvalho Chehab 	dprintk("Configure DibStream Rx synchroMode = %d", synchroMode);
14219a0bf528SMauro Carvalho Chehab 
14229a0bf528SMauro Carvalho Chehab 	if ((P_Kin != 0) && (P_Kout != 0)) {
14239a0bf528SMauro Carvalho Chehab 		syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
14249a0bf528SMauro Carvalho Chehab 				insertExtSynchro, syncSize);
14259a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1542, syncFreq);
14269a0bf528SMauro Carvalho Chehab 	}
14279a0bf528SMauro Carvalho Chehab 
14289a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1554, 1);
14299a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1536, P_Kin);
14309a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1537, P_Kout);
14319a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1539, synchroMode);
14329a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
14339a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1541, syncWord & 0xffff);
14349a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1543, syncSize);
14359a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1544, dataOutRate);
14369a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1554, 0);
14379a0bf528SMauro Carvalho Chehab }
14389a0bf528SMauro Carvalho Chehab 
14399a0bf528SMauro Carvalho Chehab static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
14409a0bf528SMauro Carvalho Chehab {
14419a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
14429a0bf528SMauro Carvalho Chehab 
14439a0bf528SMauro Carvalho Chehab 	reg_1287 = dib8000_read_word(state, 1287);
14449a0bf528SMauro Carvalho Chehab 
14459a0bf528SMauro Carvalho Chehab 	switch (onoff) {
14469a0bf528SMauro Carvalho Chehab 	case 1:
14479a0bf528SMauro Carvalho Chehab 			reg_1287 &= ~(1 << 8);
14489a0bf528SMauro Carvalho Chehab 			break;
14499a0bf528SMauro Carvalho Chehab 	case 0:
14509a0bf528SMauro Carvalho Chehab 			reg_1287 |= (1 << 8);
14519a0bf528SMauro Carvalho Chehab 			break;
14529a0bf528SMauro Carvalho Chehab 	}
14539a0bf528SMauro Carvalho Chehab 
14549a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1287, reg_1287);
14559a0bf528SMauro Carvalho Chehab }
14569a0bf528SMauro Carvalho Chehab 
14579a0bf528SMauro Carvalho Chehab static void dib8096p_configMpegMux(struct dib8000_state *state,
14589a0bf528SMauro Carvalho Chehab 		u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
14599a0bf528SMauro Carvalho Chehab {
14609a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
14619a0bf528SMauro Carvalho Chehab 
14629a0bf528SMauro Carvalho Chehab 	dprintk("Enable Mpeg mux");
14639a0bf528SMauro Carvalho Chehab 
14649a0bf528SMauro Carvalho Chehab 	dib8096p_enMpegMux(state, 0);
14659a0bf528SMauro Carvalho Chehab 
14669a0bf528SMauro Carvalho Chehab 	/* If the input mode is MPEG do not divide the serial clock */
14679a0bf528SMauro Carvalho Chehab 	if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
14689a0bf528SMauro Carvalho Chehab 		enSerialClkDiv2 = 0;
14699a0bf528SMauro Carvalho Chehab 
14709a0bf528SMauro Carvalho Chehab 	reg_1287 = ((pulseWidth & 0x1f) << 3) |
14719a0bf528SMauro Carvalho Chehab 		((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
14729a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1287, reg_1287);
14739a0bf528SMauro Carvalho Chehab 
14749a0bf528SMauro Carvalho Chehab 	dib8096p_enMpegMux(state, 1);
14759a0bf528SMauro Carvalho Chehab }
14769a0bf528SMauro Carvalho Chehab 
14779a0bf528SMauro Carvalho Chehab static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
14789a0bf528SMauro Carvalho Chehab {
14799a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
14809a0bf528SMauro Carvalho Chehab 
14819a0bf528SMauro Carvalho Chehab 	switch (mode) {
14829a0bf528SMauro Carvalho Chehab 	case MPEG_ON_DIBTX:
14839a0bf528SMauro Carvalho Chehab 			dprintk("SET MPEG ON DIBSTREAM TX");
14849a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
14859a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 9); break;
14869a0bf528SMauro Carvalho Chehab 	case DIV_ON_DIBTX:
14879a0bf528SMauro Carvalho Chehab 			dprintk("SET DIV_OUT ON DIBSTREAM TX");
14889a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
14899a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 8); break;
14909a0bf528SMauro Carvalho Chehab 	case ADC_ON_DIBTX:
14919a0bf528SMauro Carvalho Chehab 			dprintk("SET ADC_OUT ON DIBSTREAM TX");
14929a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
14939a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 7); break;
14949a0bf528SMauro Carvalho Chehab 	default:
14959a0bf528SMauro Carvalho Chehab 			break;
14969a0bf528SMauro Carvalho Chehab 	}
14979a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1288, reg_1288);
14989a0bf528SMauro Carvalho Chehab }
14999a0bf528SMauro Carvalho Chehab 
15009a0bf528SMauro Carvalho Chehab static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
15019a0bf528SMauro Carvalho Chehab {
15029a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
15039a0bf528SMauro Carvalho Chehab 
15049a0bf528SMauro Carvalho Chehab 	switch (mode) {
15059a0bf528SMauro Carvalho Chehab 	case DEMOUT_ON_HOSTBUS:
15069a0bf528SMauro Carvalho Chehab 			dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
15079a0bf528SMauro Carvalho Chehab 			dib8096p_enMpegMux(state, 0);
15089a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 6);
15099a0bf528SMauro Carvalho Chehab 			break;
15109a0bf528SMauro Carvalho Chehab 	case DIBTX_ON_HOSTBUS:
15119a0bf528SMauro Carvalho Chehab 			dprintk("SET DIBSTREAM TX ON HOST BUS");
15129a0bf528SMauro Carvalho Chehab 			dib8096p_enMpegMux(state, 0);
15139a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 5);
15149a0bf528SMauro Carvalho Chehab 			break;
15159a0bf528SMauro Carvalho Chehab 	case MPEG_ON_HOSTBUS:
15169a0bf528SMauro Carvalho Chehab 			dprintk("SET MPEG MUX ON HOST BUS");
15179a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 4);
15189a0bf528SMauro Carvalho Chehab 			break;
15199a0bf528SMauro Carvalho Chehab 	default:
15209a0bf528SMauro Carvalho Chehab 			break;
15219a0bf528SMauro Carvalho Chehab 	}
15229a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1288, reg_1288);
15239a0bf528SMauro Carvalho Chehab }
15249a0bf528SMauro Carvalho Chehab 
15259a0bf528SMauro Carvalho Chehab static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
15269a0bf528SMauro Carvalho Chehab {
15279a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
15289a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
15299a0bf528SMauro Carvalho Chehab 
15309a0bf528SMauro Carvalho Chehab 	switch (onoff) {
15319a0bf528SMauro Carvalho Chehab 	case 0: /* only use the internal way - not the diversity input */
15329a0bf528SMauro Carvalho Chehab 			dprintk("%s mode OFF : by default Enable Mpeg INPUT",
15339a0bf528SMauro Carvalho Chehab 					__func__);
15349a0bf528SMauro Carvalho Chehab 			/* outputRate = 8 */
15359a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
15369a0bf528SMauro Carvalho Chehab 
15379a0bf528SMauro Carvalho Chehab 			/* Do not divide the serial clock of MPEG MUX in
15389a0bf528SMauro Carvalho Chehab 			   SERIAL MODE in case input mode MPEG is used */
15399a0bf528SMauro Carvalho Chehab 			reg_1287 = dib8000_read_word(state, 1287);
15409a0bf528SMauro Carvalho Chehab 			/* enSerialClkDiv2 == 1 ? */
15419a0bf528SMauro Carvalho Chehab 			if ((reg_1287 & 0x1) == 1) {
15429a0bf528SMauro Carvalho Chehab 				/* force enSerialClkDiv2 = 0 */
15439a0bf528SMauro Carvalho Chehab 				reg_1287 &= ~0x1;
15449a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, 1287, reg_1287);
15459a0bf528SMauro Carvalho Chehab 			}
15469a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 1;
15479a0bf528SMauro Carvalho Chehab 			break;
15489a0bf528SMauro Carvalho Chehab 	case 1: /* both ways */
15499a0bf528SMauro Carvalho Chehab 	case 2: /* only the diversity input */
15509a0bf528SMauro Carvalho Chehab 			dprintk("%s ON : Enable diversity INPUT", __func__);
15519a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
15529a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 0;
15539a0bf528SMauro Carvalho Chehab 			break;
15549a0bf528SMauro Carvalho Chehab 	}
15559a0bf528SMauro Carvalho Chehab 
15569a0bf528SMauro Carvalho Chehab 	dib8000_set_diversity_in(state->fe[0], onoff);
15579a0bf528SMauro Carvalho Chehab 	return 0;
15589a0bf528SMauro Carvalho Chehab }
15599a0bf528SMauro Carvalho Chehab 
15609a0bf528SMauro Carvalho Chehab static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
15619a0bf528SMauro Carvalho Chehab {
15629a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
15639a0bf528SMauro Carvalho Chehab 	u16 outreg, smo_mode, fifo_threshold;
15649a0bf528SMauro Carvalho Chehab 	u8 prefer_mpeg_mux_use = 1;
15659a0bf528SMauro Carvalho Chehab 	int ret = 0;
15669a0bf528SMauro Carvalho Chehab 
1567173a64cbSPatrick Boettcher 	state->output_mode = mode;
15689a0bf528SMauro Carvalho Chehab 	dib8096p_host_bus_drive(state, 1);
15699a0bf528SMauro Carvalho Chehab 
15709a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
15719a0bf528SMauro Carvalho Chehab 	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
15729a0bf528SMauro Carvalho Chehab 	outreg   = dib8000_read_word(state, 1286) &
15739a0bf528SMauro Carvalho Chehab 		~((1 << 10) | (0x7 << 6) | (1 << 1));
15749a0bf528SMauro Carvalho Chehab 
15759a0bf528SMauro Carvalho Chehab 	switch (mode) {
15769a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:
15779a0bf528SMauro Carvalho Chehab 			outreg = 0;
15789a0bf528SMauro Carvalho Chehab 			break;
15799a0bf528SMauro Carvalho Chehab 
15809a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:
15819a0bf528SMauro Carvalho Chehab 			if (prefer_mpeg_mux_use) {
15829a0bf528SMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux");
15839a0bf528SMauro Carvalho Chehab 				dib8096p_configMpegMux(state, 3, 1, 1);
15849a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
15859a0bf528SMauro Carvalho Chehab 			} else {/* Use Smooth block */
15869a0bf528SMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc");
15879a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state,
15889a0bf528SMauro Carvalho Chehab 						DEMOUT_ON_HOSTBUS);
15899a0bf528SMauro Carvalho Chehab 				outreg |= (2 << 6) | (0 << 1);
15909a0bf528SMauro Carvalho Chehab 			}
15919a0bf528SMauro Carvalho Chehab 			break;
15929a0bf528SMauro Carvalho Chehab 
15939a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:
15949a0bf528SMauro Carvalho Chehab 			if (prefer_mpeg_mux_use) {
15959a0bf528SMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
15969a0bf528SMauro Carvalho Chehab 				dib8096p_configMpegMux(state, 2, 0, 0);
15979a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
15989a0bf528SMauro Carvalho Chehab 			} else { /* Use Smooth block */
15999a0bf528SMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block");
16009a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state,
16019a0bf528SMauro Carvalho Chehab 						DEMOUT_ON_HOSTBUS);
16029a0bf528SMauro Carvalho Chehab 				outreg |= (0 << 6);
16039a0bf528SMauro Carvalho Chehab 			}
16049a0bf528SMauro Carvalho Chehab 			break;
16059a0bf528SMauro Carvalho Chehab 
16069a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
16079a0bf528SMauro Carvalho Chehab 			dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block");
16089a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
16099a0bf528SMauro Carvalho Chehab 			outreg |= (1 << 6);
16109a0bf528SMauro Carvalho Chehab 			break;
16119a0bf528SMauro Carvalho Chehab 
16129a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:
16139a0bf528SMauro Carvalho Chehab 			/* Using Smooth block because not supported
16149a0bf528SMauro Carvalho Chehab 			   by new Mpeg Mux bloc */
16159a0bf528SMauro Carvalho Chehab 			dprintk("dib8096P setting output mode TS_FIFO using Smooth block");
16169a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
16179a0bf528SMauro Carvalho Chehab 			outreg |= (5 << 6);
16189a0bf528SMauro Carvalho Chehab 			smo_mode |= (3 << 1);
16199a0bf528SMauro Carvalho Chehab 			fifo_threshold = 512;
16209a0bf528SMauro Carvalho Chehab 			break;
16219a0bf528SMauro Carvalho Chehab 
16229a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
16239a0bf528SMauro Carvalho Chehab 			dprintk("dib8096P setting output mode MODE_DIVERSITY");
16249a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
16259a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
16269a0bf528SMauro Carvalho Chehab 			break;
16279a0bf528SMauro Carvalho Chehab 
16289a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
16299a0bf528SMauro Carvalho Chehab 			dprintk("dib8096P setting output mode MODE_ANALOG_ADC");
16309a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
16319a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
16329a0bf528SMauro Carvalho Chehab 			break;
16339a0bf528SMauro Carvalho Chehab 	}
16349a0bf528SMauro Carvalho Chehab 
16359a0bf528SMauro Carvalho Chehab 	if (mode != OUTMODE_HIGH_Z)
16369a0bf528SMauro Carvalho Chehab 		outreg |= (1<<10);
16379a0bf528SMauro Carvalho Chehab 
16389a0bf528SMauro Carvalho Chehab 	dprintk("output_mpeg2_in_188_bytes = %d",
16399a0bf528SMauro Carvalho Chehab 			state->cfg.output_mpeg2_in_188_bytes);
16409a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
16419a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
16429a0bf528SMauro Carvalho Chehab 
16439a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 299, smo_mode);
16449a0bf528SMauro Carvalho Chehab 	/* synchronous fread */
16459a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
16469a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 1286, outreg);
16479a0bf528SMauro Carvalho Chehab 
16489a0bf528SMauro Carvalho Chehab 	return ret;
16499a0bf528SMauro Carvalho Chehab }
16509a0bf528SMauro Carvalho Chehab 
16519a0bf528SMauro Carvalho Chehab static int map_addr_to_serpar_number(struct i2c_msg *msg)
16529a0bf528SMauro Carvalho Chehab {
16539a0bf528SMauro Carvalho Chehab 	if (msg->buf[0] <= 15)
16549a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 1;
16559a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 17)
16569a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 15;
16579a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 16)
16589a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 17;
16599a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 19)
16609a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 16;
16619a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
16629a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 3;
16639a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 28)
16649a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 23;
16659a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 99)
16669a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 99;
16679a0bf528SMauro Carvalho Chehab 	else
16689a0bf528SMauro Carvalho Chehab 		return -EINVAL;
16699a0bf528SMauro Carvalho Chehab 	return 0;
16709a0bf528SMauro Carvalho Chehab }
16719a0bf528SMauro Carvalho Chehab 
16729a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
16739a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
16749a0bf528SMauro Carvalho Chehab {
16759a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
16769a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1;
16779a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
16789a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
16799a0bf528SMauro Carvalho Chehab 
16809a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
16819a0bf528SMauro Carvalho Chehab 		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
16829a0bf528SMauro Carvalho Chehab 		i--;
16839a0bf528SMauro Carvalho Chehab 		if (i == 0)
16849a0bf528SMauro Carvalho Chehab 			dprintk("Tuner ITF: write busy (overflow)");
16859a0bf528SMauro Carvalho Chehab 	}
16869a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
16879a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
16889a0bf528SMauro Carvalho Chehab 
16899a0bf528SMauro Carvalho Chehab 	return num;
16909a0bf528SMauro Carvalho Chehab }
16919a0bf528SMauro Carvalho Chehab 
16929a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
16939a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
16949a0bf528SMauro Carvalho Chehab {
16959a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
16969a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1, n_empty = 1;
16979a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
16989a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
16999a0bf528SMauro Carvalho Chehab 	u16 read_word;
17009a0bf528SMauro Carvalho Chehab 
17019a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
17029a0bf528SMauro Carvalho Chehab 		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
17039a0bf528SMauro Carvalho Chehab 		i--;
17049a0bf528SMauro Carvalho Chehab 		if (i == 0)
17059a0bf528SMauro Carvalho Chehab 			dprintk("TunerITF: read busy (overflow)");
17069a0bf528SMauro Carvalho Chehab 	}
17079a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
17089a0bf528SMauro Carvalho Chehab 
17099a0bf528SMauro Carvalho Chehab 	i = 1000;
17109a0bf528SMauro Carvalho Chehab 	while (n_empty == 1 && i) {
17119a0bf528SMauro Carvalho Chehab 		n_empty = dib8000_read_word(state, 1984)&0x1;
17129a0bf528SMauro Carvalho Chehab 		i--;
17139a0bf528SMauro Carvalho Chehab 		if (i == 0)
17149a0bf528SMauro Carvalho Chehab 			dprintk("TunerITF: read busy (empty)");
17159a0bf528SMauro Carvalho Chehab 	}
17169a0bf528SMauro Carvalho Chehab 
17179a0bf528SMauro Carvalho Chehab 	read_word = dib8000_read_word(state, 1987);
17189a0bf528SMauro Carvalho Chehab 	msg[1].buf[0] = (read_word >> 8) & 0xff;
17199a0bf528SMauro Carvalho Chehab 	msg[1].buf[1] = (read_word) & 0xff;
17209a0bf528SMauro Carvalho Chehab 
17219a0bf528SMauro Carvalho Chehab 	return num;
17229a0bf528SMauro Carvalho Chehab }
17239a0bf528SMauro Carvalho Chehab 
17249a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
17259a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
17269a0bf528SMauro Carvalho Chehab {
17279a0bf528SMauro Carvalho Chehab 	if (map_addr_to_serpar_number(&msg[0]) == 0) {
17289a0bf528SMauro Carvalho Chehab 		if (num == 1) /* write */
17299a0bf528SMauro Carvalho Chehab 			return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
17309a0bf528SMauro Carvalho Chehab 		else /* read */
17319a0bf528SMauro Carvalho Chehab 			return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
17329a0bf528SMauro Carvalho Chehab 	}
17339a0bf528SMauro Carvalho Chehab 	return num;
17349a0bf528SMauro Carvalho Chehab }
17359a0bf528SMauro Carvalho Chehab 
17369a0bf528SMauro Carvalho Chehab static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
17379a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num, u16 apb_address)
17389a0bf528SMauro Carvalho Chehab {
17399a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
17409a0bf528SMauro Carvalho Chehab 	u16 word;
17419a0bf528SMauro Carvalho Chehab 
17429a0bf528SMauro Carvalho Chehab 	if (num == 1) {		/* write */
17439a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, apb_address,
17449a0bf528SMauro Carvalho Chehab 				((msg[0].buf[1] << 8) | (msg[0].buf[2])));
17459a0bf528SMauro Carvalho Chehab 	} else {
17469a0bf528SMauro Carvalho Chehab 		word = dib8000_read_word(state, apb_address);
17479a0bf528SMauro Carvalho Chehab 		msg[1].buf[0] = (word >> 8) & 0xff;
17489a0bf528SMauro Carvalho Chehab 		msg[1].buf[1] = (word) & 0xff;
17499a0bf528SMauro Carvalho Chehab 	}
17509a0bf528SMauro Carvalho Chehab 	return num;
17519a0bf528SMauro Carvalho Chehab }
17529a0bf528SMauro Carvalho Chehab 
17539a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
17549a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
17559a0bf528SMauro Carvalho Chehab {
17569a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
17579a0bf528SMauro Carvalho Chehab 	u16 apb_address = 0, word;
17589a0bf528SMauro Carvalho Chehab 	int i = 0;
17599a0bf528SMauro Carvalho Chehab 
17609a0bf528SMauro Carvalho Chehab 	switch (msg[0].buf[0]) {
17619a0bf528SMauro Carvalho Chehab 	case 0x12:
17629a0bf528SMauro Carvalho Chehab 			apb_address = 1920;
17639a0bf528SMauro Carvalho Chehab 			break;
17649a0bf528SMauro Carvalho Chehab 	case 0x14:
17659a0bf528SMauro Carvalho Chehab 			apb_address = 1921;
17669a0bf528SMauro Carvalho Chehab 			break;
17679a0bf528SMauro Carvalho Chehab 	case 0x24:
17689a0bf528SMauro Carvalho Chehab 			apb_address = 1922;
17699a0bf528SMauro Carvalho Chehab 			break;
17709a0bf528SMauro Carvalho Chehab 	case 0x1a:
17719a0bf528SMauro Carvalho Chehab 			apb_address = 1923;
17729a0bf528SMauro Carvalho Chehab 			break;
17739a0bf528SMauro Carvalho Chehab 	case 0x22:
17749a0bf528SMauro Carvalho Chehab 			apb_address = 1924;
17759a0bf528SMauro Carvalho Chehab 			break;
17769a0bf528SMauro Carvalho Chehab 	case 0x33:
17779a0bf528SMauro Carvalho Chehab 			apb_address = 1926;
17789a0bf528SMauro Carvalho Chehab 			break;
17799a0bf528SMauro Carvalho Chehab 	case 0x34:
17809a0bf528SMauro Carvalho Chehab 			apb_address = 1927;
17819a0bf528SMauro Carvalho Chehab 			break;
17829a0bf528SMauro Carvalho Chehab 	case 0x35:
17839a0bf528SMauro Carvalho Chehab 			apb_address = 1928;
17849a0bf528SMauro Carvalho Chehab 			break;
17859a0bf528SMauro Carvalho Chehab 	case 0x36:
17869a0bf528SMauro Carvalho Chehab 			apb_address = 1929;
17879a0bf528SMauro Carvalho Chehab 			break;
17889a0bf528SMauro Carvalho Chehab 	case 0x37:
17899a0bf528SMauro Carvalho Chehab 			apb_address = 1930;
17909a0bf528SMauro Carvalho Chehab 			break;
17919a0bf528SMauro Carvalho Chehab 	case 0x38:
17929a0bf528SMauro Carvalho Chehab 			apb_address = 1931;
17939a0bf528SMauro Carvalho Chehab 			break;
17949a0bf528SMauro Carvalho Chehab 	case 0x39:
17959a0bf528SMauro Carvalho Chehab 			apb_address = 1932;
17969a0bf528SMauro Carvalho Chehab 			break;
17979a0bf528SMauro Carvalho Chehab 	case 0x2a:
17989a0bf528SMauro Carvalho Chehab 			apb_address = 1935;
17999a0bf528SMauro Carvalho Chehab 			break;
18009a0bf528SMauro Carvalho Chehab 	case 0x2b:
18019a0bf528SMauro Carvalho Chehab 			apb_address = 1936;
18029a0bf528SMauro Carvalho Chehab 			break;
18039a0bf528SMauro Carvalho Chehab 	case 0x2c:
18049a0bf528SMauro Carvalho Chehab 			apb_address = 1937;
18059a0bf528SMauro Carvalho Chehab 			break;
18069a0bf528SMauro Carvalho Chehab 	case 0x2d:
18079a0bf528SMauro Carvalho Chehab 			apb_address = 1938;
18089a0bf528SMauro Carvalho Chehab 			break;
18099a0bf528SMauro Carvalho Chehab 	case 0x2e:
18109a0bf528SMauro Carvalho Chehab 			apb_address = 1939;
18119a0bf528SMauro Carvalho Chehab 			break;
18129a0bf528SMauro Carvalho Chehab 	case 0x2f:
18139a0bf528SMauro Carvalho Chehab 			apb_address = 1940;
18149a0bf528SMauro Carvalho Chehab 			break;
18159a0bf528SMauro Carvalho Chehab 	case 0x30:
18169a0bf528SMauro Carvalho Chehab 			apb_address = 1941;
18179a0bf528SMauro Carvalho Chehab 			break;
18189a0bf528SMauro Carvalho Chehab 	case 0x31:
18199a0bf528SMauro Carvalho Chehab 			apb_address = 1942;
18209a0bf528SMauro Carvalho Chehab 			break;
18219a0bf528SMauro Carvalho Chehab 	case 0x32:
18229a0bf528SMauro Carvalho Chehab 			apb_address = 1943;
18239a0bf528SMauro Carvalho Chehab 			break;
18249a0bf528SMauro Carvalho Chehab 	case 0x3e:
18259a0bf528SMauro Carvalho Chehab 			apb_address = 1944;
18269a0bf528SMauro Carvalho Chehab 			break;
18279a0bf528SMauro Carvalho Chehab 	case 0x3f:
18289a0bf528SMauro Carvalho Chehab 			apb_address = 1945;
18299a0bf528SMauro Carvalho Chehab 			break;
18309a0bf528SMauro Carvalho Chehab 	case 0x40:
18319a0bf528SMauro Carvalho Chehab 			apb_address = 1948;
18329a0bf528SMauro Carvalho Chehab 			break;
18339a0bf528SMauro Carvalho Chehab 	case 0x25:
18349a0bf528SMauro Carvalho Chehab 			apb_address = 936;
18359a0bf528SMauro Carvalho Chehab 			break;
18369a0bf528SMauro Carvalho Chehab 	case 0x26:
18379a0bf528SMauro Carvalho Chehab 			apb_address = 937;
18389a0bf528SMauro Carvalho Chehab 			break;
18399a0bf528SMauro Carvalho Chehab 	case 0x27:
18409a0bf528SMauro Carvalho Chehab 			apb_address = 938;
18419a0bf528SMauro Carvalho Chehab 			break;
18429a0bf528SMauro Carvalho Chehab 	case 0x28:
18439a0bf528SMauro Carvalho Chehab 			apb_address = 939;
18449a0bf528SMauro Carvalho Chehab 			break;
18459a0bf528SMauro Carvalho Chehab 	case 0x1d:
18469a0bf528SMauro Carvalho Chehab 			/* get sad sel request */
18479a0bf528SMauro Carvalho Chehab 			i = ((dib8000_read_word(state, 921) >> 12)&0x3);
18489a0bf528SMauro Carvalho Chehab 			word = dib8000_read_word(state, 924+i);
18499a0bf528SMauro Carvalho Chehab 			msg[1].buf[0] = (word >> 8) & 0xff;
18509a0bf528SMauro Carvalho Chehab 			msg[1].buf[1] = (word) & 0xff;
18519a0bf528SMauro Carvalho Chehab 			return num;
18529a0bf528SMauro Carvalho Chehab 	case 0x1f:
18539a0bf528SMauro Carvalho Chehab 			if (num == 1) {	/* write */
18549a0bf528SMauro Carvalho Chehab 				word = (u16) ((msg[0].buf[1] << 8) |
18559a0bf528SMauro Carvalho Chehab 						msg[0].buf[2]);
18569a0bf528SMauro Carvalho Chehab 				/* in the VGAMODE Sel are located on bit 0/1 */
18579a0bf528SMauro Carvalho Chehab 				word &= 0x3;
18589a0bf528SMauro Carvalho Chehab 				word = (dib8000_read_word(state, 921) &
18599a0bf528SMauro Carvalho Chehab 						~(3<<12)) | (word<<12);
18609a0bf528SMauro Carvalho Chehab 				/* Set the proper input */
18619a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, 921, word);
18629a0bf528SMauro Carvalho Chehab 				return num;
18639a0bf528SMauro Carvalho Chehab 			}
18649a0bf528SMauro Carvalho Chehab 	}
18659a0bf528SMauro Carvalho Chehab 
18669a0bf528SMauro Carvalho Chehab 	if (apb_address != 0) /* R/W acces via APB */
18679a0bf528SMauro Carvalho Chehab 		return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
18689a0bf528SMauro Carvalho Chehab 	else  /* R/W access via SERPAR  */
18699a0bf528SMauro Carvalho Chehab 		return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
18709a0bf528SMauro Carvalho Chehab 
18719a0bf528SMauro Carvalho Chehab 	return 0;
18729a0bf528SMauro Carvalho Chehab }
18739a0bf528SMauro Carvalho Chehab 
18749a0bf528SMauro Carvalho Chehab static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
18759a0bf528SMauro Carvalho Chehab {
18769a0bf528SMauro Carvalho Chehab 	return I2C_FUNC_I2C;
18779a0bf528SMauro Carvalho Chehab }
18789a0bf528SMauro Carvalho Chehab 
18799a0bf528SMauro Carvalho Chehab static struct i2c_algorithm dib8096p_tuner_xfer_algo = {
18809a0bf528SMauro Carvalho Chehab 	.master_xfer = dib8096p_tuner_xfer,
18819a0bf528SMauro Carvalho Chehab 	.functionality = dib8096p_i2c_func,
18829a0bf528SMauro Carvalho Chehab };
18839a0bf528SMauro Carvalho Chehab 
18849a0bf528SMauro Carvalho Chehab struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
18859a0bf528SMauro Carvalho Chehab {
18869a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
18879a0bf528SMauro Carvalho Chehab 	return &st->dib8096p_tuner_adap;
18889a0bf528SMauro Carvalho Chehab }
18899a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8096p_get_i2c_tuner);
18909a0bf528SMauro Carvalho Chehab 
18919a0bf528SMauro Carvalho Chehab int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
18929a0bf528SMauro Carvalho Chehab {
18939a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
18949a0bf528SMauro Carvalho Chehab 	u16 en_cur_state;
18959a0bf528SMauro Carvalho Chehab 
18969a0bf528SMauro Carvalho Chehab 	dprintk("sleep dib8096p: %d", onoff);
18979a0bf528SMauro Carvalho Chehab 
18989a0bf528SMauro Carvalho Chehab 	en_cur_state = dib8000_read_word(state, 1922);
18999a0bf528SMauro Carvalho Chehab 
19009a0bf528SMauro Carvalho Chehab 	/* LNAs and MIX are ON and therefore it is a valid configuration */
19019a0bf528SMauro Carvalho Chehab 	if (en_cur_state > 0xff)
19029a0bf528SMauro Carvalho Chehab 		state->tuner_enable = en_cur_state ;
19039a0bf528SMauro Carvalho Chehab 
19049a0bf528SMauro Carvalho Chehab 	if (onoff)
19059a0bf528SMauro Carvalho Chehab 		en_cur_state &= 0x00ff;
19069a0bf528SMauro Carvalho Chehab 	else {
19079a0bf528SMauro Carvalho Chehab 		if (state->tuner_enable != 0)
19089a0bf528SMauro Carvalho Chehab 			en_cur_state = state->tuner_enable;
19099a0bf528SMauro Carvalho Chehab 	}
19109a0bf528SMauro Carvalho Chehab 
19119a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1922, en_cur_state);
19129a0bf528SMauro Carvalho Chehab 
19139a0bf528SMauro Carvalho Chehab 	return 0;
19149a0bf528SMauro Carvalho Chehab }
19159a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8096p_tuner_sleep);
19169a0bf528SMauro Carvalho Chehab 
19179a0bf528SMauro Carvalho Chehab static const s32 lut_1000ln_mant[] =
19189a0bf528SMauro Carvalho Chehab {
19199a0bf528SMauro Carvalho Chehab 	908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
19209a0bf528SMauro Carvalho Chehab };
19219a0bf528SMauro Carvalho Chehab 
19229a0bf528SMauro Carvalho Chehab s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
19239a0bf528SMauro Carvalho Chehab {
19249a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
19259a0bf528SMauro Carvalho Chehab 	u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
19269a0bf528SMauro Carvalho Chehab 	s32 val;
19279a0bf528SMauro Carvalho Chehab 
19289a0bf528SMauro Carvalho Chehab 	val = dib8000_read32(state, 384);
19299a0bf528SMauro Carvalho Chehab 	if (mode) {
19309a0bf528SMauro Carvalho Chehab 		tmp_val = val;
19319a0bf528SMauro Carvalho Chehab 		while (tmp_val >>= 1)
19329a0bf528SMauro Carvalho Chehab 			exp++;
19339a0bf528SMauro Carvalho Chehab 		mant = (val * 1000 / (1<<exp));
19349a0bf528SMauro Carvalho Chehab 		ix = (u8)((mant-1000)/100); /* index of the LUT */
19359a0bf528SMauro Carvalho Chehab 		val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
19369a0bf528SMauro Carvalho Chehab 		val = (val*256)/1000;
19379a0bf528SMauro Carvalho Chehab 	}
19389a0bf528SMauro Carvalho Chehab 	return val;
19399a0bf528SMauro Carvalho Chehab }
19409a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_get_adc_power);
19419a0bf528SMauro Carvalho Chehab 
19429a0bf528SMauro Carvalho Chehab int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
19439a0bf528SMauro Carvalho Chehab {
19449a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
19459a0bf528SMauro Carvalho Chehab 	int val = 0;
19469a0bf528SMauro Carvalho Chehab 
19479a0bf528SMauro Carvalho Chehab 	switch (IQ) {
19489a0bf528SMauro Carvalho Chehab 	case 1:
19499a0bf528SMauro Carvalho Chehab 			val = dib8000_read_word(state, 403);
19509a0bf528SMauro Carvalho Chehab 			break;
19519a0bf528SMauro Carvalho Chehab 	case 0:
19529a0bf528SMauro Carvalho Chehab 			val = dib8000_read_word(state, 404);
19539a0bf528SMauro Carvalho Chehab 			break;
19549a0bf528SMauro Carvalho Chehab 	}
19559a0bf528SMauro Carvalho Chehab 	if (val  & 0x200)
19569a0bf528SMauro Carvalho Chehab 		val -= 1024;
19579a0bf528SMauro Carvalho Chehab 
19589a0bf528SMauro Carvalho Chehab 	return val;
19599a0bf528SMauro Carvalho Chehab }
19609a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8090p_get_dc_power);
19619a0bf528SMauro Carvalho Chehab 
19629a0bf528SMauro Carvalho Chehab static void dib8000_update_timf(struct dib8000_state *state)
19639a0bf528SMauro Carvalho Chehab {
19649a0bf528SMauro Carvalho Chehab 	u32 timf = state->timf = dib8000_read32(state, 435);
19659a0bf528SMauro Carvalho Chehab 
19669a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 29, (u16) (timf >> 16));
19679a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 30, (u16) (timf & 0xffff));
19689a0bf528SMauro Carvalho Chehab 	dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
19699a0bf528SMauro Carvalho Chehab }
19709a0bf528SMauro Carvalho Chehab 
19719a0bf528SMauro Carvalho Chehab u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
19729a0bf528SMauro Carvalho Chehab {
19739a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
19749a0bf528SMauro Carvalho Chehab 
19759a0bf528SMauro Carvalho Chehab 	switch (op) {
19769a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_SET:
19779a0bf528SMauro Carvalho Chehab 			state->timf = timf;
19789a0bf528SMauro Carvalho Chehab 			break;
19799a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_UPDATE:
19809a0bf528SMauro Carvalho Chehab 			dib8000_update_timf(state);
19819a0bf528SMauro Carvalho Chehab 			break;
19829a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_GET:
19839a0bf528SMauro Carvalho Chehab 			break;
19849a0bf528SMauro Carvalho Chehab 	}
19859a0bf528SMauro Carvalho Chehab 	dib8000_set_bandwidth(state->fe[0], 6000);
19869a0bf528SMauro Carvalho Chehab 
19879a0bf528SMauro Carvalho Chehab 	return state->timf;
19889a0bf528SMauro Carvalho Chehab }
19899a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_ctrl_timf);
19909a0bf528SMauro Carvalho Chehab 
19919a0bf528SMauro Carvalho Chehab static const u16 adc_target_16dB[11] = {
19929a0bf528SMauro Carvalho Chehab 	(1 << 13) - 825 - 117,
19939a0bf528SMauro Carvalho Chehab 	(1 << 13) - 837 - 117,
19949a0bf528SMauro Carvalho Chehab 	(1 << 13) - 811 - 117,
19959a0bf528SMauro Carvalho Chehab 	(1 << 13) - 766 - 117,
19969a0bf528SMauro Carvalho Chehab 	(1 << 13) - 737 - 117,
19979a0bf528SMauro Carvalho Chehab 	(1 << 13) - 693 - 117,
19989a0bf528SMauro Carvalho Chehab 	(1 << 13) - 648 - 117,
19999a0bf528SMauro Carvalho Chehab 	(1 << 13) - 619 - 117,
20009a0bf528SMauro Carvalho Chehab 	(1 << 13) - 575 - 117,
20019a0bf528SMauro Carvalho Chehab 	(1 << 13) - 531 - 117,
20029a0bf528SMauro Carvalho Chehab 	(1 << 13) - 501 - 117
20039a0bf528SMauro Carvalho Chehab };
20049a0bf528SMauro Carvalho Chehab static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
20059a0bf528SMauro Carvalho Chehab 
2006173a64cbSPatrick Boettcher static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
20079a0bf528SMauro Carvalho Chehab {
2008173a64cbSPatrick Boettcher 	u8  cr, constellation, time_intlv;
2009c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
20109a0bf528SMauro Carvalho Chehab 
2011c82056d0SMauro Carvalho Chehab 	switch (c->layer[layer_index].modulation) {
20129a0bf528SMauro Carvalho Chehab 	case DQPSK:
20139a0bf528SMauro Carvalho Chehab 			constellation = 0;
20149a0bf528SMauro Carvalho Chehab 			break;
20159a0bf528SMauro Carvalho Chehab 	case  QPSK:
20169a0bf528SMauro Carvalho Chehab 			constellation = 1;
20179a0bf528SMauro Carvalho Chehab 			break;
20189a0bf528SMauro Carvalho Chehab 	case QAM_16:
20199a0bf528SMauro Carvalho Chehab 			constellation = 2;
20209a0bf528SMauro Carvalho Chehab 			break;
20219a0bf528SMauro Carvalho Chehab 	case QAM_64:
20229a0bf528SMauro Carvalho Chehab 	default:
20239a0bf528SMauro Carvalho Chehab 			constellation = 3;
20249a0bf528SMauro Carvalho Chehab 			break;
20259a0bf528SMauro Carvalho Chehab 	}
20269a0bf528SMauro Carvalho Chehab 
2027c82056d0SMauro Carvalho Chehab 	switch (c->layer[layer_index].fec) {
20289a0bf528SMauro Carvalho Chehab 	case FEC_1_2:
2029173a64cbSPatrick Boettcher 			cr = 1;
20309a0bf528SMauro Carvalho Chehab 			break;
20319a0bf528SMauro Carvalho Chehab 	case FEC_2_3:
2032173a64cbSPatrick Boettcher 			cr = 2;
20339a0bf528SMauro Carvalho Chehab 			break;
20349a0bf528SMauro Carvalho Chehab 	case FEC_3_4:
2035173a64cbSPatrick Boettcher 			cr = 3;
20369a0bf528SMauro Carvalho Chehab 			break;
20379a0bf528SMauro Carvalho Chehab 	case FEC_5_6:
2038173a64cbSPatrick Boettcher 			cr = 5;
20399a0bf528SMauro Carvalho Chehab 			break;
20409a0bf528SMauro Carvalho Chehab 	case FEC_7_8:
20419a0bf528SMauro Carvalho Chehab 	default:
2042173a64cbSPatrick Boettcher 			cr = 7;
20439a0bf528SMauro Carvalho Chehab 			break;
20449a0bf528SMauro Carvalho Chehab 	}
20459a0bf528SMauro Carvalho Chehab 
2046c82056d0SMauro Carvalho Chehab 	if ((c->layer[layer_index].interleaving > 0) && ((c->layer[layer_index].interleaving <= 3) || (c->layer[layer_index].interleaving == 4 && c->isdbt_sb_mode == 1)))
2047c82056d0SMauro Carvalho Chehab 		time_intlv = c->layer[layer_index].interleaving;
20489a0bf528SMauro Carvalho Chehab 	else
2049173a64cbSPatrick Boettcher 		time_intlv = 0;
2050173a64cbSPatrick Boettcher 
2051c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
2052c82056d0SMauro Carvalho Chehab 	if (c->layer[layer_index].segment_count > 0) {
20539a0bf528SMauro Carvalho Chehab 		switch (max_constellation) {
20549a0bf528SMauro Carvalho Chehab 		case DQPSK:
20559a0bf528SMauro Carvalho Chehab 		case QPSK:
2056c82056d0SMauro Carvalho Chehab 				if (c->layer[layer_index].modulation == QAM_16 || c->layer[layer_index].modulation == QAM_64)
2057c82056d0SMauro Carvalho Chehab 					max_constellation = c->layer[layer_index].modulation;
20589a0bf528SMauro Carvalho Chehab 				break;
20599a0bf528SMauro Carvalho Chehab 		case QAM_16:
2060c82056d0SMauro Carvalho Chehab 				if (c->layer[layer_index].modulation == QAM_64)
2061c82056d0SMauro Carvalho Chehab 					max_constellation = c->layer[layer_index].modulation;
20629a0bf528SMauro Carvalho Chehab 				break;
20639a0bf528SMauro Carvalho Chehab 		}
20649a0bf528SMauro Carvalho Chehab 	}
2065173a64cbSPatrick Boettcher 
2066173a64cbSPatrick Boettcher 	return  max_constellation;
20679a0bf528SMauro Carvalho Chehab }
20689a0bf528SMauro Carvalho Chehab 
2069173a64cbSPatrick 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 */
2070173a64cbSPatrick 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 */
2071173a64cbSPatrick 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 */
2072173a64cbSPatrick Boettcher static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation)
2073173a64cbSPatrick Boettcher {
2074173a64cbSPatrick Boettcher 	u16 i, ana_gain = 0;
2075173a64cbSPatrick Boettcher 	const u16 *adp;
20769a0bf528SMauro Carvalho Chehab 
2077173a64cbSPatrick Boettcher 	/* channel estimation fine configuration */
2078173a64cbSPatrick Boettcher 	switch (max_constellation) {
2079173a64cbSPatrick Boettcher 	case QAM_64:
2080173a64cbSPatrick Boettcher 			ana_gain = 0x7;
2081173a64cbSPatrick Boettcher 			adp = &adp_Q64[0];
2082173a64cbSPatrick Boettcher 			break;
2083173a64cbSPatrick Boettcher 	case QAM_16:
2084173a64cbSPatrick Boettcher 			ana_gain = 0x7;
2085173a64cbSPatrick Boettcher 			adp = &adp_Q16[0];
2086173a64cbSPatrick Boettcher 			break;
2087173a64cbSPatrick Boettcher 	default:
2088173a64cbSPatrick Boettcher 			ana_gain = 0;
2089173a64cbSPatrick Boettcher 			adp = &adp_Qdefault[0];
2090173a64cbSPatrick Boettcher 			break;
20919a0bf528SMauro Carvalho Chehab 	}
20929a0bf528SMauro Carvalho Chehab 
2093173a64cbSPatrick Boettcher 	for (i = 0; i < 4; i++)
2094173a64cbSPatrick Boettcher 		dib8000_write_word(state, 215 + i, adp[i]);
20959a0bf528SMauro Carvalho Chehab 
2096173a64cbSPatrick Boettcher 	return ana_gain;
2097173a64cbSPatrick Boettcher }
20989a0bf528SMauro Carvalho Chehab 
2099173a64cbSPatrick Boettcher static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain)
2100173a64cbSPatrick Boettcher {
2101173a64cbSPatrick Boettcher 	u16 i;
21029a0bf528SMauro Carvalho Chehab 
2103173a64cbSPatrick Boettcher 	dib8000_write_word(state, 116, ana_gain);
21049a0bf528SMauro Carvalho Chehab 
2105173a64cbSPatrick Boettcher 	/* update ADC target depending on ana_gain */
2106173a64cbSPatrick Boettcher 	if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */
2107173a64cbSPatrick Boettcher 		for (i = 0; i < 10; i++)
2108173a64cbSPatrick Boettcher 			dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
2109173a64cbSPatrick Boettcher 	} else { /* set -22dB ADC target for ana_gain=0 */
2110173a64cbSPatrick Boettcher 		for (i = 0; i < 10; i++)
2111173a64cbSPatrick Boettcher 			dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
2112173a64cbSPatrick Boettcher 	}
2113173a64cbSPatrick Boettcher }
21149a0bf528SMauro Carvalho Chehab 
2115173a64cbSPatrick Boettcher static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
2116173a64cbSPatrick Boettcher {
2117173a64cbSPatrick Boettcher 	u16 mode = 0;
21189a0bf528SMauro Carvalho Chehab 
2119173a64cbSPatrick Boettcher 	if (state->isdbt_cfg_loaded == 0)
2120173a64cbSPatrick Boettcher 		for (mode = 0; mode < 24; mode++)
2121173a64cbSPatrick Boettcher 			dib8000_write_word(state, 117 + mode, ana_fe[mode]);
2122173a64cbSPatrick Boettcher }
21239a0bf528SMauro Carvalho Chehab 
2124173a64cbSPatrick Boettcher static const u16 lut_prbs_2k[14] = {
2125173a64cbSPatrick Boettcher 	0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213
2126173a64cbSPatrick Boettcher };
2127173a64cbSPatrick Boettcher static const u16 lut_prbs_4k[14] = {
2128173a64cbSPatrick Boettcher 	0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E
2129173a64cbSPatrick Boettcher };
2130173a64cbSPatrick Boettcher static const u16 lut_prbs_8k[14] = {
2131173a64cbSPatrick Boettcher 	0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684
2132173a64cbSPatrick Boettcher };
2133173a64cbSPatrick Boettcher 
2134173a64cbSPatrick Boettcher static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
2135173a64cbSPatrick Boettcher {
2136173a64cbSPatrick Boettcher 	int sub_channel_prbs_group = 0;
2137173a64cbSPatrick Boettcher 
2138173a64cbSPatrick Boettcher 	sub_channel_prbs_group = (subchannel / 3) + 1;
2139173a64cbSPatrick Boettcher 	dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]);
2140173a64cbSPatrick Boettcher 
21419a0bf528SMauro Carvalho Chehab 	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
21429a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
2143173a64cbSPatrick Boettcher 			return lut_prbs_2k[sub_channel_prbs_group];
21449a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
2145173a64cbSPatrick Boettcher 			return lut_prbs_4k[sub_channel_prbs_group];
21469a0bf528SMauro Carvalho Chehab 	default:
2147173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2148173a64cbSPatrick Boettcher 			return lut_prbs_8k[sub_channel_prbs_group];
21499a0bf528SMauro Carvalho Chehab 	}
21509a0bf528SMauro Carvalho Chehab }
21519a0bf528SMauro Carvalho Chehab 
2152173a64cbSPatrick Boettcher static void dib8000_set_13seg_channel(struct dib8000_state *state)
2153173a64cbSPatrick Boettcher {
2154173a64cbSPatrick Boettcher 	u16 i;
2155173a64cbSPatrick Boettcher 	u16 coff_pow = 0x2800;
21569a0bf528SMauro Carvalho Chehab 
2157173a64cbSPatrick Boettcher 	state->seg_mask = 0x1fff; /* All 13 segments enabled */
21589a0bf528SMauro Carvalho Chehab 
2159173a64cbSPatrick Boettcher 	/* ---- COFF ---- Carloff, the most robust --- */
2160173a64cbSPatrick Boettcher 	if (state->isdbt_cfg_loaded == 0) {  /* if not Sound Broadcasting mode : put default values for 13 segments */
21619a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 180, (16 << 6) | 9);
21629a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
21639a0bf528SMauro Carvalho Chehab 		coff_pow = 0x2800;
21649a0bf528SMauro Carvalho Chehab 		for (i = 0; i < 6; i++)
21659a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 181+i, coff_pow);
21669a0bf528SMauro Carvalho Chehab 
2167173a64cbSPatrick Boettcher 		/* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */
2168173a64cbSPatrick 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 */
21699a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
21709a0bf528SMauro Carvalho Chehab 
2171173a64cbSPatrick Boettcher 		/* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */
21729a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
2173173a64cbSPatrick Boettcher 		/* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */
21749a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
21759a0bf528SMauro Carvalho Chehab 
2176173a64cbSPatrick Boettcher 		dib8000_write_word(state, 228, 0);  /* default value */
2177173a64cbSPatrick Boettcher 		dib8000_write_word(state, 265, 31); /* default value */
2178173a64cbSPatrick Boettcher 		dib8000_write_word(state, 205, 0x200f); /* init value */
2179173a64cbSPatrick Boettcher 	}
2180173a64cbSPatrick Boettcher 
2181173a64cbSPatrick Boettcher 	/*
2182173a64cbSPatrick Boettcher 	 * make the cpil_coff_lock more robust but slower p_coff_winlen
21839a0bf528SMauro Carvalho Chehab 	 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
21849a0bf528SMauro Carvalho Chehab 	 */
21859a0bf528SMauro Carvalho Chehab 
2186173a64cbSPatrick Boettcher 	if (state->cfg.pll->ifreq == 0)
2187173a64cbSPatrick Boettcher 		dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
21889a0bf528SMauro Carvalho Chehab 
2189173a64cbSPatrick Boettcher 	dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg);
2190173a64cbSPatrick Boettcher }
21919a0bf528SMauro Carvalho Chehab 
2192173a64cbSPatrick Boettcher static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs)
2193173a64cbSPatrick Boettcher {
2194173a64cbSPatrick Boettcher 	u16 reg_1;
21959a0bf528SMauro Carvalho Chehab 
2196173a64cbSPatrick Boettcher 	reg_1 = dib8000_read_word(state, 1);
2197173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */
2198173a64cbSPatrick Boettcher }
21999a0bf528SMauro Carvalho Chehab 
2200173a64cbSPatrick Boettcher static void dib8000_small_fine_tune(struct dib8000_state *state)
2201173a64cbSPatrick Boettcher {
2202173a64cbSPatrick Boettcher 	u16 i;
2203173a64cbSPatrick Boettcher 	const s16 *ncoeff;
2204c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
22059a0bf528SMauro Carvalho Chehab 
2206173a64cbSPatrick Boettcher 	dib8000_write_word(state, 352, state->seg_diff_mask);
2207173a64cbSPatrick Boettcher 	dib8000_write_word(state, 353, state->seg_mask);
22089a0bf528SMauro Carvalho Chehab 
2209173a64cbSPatrick 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 */
2210c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 351, (c->isdbt_sb_mode << 9) | (c->isdbt_sb_mode << 8) | (13 << 4) | 5);
2211173a64cbSPatrick Boettcher 
2212c82056d0SMauro Carvalho Chehab 	if (c->isdbt_sb_mode) {
2213173a64cbSPatrick Boettcher 		/* ---- SMALL ---- */
2214c82056d0SMauro Carvalho Chehab 		switch (c->transmission_mode) {
2215173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_2K:
2216c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2217c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2218173a64cbSPatrick Boettcher 						ncoeff = coeff_2k_sb_1seg_dqpsk;
2219173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2220173a64cbSPatrick Boettcher 						ncoeff = coeff_2k_sb_1seg;
2221173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2222c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2223c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2224173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
2225173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2226173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg_0dqpsk;
2227173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2228c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2229173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg_1dqpsk;
2230173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2231173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg;
2232173a64cbSPatrick Boettcher 					}
2233173a64cbSPatrick Boettcher 				}
22349a0bf528SMauro Carvalho Chehab 				break;
22359a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_4K:
2236c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2237c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2238173a64cbSPatrick Boettcher 						ncoeff = coeff_4k_sb_1seg_dqpsk;
2239173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2240173a64cbSPatrick Boettcher 						ncoeff = coeff_4k_sb_1seg;
2241173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2242c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2243c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2244173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
2245173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2246173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_0dqpsk;
2247173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2248c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2249173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_1dqpsk;
2250173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2251173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg;
2252173a64cbSPatrick Boettcher 					}
2253173a64cbSPatrick Boettcher 				}
22549a0bf528SMauro Carvalho Chehab 				break;
2255173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_AUTO:
2256173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_8K:
22579a0bf528SMauro Carvalho Chehab 		default:
2258c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2259c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2260173a64cbSPatrick Boettcher 						ncoeff = coeff_8k_sb_1seg_dqpsk;
2261173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2262173a64cbSPatrick Boettcher 						ncoeff = coeff_8k_sb_1seg;
2263173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2264c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2265c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2266173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
2267173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2268173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_0dqpsk;
2269173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2270c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2271173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_1dqpsk;
2272173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2273173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg;
2274173a64cbSPatrick Boettcher 					}
2275173a64cbSPatrick Boettcher 				}
22769a0bf528SMauro Carvalho Chehab 				break;
22779a0bf528SMauro Carvalho Chehab 		}
2278173a64cbSPatrick Boettcher 
2279173a64cbSPatrick Boettcher 		for (i = 0; i < 8; i++)
2280173a64cbSPatrick Boettcher 			dib8000_write_word(state, 343 + i, ncoeff[i]);
2281173a64cbSPatrick Boettcher 	}
2282173a64cbSPatrick Boettcher }
2283173a64cbSPatrick Boettcher 
2284173a64cbSPatrick Boettcher static const u16 coff_thres_1seg[3] = {300, 150, 80};
2285173a64cbSPatrick Boettcher static const u16 coff_thres_3seg[3] = {350, 300, 250};
2286173a64cbSPatrick Boettcher static void dib8000_set_sb_channel(struct dib8000_state *state)
2287173a64cbSPatrick Boettcher {
2288c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2289173a64cbSPatrick Boettcher 	const u16 *coff;
2290173a64cbSPatrick Boettcher 	u16 i;
2291173a64cbSPatrick Boettcher 
2292c82056d0SMauro Carvalho Chehab 	if (c->transmission_mode == TRANSMISSION_MODE_2K || c->transmission_mode == TRANSMISSION_MODE_4K) {
2293173a64cbSPatrick Boettcher 		dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */
2294173a64cbSPatrick Boettcher 		dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */
2295173a64cbSPatrick Boettcher 	} else {
2296173a64cbSPatrick Boettcher 		dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */
2297173a64cbSPatrick Boettcher 		dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */
2298173a64cbSPatrick Boettcher 	}
2299173a64cbSPatrick Boettcher 
2300c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 1) /* 3-segments */
2301173a64cbSPatrick Boettcher 		state->seg_mask = 0x00E0;
2302173a64cbSPatrick Boettcher 	else /* 1-segment */
2303173a64cbSPatrick Boettcher 		state->seg_mask = 0x0040;
2304173a64cbSPatrick Boettcher 
2305173a64cbSPatrick Boettcher 	dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2306173a64cbSPatrick Boettcher 
2307173a64cbSPatrick Boettcher 	/* ---- COFF ---- Carloff, the most robust --- */
2308173a64cbSPatrick 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 */
2309c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 187, (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~c->isdbt_partial_reception & 1) << 2) | 0x3);
2310173a64cbSPatrick Boettcher 
2311173a64cbSPatrick Boettcher 	dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */
2312173a64cbSPatrick 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 */
2313173a64cbSPatrick Boettcher 
2314173a64cbSPatrick Boettcher 	/* Sound Broadcasting mode 1 seg */
2315c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 0) {
2316173a64cbSPatrick 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) */
2317173a64cbSPatrick Boettcher 		if (state->mode == 3)
2318173a64cbSPatrick Boettcher 			dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14));
23199a0bf528SMauro Carvalho Chehab 		else
2320173a64cbSPatrick Boettcher 			dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14));
2321173a64cbSPatrick Boettcher 
2322173a64cbSPatrick 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 */
2323173a64cbSPatrick Boettcher 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
2324173a64cbSPatrick Boettcher 		coff = &coff_thres_1seg[0];
2325173a64cbSPatrick Boettcher 	} else {   /* Sound Broadcasting mode 3 seg */
2326173a64cbSPatrick Boettcher 		dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
2327173a64cbSPatrick 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 */
2328173a64cbSPatrick Boettcher 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
2329173a64cbSPatrick Boettcher 		coff = &coff_thres_3seg[0];
2330173a64cbSPatrick Boettcher 	}
2331173a64cbSPatrick Boettcher 
2332173a64cbSPatrick Boettcher 	dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */
2333173a64cbSPatrick Boettcher 	dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */
2334173a64cbSPatrick Boettcher 
2335c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 0 && c->transmission_mode == TRANSMISSION_MODE_2K)
2336173a64cbSPatrick Boettcher 		dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */
2337173a64cbSPatrick Boettcher 
2338173a64cbSPatrick Boettcher 	/* Write COFF thres */
2339173a64cbSPatrick Boettcher 	for (i = 0 ; i < 3; i++) {
2340173a64cbSPatrick Boettcher 		dib8000_write_word(state, 181+i, coff[i]);
2341173a64cbSPatrick Boettcher 		dib8000_write_word(state, 184+i, coff[i]);
2342173a64cbSPatrick Boettcher 	}
2343173a64cbSPatrick Boettcher 
2344173a64cbSPatrick Boettcher 	/*
2345173a64cbSPatrick Boettcher 	 * make the cpil_coff_lock more robust but slower p_coff_winlen
2346173a64cbSPatrick Boettcher 	 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2347173a64cbSPatrick Boettcher 	 */
2348173a64cbSPatrick Boettcher 
2349173a64cbSPatrick Boettcher 	dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */
2350173a64cbSPatrick Boettcher 
2351c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 0)
2352173a64cbSPatrick Boettcher 		dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */
2353173a64cbSPatrick Boettcher 	else
2354173a64cbSPatrick Boettcher 		dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2355173a64cbSPatrick Boettcher }
2356173a64cbSPatrick Boettcher 
2357173a64cbSPatrick Boettcher static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
2358173a64cbSPatrick Boettcher {
2359173a64cbSPatrick Boettcher 	u16 p_cfr_left_edge  = 0, p_cfr_right_edge = 0;
2360173a64cbSPatrick Boettcher 	u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ;
2361173a64cbSPatrick Boettcher 	u16 max_constellation = DQPSK;
2362173a64cbSPatrick Boettcher 	int init_prbs;
2363c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2364173a64cbSPatrick Boettcher 
2365173a64cbSPatrick Boettcher 	/* P_mode */
2366173a64cbSPatrick Boettcher 	dib8000_write_word(state, 10, (seq << 4));
2367173a64cbSPatrick Boettcher 
2368173a64cbSPatrick Boettcher 	/* init mode */
2369173a64cbSPatrick Boettcher 	state->mode = fft_to_mode(state);
2370173a64cbSPatrick Boettcher 
2371173a64cbSPatrick Boettcher 	/* set guard */
2372173a64cbSPatrick Boettcher 	tmp = dib8000_read_word(state, 1);
2373c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3));
2374173a64cbSPatrick Boettcher 
2375c82056d0SMauro 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));
2376173a64cbSPatrick Boettcher 
2377173a64cbSPatrick Boettcher 	/* signal optimization parameter */
2378c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception) {
2379c82056d0SMauro Carvalho Chehab 		state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0];
2380173a64cbSPatrick Boettcher 		for (i = 1; i < 3; i++)
2381c82056d0SMauro Carvalho Chehab 			nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
2382173a64cbSPatrick Boettcher 		for (i = 0; i < nbseg_diff; i++)
2383173a64cbSPatrick Boettcher 			state->seg_diff_mask |= 1 << permu_seg[i+1];
2384173a64cbSPatrick Boettcher 	} else {
2385173a64cbSPatrick Boettcher 		for (i = 0; i < 3; i++)
2386c82056d0SMauro Carvalho Chehab 			nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
2387173a64cbSPatrick Boettcher 		for (i = 0; i < nbseg_diff; i++)
2388173a64cbSPatrick Boettcher 			state->seg_diff_mask |= 1 << permu_seg[i];
2389173a64cbSPatrick Boettcher 	}
2390173a64cbSPatrick Boettcher 
2391173a64cbSPatrick Boettcher 	if (state->seg_diff_mask)
2392173a64cbSPatrick Boettcher 		dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2393173a64cbSPatrick Boettcher 	else
2394173a64cbSPatrick Boettcher 		dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */
2395173a64cbSPatrick Boettcher 
2396173a64cbSPatrick Boettcher 	for (i = 0; i < 3; i++)
2397173a64cbSPatrick Boettcher 		max_constellation = dib8000_set_layer(state, i, max_constellation);
2398173a64cbSPatrick Boettcher 	if (autosearching == 0) {
2399c82056d0SMauro Carvalho Chehab 		state->layer_b_nb_seg = c->layer[1].segment_count;
2400c82056d0SMauro Carvalho Chehab 		state->layer_c_nb_seg = c->layer[2].segment_count;
2401173a64cbSPatrick Boettcher 	}
2402173a64cbSPatrick Boettcher 
2403173a64cbSPatrick Boettcher 	/* WRITE: Mode & Diff mask */
2404173a64cbSPatrick Boettcher 	dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask);
2405173a64cbSPatrick Boettcher 
2406173a64cbSPatrick Boettcher 	state->differential_constellation = (state->seg_diff_mask != 0);
24079a0bf528SMauro Carvalho Chehab 
24089a0bf528SMauro Carvalho Chehab 	/* channel estimation fine configuration */
2409173a64cbSPatrick Boettcher 	ana_gain = dib8000_adp_fine_tune(state, max_constellation);
24109a0bf528SMauro Carvalho Chehab 
2411173a64cbSPatrick Boettcher 	/* update ana_gain depending on max constellation */
2412173a64cbSPatrick Boettcher 	dib8000_update_ana_gain(state, ana_gain);
24139a0bf528SMauro Carvalho Chehab 
2414173a64cbSPatrick Boettcher 	/* ---- ANA_FE ---- */
2415c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception) /* 3-segments */
2416173a64cbSPatrick Boettcher 		dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg);
2417173a64cbSPatrick Boettcher 	else
2418173a64cbSPatrick Boettcher 		dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */
2419173a64cbSPatrick Boettcher 
2420173a64cbSPatrick Boettcher 	/* TSB or ISDBT ? apply it now */
2421c82056d0SMauro Carvalho Chehab 	if (c->isdbt_sb_mode) {
2422173a64cbSPatrick Boettcher 		dib8000_set_sb_channel(state);
2423746f7ae0SMauro Carvalho Chehab 		if (c->isdbt_sb_subchannel < 14)
2424c82056d0SMauro Carvalho Chehab 			init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel);
2425173a64cbSPatrick Boettcher 		else
2426173a64cbSPatrick Boettcher 			init_prbs = 0;
2427173a64cbSPatrick Boettcher 	} else {
2428173a64cbSPatrick Boettcher 		dib8000_set_13seg_channel(state);
2429173a64cbSPatrick Boettcher 		init_prbs = 0xfff;
2430173a64cbSPatrick Boettcher 	}
24319a0bf528SMauro Carvalho Chehab 
2432173a64cbSPatrick Boettcher 	/* SMALL */
2433173a64cbSPatrick Boettcher 	dib8000_small_fine_tune(state);
24349a0bf528SMauro Carvalho Chehab 
2435173a64cbSPatrick Boettcher 	dib8000_set_subchannel_prbs(state, init_prbs);
2436173a64cbSPatrick Boettcher 
2437173a64cbSPatrick Boettcher 	/* ---- CHAN_BLK ---- */
24389a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 13; i++) {
2439173a64cbSPatrick Boettcher 		if ((((~state->seg_diff_mask) >> i) & 1) == 1) {
2440173a64cbSPatrick Boettcher 			p_cfr_left_edge  += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0));
2441173a64cbSPatrick Boettcher 			p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0));
24429a0bf528SMauro Carvalho Chehab 		}
24439a0bf528SMauro Carvalho Chehab 	}
2444173a64cbSPatrick Boettcher 	dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */
2445173a64cbSPatrick Boettcher 	dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */
2446173a64cbSPatrick Boettcher 	/* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */
24479a0bf528SMauro Carvalho Chehab 
2448173a64cbSPatrick Boettcher 	dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */
2449173a64cbSPatrick Boettcher 	dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */
2450173a64cbSPatrick Boettcher 	dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */
2451173a64cbSPatrick Boettcher 
2452173a64cbSPatrick Boettcher 	if (!autosearching)
2453173a64cbSPatrick Boettcher 		dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
2454173a64cbSPatrick Boettcher 	else
2455173a64cbSPatrick Boettcher 		dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */
2456173a64cbSPatrick Boettcher 
2457173a64cbSPatrick Boettcher 	dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */
2458173a64cbSPatrick Boettcher 	dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */
2459173a64cbSPatrick Boettcher 
2460173a64cbSPatrick Boettcher 	dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2461173a64cbSPatrick Boettcher 
2462173a64cbSPatrick Boettcher 	/* ---- TMCC ---- */
24639a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 3; i++)
2464c82056d0SMauro Carvalho Chehab 		tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ;
2465173a64cbSPatrick Boettcher 
2466173a64cbSPatrick Boettcher 	/* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */
2467173a64cbSPatrick Boettcher 	/* Threshold is set at 1/4 of max power. */
24689a0bf528SMauro Carvalho Chehab 	tmcc_pow *= (1 << (9-2));
2469173a64cbSPatrick Boettcher 	dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */
2470173a64cbSPatrick Boettcher 	dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */
2471173a64cbSPatrick Boettcher 	dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */
2472173a64cbSPatrick Boettcher 	/*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */
24739a0bf528SMauro Carvalho Chehab 
2474173a64cbSPatrick Boettcher 	/* ---- PHA3 ---- */
24759a0bf528SMauro Carvalho Chehab 	if (state->isdbt_cfg_loaded == 0)
24769a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */
24779a0bf528SMauro Carvalho Chehab 
24789a0bf528SMauro Carvalho Chehab 	state->isdbt_cfg_loaded = 0;
2479173a64cbSPatrick Boettcher }
24809a0bf528SMauro Carvalho Chehab 
24816f7ee06fSMauro Carvalho Chehab static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal,
24826f7ee06fSMauro Carvalho Chehab 			     u32 wait0_ms, u32 wait1_ms, u32 wait2_ms)
2483173a64cbSPatrick Boettcher {
248413122f98SMauro Carvalho Chehab 	u32 value = 0;	/* P_search_end0 wait time */
2485173a64cbSPatrick Boettcher 	u16 reg = 11;	/* P_search_end0 start addr */
2486173a64cbSPatrick Boettcher 
2487173a64cbSPatrick Boettcher 	for (reg = 11; reg < 16; reg += 2) {
2488173a64cbSPatrick Boettcher 		if (reg == 11) {
2489173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
249013122f98SMauro Carvalho Chehab 				value = internal * wait1_ms;
2491173a64cbSPatrick Boettcher 			else
249213122f98SMauro Carvalho Chehab 				value = internal * wait0_ms;
2493173a64cbSPatrick Boettcher 		} else if (reg == 13)
249413122f98SMauro Carvalho Chehab 			value = internal * wait1_ms;
2495173a64cbSPatrick Boettcher 		else if (reg == 15)
249613122f98SMauro Carvalho Chehab 			value = internal * wait2_ms;
2497173a64cbSPatrick Boettcher 		dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff));
2498173a64cbSPatrick Boettcher 		dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff));
2499173a64cbSPatrick Boettcher 	}
2500173a64cbSPatrick Boettcher 	return value;
25019a0bf528SMauro Carvalho Chehab }
25029a0bf528SMauro Carvalho Chehab 
25039a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_start(struct dvb_frontend *fe)
25049a0bf528SMauro Carvalho Chehab {
25059a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
2506c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2507173a64cbSPatrick Boettcher 	u8 slist = 0;
2508173a64cbSPatrick Boettcher 	u32 value, internal = state->cfg.pll->internal;
25099a0bf528SMauro Carvalho Chehab 
2510173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
2511173a64cbSPatrick Boettcher 		internal = dib8000_read32(state, 23) / 1000;
25129a0bf528SMauro Carvalho Chehab 
2513d67350f8SOlivier Grenie 	if ((state->revision >= 0x8002) &&
2514d67350f8SOlivier Grenie 	    (state->autosearch_state == AS_SEARCHING_FFT)) {
2515173a64cbSPatrick Boettcher 		dib8000_write_word(state,  37, 0x0065); /* P_ctrl_pha_off_max default values */
2516173a64cbSPatrick Boettcher 		dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
2517173a64cbSPatrick Boettcher 
2518173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */
2519173a64cbSPatrick Boettcher 		dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */
2520173a64cbSPatrick Boettcher 		dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */
2521173a64cbSPatrick Boettcher 		dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */
2522173a64cbSPatrick Boettcher 		dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */
2523173a64cbSPatrick Boettcher 		dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */
2524173a64cbSPatrick Boettcher 
2525173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2526173a64cbSPatrick Boettcher 			value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2527173a64cbSPatrick Boettcher 		else
2528173a64cbSPatrick Boettcher 			value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2529173a64cbSPatrick Boettcher 
2530173a64cbSPatrick Boettcher 		dib8000_write_word(state, 17, 0);
2531173a64cbSPatrick Boettcher 		dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */
2532173a64cbSPatrick Boettcher 		dib8000_write_word(state, 19, 0);
2533173a64cbSPatrick Boettcher 		dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */
2534173a64cbSPatrick Boettcher 		dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */
2535173a64cbSPatrick Boettcher 		dib8000_write_word(state, 22, value & 0xffff);
2536173a64cbSPatrick Boettcher 
2537173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2538173a64cbSPatrick Boettcher 			dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */
2539173a64cbSPatrick Boettcher 		else
2540173a64cbSPatrick Boettcher 			dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */
2541173a64cbSPatrick Boettcher 		dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */
2542173a64cbSPatrick Boettcher 
2543173a64cbSPatrick Boettcher 		/* P_search_param_select = (1 | 1<<4 | 1 << 8) */
2544173a64cbSPatrick Boettcher 		dib8000_write_word(state, 356, 0);
2545173a64cbSPatrick Boettcher 		dib8000_write_word(state, 357, 0x111);
2546173a64cbSPatrick Boettcher 
2547173a64cbSPatrick Boettcher 		dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
2548173a64cbSPatrick Boettcher 		dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
2549173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */
2550d67350f8SOlivier Grenie 	} else if ((state->revision >= 0x8002) &&
2551d67350f8SOlivier Grenie 		   (state->autosearch_state == AS_SEARCHING_GUARD)) {
2552c82056d0SMauro Carvalho Chehab 		c->transmission_mode = TRANSMISSION_MODE_8K;
2553c82056d0SMauro Carvalho Chehab 		c->guard_interval = GUARD_INTERVAL_1_8;
2554c82056d0SMauro Carvalho Chehab 		c->inversion = 0;
2555c82056d0SMauro Carvalho Chehab 		c->layer[0].modulation = QAM_64;
2556c82056d0SMauro Carvalho Chehab 		c->layer[0].fec = FEC_2_3;
2557c82056d0SMauro Carvalho Chehab 		c->layer[0].interleaving = 0;
2558c82056d0SMauro Carvalho Chehab 		c->layer[0].segment_count = 13;
25599a0bf528SMauro Carvalho Chehab 
2560173a64cbSPatrick Boettcher 		slist = 16;
2561c82056d0SMauro Carvalho Chehab 		c->transmission_mode = state->found_nfft;
2562173a64cbSPatrick Boettcher 
2563173a64cbSPatrick Boettcher 		dib8000_set_isdbt_common_channel(state, slist, 1);
2564173a64cbSPatrick Boettcher 
2565173a64cbSPatrick Boettcher 		/* set lock_mask values */
2566173a64cbSPatrick Boettcher 		dib8000_write_word(state, 6, 0x4);
2567173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2568173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */
2569173a64cbSPatrick Boettcher 		else
2570173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, 0x8);
2571173a64cbSPatrick Boettcher 		dib8000_write_word(state, 8, 0x1000);
2572173a64cbSPatrick Boettcher 
2573173a64cbSPatrick Boettcher 		/* set lock_mask wait time values */
2574173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2575173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2576173a64cbSPatrick Boettcher 		else
2577173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2578173a64cbSPatrick Boettcher 
2579173a64cbSPatrick Boettcher 		dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */
2580173a64cbSPatrick Boettcher 
2581173a64cbSPatrick Boettcher 		/* P_search_param_select = 0xf; look for the 4 different guard intervals */
2582173a64cbSPatrick Boettcher 		dib8000_write_word(state, 356, 0);
2583173a64cbSPatrick Boettcher 		dib8000_write_word(state, 357, 0xf);
2584173a64cbSPatrick Boettcher 
2585173a64cbSPatrick Boettcher 		value = dib8000_read_word(state, 0);
2586173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2587173a64cbSPatrick Boettcher 		dib8000_read_word(state, 1284);  /* reset the INT. n_irq_pending */
2588173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (u16)value);
2589173a64cbSPatrick Boettcher 	} else {
2590c82056d0SMauro Carvalho Chehab 		c->inversion = 0;
2591c82056d0SMauro Carvalho Chehab 		c->layer[0].modulation = QAM_64;
2592c82056d0SMauro Carvalho Chehab 		c->layer[0].fec = FEC_2_3;
2593c82056d0SMauro Carvalho Chehab 		c->layer[0].interleaving = 0;
2594c82056d0SMauro Carvalho Chehab 		c->layer[0].segment_count = 13;
2595c82056d0SMauro Carvalho Chehab 		if (!c->isdbt_sb_mode)
2596c82056d0SMauro Carvalho Chehab 			c->layer[0].segment_count = 13;
2597173a64cbSPatrick Boettcher 
2598173a64cbSPatrick Boettcher 		/* choose the right list, in sb, always do everything */
2599c82056d0SMauro Carvalho Chehab 		if (c->isdbt_sb_mode) {
26009a0bf528SMauro Carvalho Chehab 			slist = 7;
26019a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
26029a0bf528SMauro Carvalho Chehab 		} else {
2603c82056d0SMauro Carvalho Chehab 			if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2604c82056d0SMauro Carvalho Chehab 				if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2605c82056d0SMauro Carvalho Chehab 					c->transmission_mode = TRANSMISSION_MODE_8K;
2606c82056d0SMauro Carvalho Chehab 					c->guard_interval = GUARD_INTERVAL_1_8;
26079a0bf528SMauro Carvalho Chehab 					slist = 7;
2608173a64cbSPatrick Boettcher 					dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));  /* P_mode = 1 to have autosearch start ok with mode2 */
2609173a64cbSPatrick Boettcher 				} else {
2610c82056d0SMauro Carvalho Chehab 					c->guard_interval = GUARD_INTERVAL_1_8;
26119a0bf528SMauro Carvalho Chehab 					slist = 3;
2612173a64cbSPatrick Boettcher 				}
26139a0bf528SMauro Carvalho Chehab 			} else {
2614c82056d0SMauro Carvalho Chehab 				if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2615c82056d0SMauro Carvalho Chehab 					c->transmission_mode = TRANSMISSION_MODE_8K;
26169a0bf528SMauro Carvalho Chehab 					slist = 2;
2617173a64cbSPatrick Boettcher 					dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));  /* P_mode = 1 */
26189a0bf528SMauro Carvalho Chehab 				} else
26199a0bf528SMauro Carvalho Chehab 					slist = 0;
26209a0bf528SMauro Carvalho Chehab 			}
2621173a64cbSPatrick Boettcher 		}
2622173a64cbSPatrick Boettcher 		dprintk("Using list for autosearch : %d", slist);
26239a0bf528SMauro Carvalho Chehab 
2624173a64cbSPatrick Boettcher 		dib8000_set_isdbt_common_channel(state, slist, 1);
26259a0bf528SMauro Carvalho Chehab 
2626173a64cbSPatrick Boettcher 		/* set lock_mask values */
26279a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 6, 0x4);
2628173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2629173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10));
2630173a64cbSPatrick Boettcher 		else
26319a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 7, 0x8);
26329a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 8, 0x1000);
26339a0bf528SMauro Carvalho Chehab 
2634173a64cbSPatrick Boettcher 		/* set lock_mask wait time values */
2635173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2636173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2637173a64cbSPatrick Boettcher 		else
2638173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
26399a0bf528SMauro Carvalho Chehab 
26409a0bf528SMauro Carvalho Chehab 		value = dib8000_read_word(state, 0);
26419a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2642173a64cbSPatrick Boettcher 		dib8000_read_word(state, 1284);  /* reset the INT. n_irq_pending */
26439a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 0, (u16)value);
26449a0bf528SMauro Carvalho Chehab 	}
26459a0bf528SMauro Carvalho Chehab 	return 0;
26469a0bf528SMauro Carvalho Chehab }
26479a0bf528SMauro Carvalho Chehab 
26489a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_irq(struct dvb_frontend *fe)
26499a0bf528SMauro Carvalho Chehab {
26509a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
26519a0bf528SMauro Carvalho Chehab 	u16 irq_pending = dib8000_read_word(state, 1284);
26529a0bf528SMauro Carvalho Chehab 
2653d67350f8SOlivier Grenie 	if ((state->revision >= 0x8002) &&
2654d67350f8SOlivier Grenie 	    (state->autosearch_state == AS_SEARCHING_FFT)) {
2655173a64cbSPatrick Boettcher 		if (irq_pending & 0x1) {
2656173a64cbSPatrick Boettcher 			dprintk("dib8000_autosearch_irq: max correlation result available");
2657173a64cbSPatrick Boettcher 			return 3;
2658173a64cbSPatrick Boettcher 		}
2659173a64cbSPatrick Boettcher 	} else {
2660173a64cbSPatrick Boettcher 		if (irq_pending & 0x1) {	/* failed */
26619a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_autosearch_irq failed");
26629a0bf528SMauro Carvalho Chehab 			return 1;
26639a0bf528SMauro Carvalho Chehab 		}
26649a0bf528SMauro Carvalho Chehab 
2665173a64cbSPatrick Boettcher 		if (irq_pending & 0x2) {	/* succeeded */
26669a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_autosearch_irq succeeded");
26679a0bf528SMauro Carvalho Chehab 			return 2;
26689a0bf528SMauro Carvalho Chehab 		}
2669173a64cbSPatrick Boettcher 	}
26709a0bf528SMauro Carvalho Chehab 
26719a0bf528SMauro Carvalho Chehab 	return 0;		// still pending
26729a0bf528SMauro Carvalho Chehab }
26739a0bf528SMauro Carvalho Chehab 
2674173a64cbSPatrick Boettcher static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
2675173a64cbSPatrick Boettcher {
2676173a64cbSPatrick Boettcher 	u16 tmp;
2677173a64cbSPatrick Boettcher 
2678173a64cbSPatrick Boettcher 	tmp = dib8000_read_word(state, 771);
2679173a64cbSPatrick Boettcher 	if (onoff) /* start P_restart_chd : channel_decoder */
2680173a64cbSPatrick Boettcher 		dib8000_write_word(state, 771, tmp & 0xfffd);
2681173a64cbSPatrick Boettcher 	else /* stop P_restart_chd : channel_decoder */
2682173a64cbSPatrick Boettcher 		dib8000_write_word(state, 771, tmp | (1<<1));
2683173a64cbSPatrick Boettcher }
2684173a64cbSPatrick Boettcher 
2685173a64cbSPatrick Boettcher static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
2686173a64cbSPatrick Boettcher {
2687173a64cbSPatrick Boettcher 	s16 unit_khz_dds_val;
2688173a64cbSPatrick Boettcher 	u32 abs_offset_khz = ABS(offset_khz);
2689173a64cbSPatrick Boettcher 	u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
2690173a64cbSPatrick Boettcher 	u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
2691173a64cbSPatrick Boettcher 	u8 ratio;
2692173a64cbSPatrick Boettcher 
2693173a64cbSPatrick Boettcher 	if (state->revision == 0x8090) {
2694173a64cbSPatrick Boettcher 		ratio = 4;
2695173a64cbSPatrick Boettcher 		unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000);
2696173a64cbSPatrick Boettcher 		if (offset_khz < 0)
2697173a64cbSPatrick Boettcher 			dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
2698173a64cbSPatrick Boettcher 		else
2699173a64cbSPatrick Boettcher 			dds = (abs_offset_khz * unit_khz_dds_val);
2700173a64cbSPatrick Boettcher 
2701173a64cbSPatrick Boettcher 		if (invert)
2702173a64cbSPatrick Boettcher 			dds = (1<<26) - dds;
2703173a64cbSPatrick Boettcher 	} else {
2704173a64cbSPatrick Boettcher 		ratio = 2;
2705173a64cbSPatrick Boettcher 		unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
2706173a64cbSPatrick Boettcher 
2707173a64cbSPatrick Boettcher 		if (offset_khz < 0)
2708173a64cbSPatrick Boettcher 			unit_khz_dds_val *= -1;
2709173a64cbSPatrick Boettcher 
2710173a64cbSPatrick Boettcher 		/* IF tuner */
2711173a64cbSPatrick Boettcher 		if (invert)
2712173a64cbSPatrick Boettcher 			dds -= abs_offset_khz * unit_khz_dds_val;
2713173a64cbSPatrick Boettcher 		else
2714173a64cbSPatrick Boettcher 			dds += abs_offset_khz * unit_khz_dds_val;
2715173a64cbSPatrick Boettcher 	}
2716173a64cbSPatrick Boettcher 
2717173a64cbSPatrick Boettcher 	dprintk("setting a DDS frequency offset of %c%dkHz", invert ? '-' : ' ', dds / unit_khz_dds_val);
2718173a64cbSPatrick Boettcher 
2719173a64cbSPatrick Boettcher 	if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) {
2720173a64cbSPatrick Boettcher 		/* Max dds offset is the half of the demod freq */
2721173a64cbSPatrick Boettcher 		dib8000_write_word(state, 26, invert);
2722173a64cbSPatrick Boettcher 		dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff);
2723173a64cbSPatrick Boettcher 		dib8000_write_word(state, 28, (u16)(dds & 0xffff));
2724173a64cbSPatrick Boettcher 	}
2725173a64cbSPatrick Boettcher }
2726173a64cbSPatrick Boettcher 
2727173a64cbSPatrick Boettcher static void dib8000_set_frequency_offset(struct dib8000_state *state)
2728173a64cbSPatrick Boettcher {
2729c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2730173a64cbSPatrick Boettcher 	int i;
2731173a64cbSPatrick Boettcher 	u32 current_rf;
2732173a64cbSPatrick Boettcher 	int total_dds_offset_khz;
2733173a64cbSPatrick Boettcher 
2734173a64cbSPatrick Boettcher 	if (state->fe[0]->ops.tuner_ops.get_frequency)
2735173a64cbSPatrick Boettcher 		state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], &current_rf);
2736173a64cbSPatrick Boettcher 	else
2737c82056d0SMauro Carvalho Chehab 		current_rf = c->frequency;
2738173a64cbSPatrick Boettcher 	current_rf /= 1000;
2739c82056d0SMauro Carvalho Chehab 	total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000;
2740173a64cbSPatrick Boettcher 
2741c82056d0SMauro Carvalho Chehab 	if (c->isdbt_sb_mode) {
2742c82056d0SMauro Carvalho Chehab 		state->subchannel = c->isdbt_sb_subchannel;
2743173a64cbSPatrick Boettcher 
2744173a64cbSPatrick Boettcher 		i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */
2745c82056d0SMauro Carvalho Chehab 		dib8000_write_word(state, 26, c->inversion ^ i);
2746173a64cbSPatrick Boettcher 
2747173a64cbSPatrick Boettcher 		if (state->cfg.pll->ifreq == 0) { /* low if tuner */
2748c82056d0SMauro Carvalho Chehab 			if ((c->inversion ^ i) == 0)
2749173a64cbSPatrick Boettcher 				dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
2750173a64cbSPatrick Boettcher 		} else {
2751c82056d0SMauro Carvalho Chehab 			if ((c->inversion ^ i) == 0)
2752173a64cbSPatrick Boettcher 				total_dds_offset_khz *= -1;
2753173a64cbSPatrick Boettcher 		}
2754173a64cbSPatrick Boettcher 	}
2755173a64cbSPatrick Boettcher 
2756c82056d0SMauro 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);
2757173a64cbSPatrick Boettcher 
2758173a64cbSPatrick Boettcher 	/* apply dds offset now */
2759173a64cbSPatrick Boettcher 	dib8000_set_dds(state, total_dds_offset_khz);
2760173a64cbSPatrick Boettcher }
2761173a64cbSPatrick Boettcher 
2762173a64cbSPatrick Boettcher static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 };
27636f7ee06fSMauro Carvalho Chehab 
27646f7ee06fSMauro Carvalho Chehab static u32 dib8000_get_symbol_duration(struct dib8000_state *state)
2765173a64cbSPatrick Boettcher {
2766c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2767173a64cbSPatrick Boettcher 	u16 i;
2768173a64cbSPatrick Boettcher 
2769c82056d0SMauro Carvalho Chehab 	switch (c->transmission_mode) {
2770173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_2K:
2771173a64cbSPatrick Boettcher 			i = 0;
2772173a64cbSPatrick Boettcher 			break;
2773173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_4K:
2774173a64cbSPatrick Boettcher 			i = 2;
2775173a64cbSPatrick Boettcher 			break;
2776173a64cbSPatrick Boettcher 	default:
2777173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_AUTO:
2778173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2779173a64cbSPatrick Boettcher 			i = 1;
2780173a64cbSPatrick Boettcher 			break;
2781173a64cbSPatrick Boettcher 	}
2782173a64cbSPatrick Boettcher 
2783c82056d0SMauro Carvalho Chehab 	return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1;
2784173a64cbSPatrick Boettcher }
2785173a64cbSPatrick Boettcher 
2786173a64cbSPatrick Boettcher static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step)
2787173a64cbSPatrick Boettcher {
2788c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2789173a64cbSPatrick Boettcher 	u16 reg_32 = 0, reg_37 = 0;
2790173a64cbSPatrick Boettcher 
2791173a64cbSPatrick Boettcher 	switch (loop_step) {
2792173a64cbSPatrick Boettcher 	case LOOP_TUNE_1:
2793c82056d0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode)  {
2794c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) {
2795173a64cbSPatrick Boettcher 					reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */
2796173a64cbSPatrick 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)  */
2797173a64cbSPatrick Boettcher 				} else { /* Sound Broadcasting mode 3 seg */
2798173a64cbSPatrick Boettcher 					reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */
2799173a64cbSPatrick 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)  */
2800173a64cbSPatrick Boettcher 				}
2801173a64cbSPatrick Boettcher 			} else { /* 13-seg start conf offset loop parameters */
2802173a64cbSPatrick Boettcher 				reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
2803173a64cbSPatrick 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  */
2804173a64cbSPatrick Boettcher 			}
2805173a64cbSPatrick Boettcher 			break;
2806173a64cbSPatrick Boettcher 	case LOOP_TUNE_2:
2807c82056d0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode)  {
2808c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) {  /* Sound Broadcasting mode 1 seg */
2809173a64cbSPatrick Boettcher 					reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/
2810173a64cbSPatrick Boettcher 					reg_37 = (12-state->mode) | ((5 + state->mode) << 5);
2811173a64cbSPatrick Boettcher 				} else {  /* Sound Broadcasting mode 3 seg */
2812173a64cbSPatrick Boettcher 					reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */
2813173a64cbSPatrick Boettcher 					reg_37 = (11-state->mode) | ((5 + state->mode) << 5);
2814173a64cbSPatrick Boettcher 				}
2815173a64cbSPatrick Boettcher 			} else {  /* 13 seg */
2816173a64cbSPatrick Boettcher 				reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */
2817173a64cbSPatrick Boettcher 				reg_37 = ((5+state->mode) << 5) | (10 - state->mode);
2818173a64cbSPatrick Boettcher 			}
2819173a64cbSPatrick Boettcher 			break;
2820173a64cbSPatrick Boettcher 	}
2821173a64cbSPatrick Boettcher 	dib8000_write_word(state, 32, reg_32);
2822173a64cbSPatrick Boettcher 	dib8000_write_word(state, 37, reg_37);
2823173a64cbSPatrick Boettcher }
2824173a64cbSPatrick Boettcher 
2825173a64cbSPatrick Boettcher static void dib8000_demod_restart(struct dib8000_state *state)
2826173a64cbSPatrick Boettcher {
2827173a64cbSPatrick Boettcher 	dib8000_write_word(state, 770, 0x4000);
2828173a64cbSPatrick Boettcher 	dib8000_write_word(state, 770, 0x0000);
2829173a64cbSPatrick Boettcher 	return;
2830173a64cbSPatrick Boettcher }
2831173a64cbSPatrick Boettcher 
2832173a64cbSPatrick Boettcher static void dib8000_set_sync_wait(struct dib8000_state *state)
2833173a64cbSPatrick Boettcher {
2834c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2835173a64cbSPatrick Boettcher 	u16 sync_wait = 64;
2836173a64cbSPatrick Boettcher 
2837173a64cbSPatrick Boettcher 	/* P_dvsy_sync_wait - reuse mode */
2838c82056d0SMauro Carvalho Chehab 	switch (c->transmission_mode) {
2839173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2840173a64cbSPatrick Boettcher 			sync_wait = 256;
2841173a64cbSPatrick Boettcher 			break;
2842173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_4K:
2843173a64cbSPatrick Boettcher 			sync_wait = 128;
2844173a64cbSPatrick Boettcher 			break;
2845173a64cbSPatrick Boettcher 	default:
2846173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_2K:
2847173a64cbSPatrick Boettcher 			sync_wait =  64;
2848173a64cbSPatrick Boettcher 			break;
2849173a64cbSPatrick Boettcher 	}
2850173a64cbSPatrick Boettcher 
2851173a64cbSPatrick Boettcher 	if (state->cfg.diversity_delay == 0)
2852c82056d0SMauro Carvalho Chehab 		sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */
2853173a64cbSPatrick Boettcher 	else
2854c82056d0SMauro Carvalho Chehab 		sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */
2855173a64cbSPatrick Boettcher 
2856173a64cbSPatrick Boettcher 	dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
2857173a64cbSPatrick Boettcher }
2858173a64cbSPatrick Boettcher 
2859173a64cbSPatrick Boettcher static u32 dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
2860173a64cbSPatrick Boettcher {
2861173a64cbSPatrick Boettcher 	if (mode == SYMBOL_DEPENDENT_ON)
2862173a64cbSPatrick Boettcher 		return systime() + (delay * state->symbol_duration);
2863173a64cbSPatrick Boettcher 	else
2864173a64cbSPatrick Boettcher 		return systime() + delay;
2865173a64cbSPatrick Boettcher }
2866173a64cbSPatrick Boettcher 
2867173a64cbSPatrick Boettcher static s32 dib8000_get_status(struct dvb_frontend *fe)
2868173a64cbSPatrick Boettcher {
2869173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2870173a64cbSPatrick Boettcher 	return state->status;
2871173a64cbSPatrick Boettcher }
2872173a64cbSPatrick Boettcher 
2873173a64cbSPatrick Boettcher enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
2874173a64cbSPatrick Boettcher {
2875173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2876173a64cbSPatrick Boettcher 	return state->tune_state;
2877173a64cbSPatrick Boettcher }
2878173a64cbSPatrick Boettcher EXPORT_SYMBOL(dib8000_get_tune_state);
2879173a64cbSPatrick Boettcher 
2880173a64cbSPatrick Boettcher int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2881173a64cbSPatrick Boettcher {
2882173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2883173a64cbSPatrick Boettcher 
2884173a64cbSPatrick Boettcher 	state->tune_state = tune_state;
2885173a64cbSPatrick Boettcher 	return 0;
2886173a64cbSPatrick Boettcher }
2887173a64cbSPatrick Boettcher EXPORT_SYMBOL(dib8000_set_tune_state);
2888173a64cbSPatrick Boettcher 
2889173a64cbSPatrick Boettcher static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
2890173a64cbSPatrick Boettcher {
2891173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2892173a64cbSPatrick Boettcher 
2893173a64cbSPatrick Boettcher 	state->status = FE_STATUS_TUNE_PENDING;
2894173a64cbSPatrick Boettcher 	state->tune_state = CT_DEMOD_START;
2895173a64cbSPatrick Boettcher 	return 0;
2896173a64cbSPatrick Boettcher }
2897173a64cbSPatrick Boettcher 
2898173a64cbSPatrick Boettcher static u16 dib8000_read_lock(struct dvb_frontend *fe)
2899173a64cbSPatrick Boettcher {
2900173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2901173a64cbSPatrick Boettcher 
2902173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
2903173a64cbSPatrick Boettcher 		return dib8000_read_word(state, 570);
2904173a64cbSPatrick Boettcher 	return dib8000_read_word(state, 568);
2905173a64cbSPatrick Boettcher }
2906173a64cbSPatrick Boettcher 
2907173a64cbSPatrick Boettcher static int dib8090p_init_sdram(struct dib8000_state *state)
2908173a64cbSPatrick Boettcher {
2909173a64cbSPatrick Boettcher 	u16 reg = 0;
2910173a64cbSPatrick Boettcher 	dprintk("init sdram");
2911173a64cbSPatrick Boettcher 
2912173a64cbSPatrick Boettcher 	reg = dib8000_read_word(state, 274) & 0xfff0;
2913173a64cbSPatrick Boettcher 	dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */
2914173a64cbSPatrick Boettcher 
2915173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1803, (7 << 2));
2916173a64cbSPatrick Boettcher 
2917173a64cbSPatrick Boettcher 	reg = dib8000_read_word(state, 1280);
2918173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1280,  reg | (1 << 2)); /* force restart P_restart_sdram */
2919173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1280,  reg); /* release restart P_restart_sdram */
2920173a64cbSPatrick Boettcher 
2921173a64cbSPatrick Boettcher 	return 0;
2922173a64cbSPatrick Boettcher }
2923173a64cbSPatrick Boettcher 
2924ad976187SMauro Carvalho Chehab /**
2925ad976187SMauro Carvalho Chehab  * is_manual_mode - Check if TMCC should be used for parameters settings
2926ad976187SMauro Carvalho Chehab  * @c:	struct dvb_frontend_properties
2927ad976187SMauro Carvalho Chehab  *
2928ad976187SMauro Carvalho Chehab  * By default, TMCC table should be used for parameter settings on most
2929ad976187SMauro Carvalho Chehab  * usercases. However, sometimes it is desirable to lock the demod to
2930ad976187SMauro Carvalho Chehab  * use the manual parameters.
2931ad976187SMauro Carvalho Chehab  *
2932ad976187SMauro Carvalho Chehab  * On manual mode, the current dib8000_tune state machine is very restrict:
2933ad976187SMauro Carvalho Chehab  * It requires that both per-layer and per-transponder parameters to be
2934ad976187SMauro Carvalho Chehab  * properly specified, otherwise the device won't lock.
2935ad976187SMauro Carvalho Chehab  *
2936ad976187SMauro Carvalho Chehab  * Check if all those conditions are properly satisfied before allowing
2937ad976187SMauro Carvalho Chehab  * the device to use the manual frequency lock mode.
2938ad976187SMauro Carvalho Chehab  */
2939ad976187SMauro Carvalho Chehab static int is_manual_mode(struct dtv_frontend_properties *c)
2940ad976187SMauro Carvalho Chehab {
2941ad976187SMauro Carvalho Chehab 	int i, n_segs = 0;
2942ad976187SMauro Carvalho Chehab 
2943ad976187SMauro Carvalho Chehab 	/* Use auto mode on DVB-T compat mode */
2944ad976187SMauro Carvalho Chehab 	if (c->delivery_system != SYS_ISDBT)
2945ad976187SMauro Carvalho Chehab 		return 0;
2946ad976187SMauro Carvalho Chehab 
2947ad976187SMauro Carvalho Chehab 	/*
2948ad976187SMauro Carvalho Chehab 	 * Transmission mode is only detected on auto mode, currently
2949ad976187SMauro Carvalho Chehab 	 */
2950ad976187SMauro Carvalho Chehab 	if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2951ad976187SMauro Carvalho Chehab 		dprintk("transmission mode auto");
2952ad976187SMauro Carvalho Chehab 		return 0;
2953ad976187SMauro Carvalho Chehab 	}
2954ad976187SMauro Carvalho Chehab 
2955ad976187SMauro Carvalho Chehab 	/*
2956ad976187SMauro Carvalho Chehab 	 * Guard interval is only detected on auto mode, currently
2957ad976187SMauro Carvalho Chehab 	 */
2958ad976187SMauro Carvalho Chehab 	if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2959ad976187SMauro Carvalho Chehab 		dprintk("guard interval auto");
2960ad976187SMauro Carvalho Chehab 		return 0;
2961ad976187SMauro Carvalho Chehab 	}
2962ad976187SMauro Carvalho Chehab 
2963ad976187SMauro Carvalho Chehab 	/*
2964ad976187SMauro Carvalho Chehab 	 * If no layer is enabled, assume auto mode, as at least one
2965ad976187SMauro Carvalho Chehab 	 * layer should be enabled
2966ad976187SMauro Carvalho Chehab 	 */
2967ad976187SMauro Carvalho Chehab 	if (!c->isdbt_layer_enabled) {
2968ad976187SMauro Carvalho Chehab 		dprintk("no layer modulation specified");
2969ad976187SMauro Carvalho Chehab 		return 0;
2970ad976187SMauro Carvalho Chehab 	}
2971ad976187SMauro Carvalho Chehab 
2972ad976187SMauro Carvalho Chehab 	/*
2973ad976187SMauro Carvalho Chehab 	 * Check if the per-layer parameters aren't auto and
2974ad976187SMauro Carvalho Chehab 	 * disable a layer if segment count is 0 or invalid.
2975ad976187SMauro Carvalho Chehab 	 */
2976ad976187SMauro Carvalho Chehab 	for (i = 0; i < 3; i++) {
2977ad976187SMauro Carvalho Chehab 		if (!(c->isdbt_layer_enabled & 1 << i))
2978ad976187SMauro Carvalho Chehab 			continue;
2979ad976187SMauro Carvalho Chehab 
2980ad976187SMauro Carvalho Chehab 		if ((c->layer[i].segment_count > 13) ||
2981ad976187SMauro Carvalho Chehab 		    (c->layer[i].segment_count == 0)) {
2982ad976187SMauro Carvalho Chehab 			c->isdbt_layer_enabled &= ~(1 << i);
2983ad976187SMauro Carvalho Chehab 			continue;
2984ad976187SMauro Carvalho Chehab 		}
2985ad976187SMauro Carvalho Chehab 
2986ad976187SMauro Carvalho Chehab 		n_segs += c->layer[i].segment_count;
2987ad976187SMauro Carvalho Chehab 
2988ad976187SMauro Carvalho Chehab 		if ((c->layer[i].modulation == QAM_AUTO) ||
2989ad976187SMauro Carvalho Chehab 		    (c->layer[i].fec == FEC_AUTO)) {
2990ad976187SMauro Carvalho Chehab 			dprintk("layer %c has either modulation or FEC auto",
2991ad976187SMauro Carvalho Chehab 				'A' + i);
2992ad976187SMauro Carvalho Chehab 			return 0;
2993ad976187SMauro Carvalho Chehab 		}
2994ad976187SMauro Carvalho Chehab 	}
2995ad976187SMauro Carvalho Chehab 
2996ad976187SMauro Carvalho Chehab 	/*
2997ad976187SMauro Carvalho Chehab 	 * Userspace specified a wrong number of segments.
2998ad976187SMauro Carvalho Chehab 	 *	fallback to auto mode.
2999ad976187SMauro Carvalho Chehab 	 */
3000ad976187SMauro Carvalho Chehab 	if (n_segs == 0 || n_segs > 13) {
3001ad976187SMauro Carvalho Chehab 		dprintk("number of segments is invalid");
3002ad976187SMauro Carvalho Chehab 		return 0;
3003ad976187SMauro Carvalho Chehab 	}
3004ad976187SMauro Carvalho Chehab 
3005ad976187SMauro Carvalho Chehab 	/* Everything looks ok for manual mode */
3006ad976187SMauro Carvalho Chehab 	return 1;
3007ad976187SMauro Carvalho Chehab }
3008ad976187SMauro Carvalho Chehab 
30099a0bf528SMauro Carvalho Chehab static int dib8000_tune(struct dvb_frontend *fe)
30109a0bf528SMauro Carvalho Chehab {
30119a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
3012c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3013173a64cbSPatrick Boettcher 	enum frontend_tune_state *tune_state = &state->tune_state;
30149a0bf528SMauro Carvalho Chehab 
3015173a64cbSPatrick Boettcher 	u16 locks, deeper_interleaver = 0, i;
3016173a64cbSPatrick Boettcher 	int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
30179a0bf528SMauro Carvalho Chehab 
3018173a64cbSPatrick Boettcher 	u32 *timeout = &state->timeout;
3019173a64cbSPatrick Boettcher 	u32 now = systime();
3020173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3021173a64cbSPatrick Boettcher 	u16 agc1, agc2;
3022173a64cbSPatrick Boettcher #endif
30239a0bf528SMauro Carvalho Chehab 
3024173a64cbSPatrick Boettcher 	u32 corm[4] = {0, 0, 0, 0};
3025173a64cbSPatrick Boettcher 	u8 find_index, max_value;
30269a0bf528SMauro Carvalho Chehab 
3027173a64cbSPatrick Boettcher #if 0
3028173a64cbSPatrick Boettcher 	if (*tune_state < CT_DEMOD_STOP)
3029173a64cbSPatrick Boettcher 		dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u systime = %u", state->channel_parameters_set, *tune_state, state->autosearch_state, now);
3030173a64cbSPatrick Boettcher #endif
30319a0bf528SMauro Carvalho Chehab 
3032173a64cbSPatrick Boettcher 	switch (*tune_state) {
3033173a64cbSPatrick Boettcher 	case CT_DEMOD_START: /* 30 */
30346ef06e78SMauro Carvalho Chehab 			dib8000_reset_stats(fe);
30356ef06e78SMauro Carvalho Chehab 
3036173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
3037173a64cbSPatrick Boettcher 				dib8090p_init_sdram(state);
3038173a64cbSPatrick Boettcher 			state->status = FE_STATUS_TUNE_PENDING;
3039ad976187SMauro Carvalho Chehab 			state->channel_parameters_set = is_manual_mode(c);
3040ad976187SMauro Carvalho Chehab 
3041ad976187SMauro Carvalho Chehab 			dprintk("Tuning channel on %s search mode",
3042ad976187SMauro Carvalho Chehab 				state->channel_parameters_set ? "manual" : "auto");
30439a0bf528SMauro Carvalho Chehab 
3044173a64cbSPatrick Boettcher 			dib8000_viterbi_state(state, 0); /* force chan dec in restart */
30459a0bf528SMauro Carvalho Chehab 
3046ad976187SMauro Carvalho Chehab 			/* Layer monitor */
3047173a64cbSPatrick Boettcher 			dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
3048173a64cbSPatrick Boettcher 
3049173a64cbSPatrick Boettcher 			dib8000_set_frequency_offset(state);
3050c82056d0SMauro Carvalho Chehab 			dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
3051173a64cbSPatrick Boettcher 
3052173a64cbSPatrick Boettcher 			if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
3053173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3054173a64cbSPatrick Boettcher 				if (state->revision != 0x8090) {
3055173a64cbSPatrick Boettcher 					state->agc1_max = dib8000_read_word(state, 108);
3056173a64cbSPatrick Boettcher 					state->agc1_min = dib8000_read_word(state, 109);
3057173a64cbSPatrick Boettcher 					state->agc2_max = dib8000_read_word(state, 110);
3058173a64cbSPatrick Boettcher 					state->agc2_min = dib8000_read_word(state, 111);
3059173a64cbSPatrick Boettcher 					agc1 = dib8000_read_word(state, 388);
3060173a64cbSPatrick Boettcher 					agc2 = dib8000_read_word(state, 389);
3061173a64cbSPatrick Boettcher 					dib8000_write_word(state, 108, agc1);
3062173a64cbSPatrick Boettcher 					dib8000_write_word(state, 109, agc1);
3063173a64cbSPatrick Boettcher 					dib8000_write_word(state, 110, agc2);
3064173a64cbSPatrick Boettcher 					dib8000_write_word(state, 111, agc2);
3065173a64cbSPatrick Boettcher 				}
3066173a64cbSPatrick Boettcher #endif
3067173a64cbSPatrick Boettcher 				state->autosearch_state = AS_SEARCHING_FFT;
3068173a64cbSPatrick Boettcher 				state->found_nfft = TRANSMISSION_MODE_AUTO;
3069173a64cbSPatrick Boettcher 				state->found_guard = GUARD_INTERVAL_AUTO;
3070173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_SEARCH_NEXT;
3071173a64cbSPatrick Boettcher 			} else { /* we already know the channel struct so TUNE only ! */
3072173a64cbSPatrick Boettcher 				state->autosearch_state = AS_DONE;
3073173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_3;
3074173a64cbSPatrick Boettcher 			}
3075173a64cbSPatrick Boettcher 			state->symbol_duration = dib8000_get_symbol_duration(state);
3076173a64cbSPatrick Boettcher 			break;
3077173a64cbSPatrick Boettcher 
3078173a64cbSPatrick Boettcher 	case CT_DEMOD_SEARCH_NEXT: /* 51 */
3079173a64cbSPatrick Boettcher 			dib8000_autosearch_start(fe);
3080173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
3081173a64cbSPatrick Boettcher 				ret = 50;
3082173a64cbSPatrick Boettcher 			else
3083173a64cbSPatrick Boettcher 				ret = 15;
3084173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_1;
3085173a64cbSPatrick Boettcher 			break;
3086173a64cbSPatrick Boettcher 
3087173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_1: /* 31 */
3088173a64cbSPatrick Boettcher 			switch (dib8000_autosearch_irq(fe)) {
3089173a64cbSPatrick Boettcher 			case 1: /* fail */
3090173a64cbSPatrick Boettcher 					state->status = FE_STATUS_TUNE_FAILED;
3091173a64cbSPatrick Boettcher 					state->autosearch_state = AS_DONE;
3092173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STOP; /* else we are done here */
3093173a64cbSPatrick Boettcher 					break;
3094173a64cbSPatrick Boettcher 			case 2: /* Succes */
3095173a64cbSPatrick Boettcher 					state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
3096173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_3;
3097173a64cbSPatrick Boettcher 					if (state->autosearch_state == AS_SEARCHING_GUARD)
3098173a64cbSPatrick Boettcher 						*tune_state = CT_DEMOD_STEP_2;
3099173a64cbSPatrick Boettcher 					else
3100173a64cbSPatrick Boettcher 						state->autosearch_state = AS_DONE;
3101173a64cbSPatrick Boettcher 					break;
3102173a64cbSPatrick Boettcher 			case 3: /* Autosearch FFT max correlation endded */
3103173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_2;
3104173a64cbSPatrick Boettcher 					break;
3105173a64cbSPatrick Boettcher 			}
3106173a64cbSPatrick Boettcher 			break;
3107173a64cbSPatrick Boettcher 
3108173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_2:
3109173a64cbSPatrick Boettcher 			switch (state->autosearch_state) {
3110173a64cbSPatrick Boettcher 			case AS_SEARCHING_FFT:
3111173a64cbSPatrick Boettcher 					/* searching for the correct FFT */
3112173a64cbSPatrick Boettcher 				if (state->revision == 0x8090) {
3113173a64cbSPatrick Boettcher 					corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3114173a64cbSPatrick Boettcher 					corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3115173a64cbSPatrick Boettcher 					corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
3116173a64cbSPatrick Boettcher 				} else {
3117173a64cbSPatrick Boettcher 					corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
3118173a64cbSPatrick Boettcher 					corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3119173a64cbSPatrick Boettcher 					corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3120173a64cbSPatrick Boettcher 				}
3121173a64cbSPatrick Boettcher 					/* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */
3122173a64cbSPatrick Boettcher 
3123173a64cbSPatrick Boettcher 					max_value = 0;
3124173a64cbSPatrick Boettcher 					for (find_index = 1 ; find_index < 3 ; find_index++) {
3125173a64cbSPatrick Boettcher 						if (corm[max_value] < corm[find_index])
3126173a64cbSPatrick Boettcher 							max_value = find_index ;
31279a0bf528SMauro Carvalho Chehab 					}
31289a0bf528SMauro Carvalho Chehab 
3129173a64cbSPatrick Boettcher 					switch (max_value) {
3130173a64cbSPatrick Boettcher 					case 0:
3131173a64cbSPatrick Boettcher 							state->found_nfft = TRANSMISSION_MODE_2K;
3132173a64cbSPatrick Boettcher 							break;
3133173a64cbSPatrick Boettcher 					case 1:
3134173a64cbSPatrick Boettcher 							state->found_nfft = TRANSMISSION_MODE_4K;
3135173a64cbSPatrick Boettcher 							break;
3136173a64cbSPatrick Boettcher 					case 2:
3137173a64cbSPatrick Boettcher 					default:
3138173a64cbSPatrick Boettcher 							state->found_nfft = TRANSMISSION_MODE_8K;
3139173a64cbSPatrick Boettcher 							break;
3140173a64cbSPatrick Boettcher 					}
3141173a64cbSPatrick Boettcher 					/* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */
3142173a64cbSPatrick Boettcher 
3143173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_SEARCH_NEXT;
3144173a64cbSPatrick Boettcher 					state->autosearch_state = AS_SEARCHING_GUARD;
3145173a64cbSPatrick Boettcher 					if (state->revision == 0x8090)
3146173a64cbSPatrick Boettcher 						ret = 50;
3147173a64cbSPatrick Boettcher 					else
3148173a64cbSPatrick Boettcher 						ret = 10;
3149173a64cbSPatrick Boettcher 					break;
3150173a64cbSPatrick Boettcher 			case AS_SEARCHING_GUARD:
3151173a64cbSPatrick Boettcher 					/* searching for the correct guard interval */
3152173a64cbSPatrick Boettcher 					if (state->revision == 0x8090)
3153173a64cbSPatrick Boettcher 						state->found_guard = dib8000_read_word(state, 572) & 0x3;
3154173a64cbSPatrick Boettcher 					else
3155173a64cbSPatrick Boettcher 						state->found_guard = dib8000_read_word(state, 570) & 0x3;
3156173a64cbSPatrick Boettcher 					/* dprintk("guard interval found=%i", state->found_guard); */
3157173a64cbSPatrick Boettcher 
3158173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_3;
3159173a64cbSPatrick Boettcher 					break;
3160173a64cbSPatrick Boettcher 			default:
3161173a64cbSPatrick Boettcher 					/* the demod should never be in this state */
3162173a64cbSPatrick Boettcher 					state->status = FE_STATUS_TUNE_FAILED;
3163173a64cbSPatrick Boettcher 					state->autosearch_state = AS_DONE;
3164173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STOP; /* else we are done here */
3165173a64cbSPatrick Boettcher 					break;
3166173a64cbSPatrick Boettcher 			}
3167173a64cbSPatrick Boettcher 			break;
3168173a64cbSPatrick Boettcher 
3169173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_3: /* 33 */
3170173a64cbSPatrick Boettcher 			state->symbol_duration = dib8000_get_symbol_duration(state);
3171173a64cbSPatrick Boettcher 			dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
3172173a64cbSPatrick Boettcher 			dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
3173173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_4;
3174173a64cbSPatrick Boettcher 			break;
3175173a64cbSPatrick Boettcher 
3176173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_4: /* (34) */
3177173a64cbSPatrick Boettcher 			dib8000_demod_restart(state);
3178173a64cbSPatrick Boettcher 
3179173a64cbSPatrick Boettcher 			dib8000_set_sync_wait(state);
3180173a64cbSPatrick Boettcher 			dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
3181173a64cbSPatrick Boettcher 
3182173a64cbSPatrick Boettcher 			locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
318339c1cb2bSJonathan McCrohan 			/* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */
3184173a64cbSPatrick Boettcher 			*timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
3185173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_5;
3186173a64cbSPatrick Boettcher 			break;
3187173a64cbSPatrick Boettcher 
3188173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_5: /* (35) */
3189173a64cbSPatrick Boettcher 			locks = dib8000_read_lock(fe);
3190173a64cbSPatrick Boettcher 			if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
3191173a64cbSPatrick Boettcher 				dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
3192173a64cbSPatrick Boettcher 				if (!state->differential_constellation) {
3193173a64cbSPatrick Boettcher 					/* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
3194173a64cbSPatrick Boettcher 					*timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
3195173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_7;
3196173a64cbSPatrick Boettcher 				} else {
3197173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_8;
3198173a64cbSPatrick Boettcher 				}
3199173a64cbSPatrick Boettcher 			} else if (now > *timeout) {
3200173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3201173a64cbSPatrick Boettcher 			}
3202173a64cbSPatrick Boettcher 			break;
3203173a64cbSPatrick Boettcher 
3204173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_6: /* (36)  if there is an input (diversity) */
3205173a64cbSPatrick Boettcher 			if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
3206173a64cbSPatrick 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 */
3207173a64cbSPatrick Boettcher 				if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
3208173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
3209173a64cbSPatrick Boettcher 				else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */
3210173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3211173a64cbSPatrick Boettcher 					dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3212173a64cbSPatrick Boettcher 					dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3213173a64cbSPatrick Boettcher 					state->status = FE_STATUS_TUNE_FAILED;
3214173a64cbSPatrick Boettcher 				}
3215173a64cbSPatrick Boettcher 			} else {
3216173a64cbSPatrick Boettcher 				dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3217173a64cbSPatrick Boettcher 				dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3218173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3219173a64cbSPatrick Boettcher 				state->status = FE_STATUS_TUNE_FAILED;
3220173a64cbSPatrick Boettcher 			}
3221173a64cbSPatrick Boettcher 			break;
3222173a64cbSPatrick Boettcher 
3223173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_7: /* 37 */
3224173a64cbSPatrick Boettcher 			locks = dib8000_read_lock(fe);
3225173a64cbSPatrick Boettcher 			if (locks & (1<<10)) { /* lmod4_lock */
3226173a64cbSPatrick Boettcher 				ret = 14; /* wait for 14 symbols */
3227173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_8;
3228173a64cbSPatrick Boettcher 			} else if (now > *timeout)
3229173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3230173a64cbSPatrick Boettcher 			break;
3231173a64cbSPatrick Boettcher 
3232173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_8: /* 38 */
3233173a64cbSPatrick Boettcher 			dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3234173a64cbSPatrick Boettcher 			dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3235173a64cbSPatrick Boettcher 
3236173a64cbSPatrick Boettcher 			/* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
3237746f7ae0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode
3238746f7ae0SMauro Carvalho Chehab 			    && c->isdbt_sb_subchannel < 14
3239746f7ae0SMauro Carvalho Chehab 			    && !state->differential_constellation) {
3240173a64cbSPatrick Boettcher 				state->subchannel = 0;
3241173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_11;
3242173a64cbSPatrick Boettcher 			} else {
3243173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_9;
3244173a64cbSPatrick Boettcher 				state->status = FE_STATUS_LOCKED;
3245173a64cbSPatrick Boettcher 			}
3246173a64cbSPatrick Boettcher 			break;
3247173a64cbSPatrick Boettcher 
3248173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_9: /* 39 */
3249173a64cbSPatrick Boettcher 			if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
325039c1cb2bSJonathan McCrohan 				/* defines timeout for mpeg lock depending on interleaver length of longest layer */
3251173a64cbSPatrick Boettcher 				for (i = 0; i < 3; i++) {
3252c82056d0SMauro Carvalho Chehab 					if (c->layer[i].interleaving >= deeper_interleaver) {
3253c82056d0SMauro Carvalho Chehab 						dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving);
3254c82056d0SMauro Carvalho Chehab 						if (c->layer[i].segment_count > 0) { /* valid layer */
3255c82056d0SMauro Carvalho Chehab 							deeper_interleaver = c->layer[0].interleaving;
3256173a64cbSPatrick Boettcher 							state->longest_intlv_layer = i;
3257173a64cbSPatrick Boettcher 						}
3258173a64cbSPatrick Boettcher 					}
3259173a64cbSPatrick Boettcher 				}
3260173a64cbSPatrick Boettcher 
3261173a64cbSPatrick Boettcher 				if (deeper_interleaver == 0)
3262173a64cbSPatrick Boettcher 					locks = 2; /* locks is the tmp local variable name */
3263173a64cbSPatrick Boettcher 				else if (deeper_interleaver == 3)
3264173a64cbSPatrick Boettcher 					locks = 8;
3265173a64cbSPatrick Boettcher 				else
3266173a64cbSPatrick Boettcher 					locks = 2 * deeper_interleaver;
3267173a64cbSPatrick Boettcher 
3268173a64cbSPatrick Boettcher 				if (state->diversity_onoff != 0) /* because of diversity sync */
3269173a64cbSPatrick Boettcher 					locks *= 2;
3270173a64cbSPatrick Boettcher 
3271173a64cbSPatrick Boettcher 				*timeout = now + (2000 * locks); /* give the mpeg lock 800ms if sram is present */
3272173a64cbSPatrick 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);
3273173a64cbSPatrick Boettcher 
3274173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_10;
3275173a64cbSPatrick Boettcher 			} else
3276173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP;
3277173a64cbSPatrick Boettcher 			break;
3278173a64cbSPatrick Boettcher 
3279173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_10: /* 40 */
3280173a64cbSPatrick Boettcher 			locks = dib8000_read_lock(fe);
3281173a64cbSPatrick Boettcher 			if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
3282173a64cbSPatrick Boettcher 				dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
3283746f7ae0SMauro Carvalho Chehab 				if (c->isdbt_sb_mode
3284746f7ae0SMauro Carvalho Chehab 				    && c->isdbt_sb_subchannel < 14
3285746f7ae0SMauro Carvalho Chehab 				    && !state->differential_constellation)
3286173a64cbSPatrick Boettcher 					/* signal to the upper layer, that there was a channel found and the parameters can be read */
3287173a64cbSPatrick Boettcher 					state->status = FE_STATUS_DEMOD_SUCCESS;
3288173a64cbSPatrick Boettcher 				else
3289173a64cbSPatrick Boettcher 					state->status = FE_STATUS_DATA_LOCKED;
3290173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP;
3291173a64cbSPatrick Boettcher 			} else if (now > *timeout) {
3292746f7ae0SMauro Carvalho Chehab 				if (c->isdbt_sb_mode
3293746f7ae0SMauro Carvalho Chehab 				    && c->isdbt_sb_subchannel < 14
3294746f7ae0SMauro Carvalho Chehab 				    && !state->differential_constellation) { /* continue to try init prbs autosearch */
3295173a64cbSPatrick Boettcher 					state->subchannel += 3;
3296173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_11;
3297173a64cbSPatrick 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 */
3298173a64cbSPatrick Boettcher 					if (locks & (0x7<<5)) {
3299173a64cbSPatrick Boettcher 						dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
3300173a64cbSPatrick Boettcher 						state->status = FE_STATUS_DATA_LOCKED;
3301173a64cbSPatrick Boettcher 					} else
3302173a64cbSPatrick Boettcher 						state->status = FE_STATUS_TUNE_FAILED;
3303173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STOP;
3304173a64cbSPatrick Boettcher 				}
3305173a64cbSPatrick Boettcher 			}
3306173a64cbSPatrick Boettcher 			break;
3307173a64cbSPatrick Boettcher 
3308173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_11:  /* 41 : init prbs autosearch */
3309173a64cbSPatrick Boettcher 			if (state->subchannel <= 41) {
3310173a64cbSPatrick Boettcher 				dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
3311173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_9;
3312173a64cbSPatrick Boettcher 			} else {
3313173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP;
3314173a64cbSPatrick Boettcher 				state->status = FE_STATUS_TUNE_FAILED;
3315173a64cbSPatrick Boettcher 			}
3316173a64cbSPatrick Boettcher 			break;
3317173a64cbSPatrick Boettcher 
3318173a64cbSPatrick Boettcher 	default:
3319173a64cbSPatrick Boettcher 			break;
3320173a64cbSPatrick Boettcher 	}
3321173a64cbSPatrick Boettcher 
3322173a64cbSPatrick Boettcher 	/* tuning is finished - cleanup the demod */
3323173a64cbSPatrick Boettcher 	switch (*tune_state) {
3324173a64cbSPatrick Boettcher 	case CT_DEMOD_STOP: /* (42) */
3325173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3326173a64cbSPatrick Boettcher 			if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
3327173a64cbSPatrick Boettcher 				dib8000_write_word(state, 108, state->agc1_max);
3328173a64cbSPatrick Boettcher 				dib8000_write_word(state, 109, state->agc1_min);
3329173a64cbSPatrick Boettcher 				dib8000_write_word(state, 110, state->agc2_max);
3330173a64cbSPatrick Boettcher 				dib8000_write_word(state, 111, state->agc2_min);
3331173a64cbSPatrick Boettcher 				state->agc1_max = 0;
3332173a64cbSPatrick Boettcher 				state->agc1_min = 0;
3333173a64cbSPatrick Boettcher 				state->agc2_max = 0;
3334173a64cbSPatrick Boettcher 				state->agc2_min = 0;
3335173a64cbSPatrick Boettcher 			}
3336173a64cbSPatrick Boettcher #endif
3337173a64cbSPatrick Boettcher 			ret = FE_CALLBACK_TIME_NEVER;
3338173a64cbSPatrick Boettcher 			break;
3339173a64cbSPatrick Boettcher 	default:
3340173a64cbSPatrick Boettcher 			break;
3341173a64cbSPatrick Boettcher 	}
3342173a64cbSPatrick Boettcher 
3343173a64cbSPatrick Boettcher 	if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
3344173a64cbSPatrick Boettcher 		return ret * state->symbol_duration;
3345173a64cbSPatrick Boettcher 	if ((ret > 0) && (ret < state->symbol_duration))
3346173a64cbSPatrick Boettcher 		return state->symbol_duration; /* at least one symbol */
33479a0bf528SMauro Carvalho Chehab 	return ret;
33489a0bf528SMauro Carvalho Chehab }
33499a0bf528SMauro Carvalho Chehab 
33509a0bf528SMauro Carvalho Chehab static int dib8000_wakeup(struct dvb_frontend *fe)
33519a0bf528SMauro Carvalho Chehab {
33529a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
33539a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
33549a0bf528SMauro Carvalho Chehab 	int ret;
33559a0bf528SMauro Carvalho Chehab 
33569a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
33579a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_ADC_ON);
33589a0bf528SMauro Carvalho Chehab 	if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
33599a0bf528SMauro Carvalho Chehab 		dprintk("could not start Slow ADC");
33609a0bf528SMauro Carvalho Chehab 
3361173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
33629a0bf528SMauro Carvalho Chehab 		dib8000_sad_calib(state);
33639a0bf528SMauro Carvalho Chehab 
33649a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
33659a0bf528SMauro Carvalho Chehab 		ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
33669a0bf528SMauro Carvalho Chehab 		if (ret < 0)
33679a0bf528SMauro Carvalho Chehab 			return ret;
33689a0bf528SMauro Carvalho Chehab 	}
33699a0bf528SMauro Carvalho Chehab 
33709a0bf528SMauro Carvalho Chehab 	return 0;
33719a0bf528SMauro Carvalho Chehab }
33729a0bf528SMauro Carvalho Chehab 
33739a0bf528SMauro Carvalho Chehab static int dib8000_sleep(struct dvb_frontend *fe)
33749a0bf528SMauro Carvalho Chehab {
33759a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
33769a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
33779a0bf528SMauro Carvalho Chehab 	int ret;
33789a0bf528SMauro Carvalho Chehab 
33799a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
33809a0bf528SMauro Carvalho Chehab 		ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
33819a0bf528SMauro Carvalho Chehab 		if (ret < 0)
33829a0bf528SMauro Carvalho Chehab 			return ret;
33839a0bf528SMauro Carvalho Chehab 	}
33849a0bf528SMauro Carvalho Chehab 
33859a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
33869a0bf528SMauro Carvalho Chehab 		dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
33879a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
33889a0bf528SMauro Carvalho Chehab 	return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
33899a0bf528SMauro Carvalho Chehab }
33909a0bf528SMauro Carvalho Chehab 
339170315b3eSMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat);
339270315b3eSMauro Carvalho Chehab 
33939a0bf528SMauro Carvalho Chehab static int dib8000_get_frontend(struct dvb_frontend *fe)
33949a0bf528SMauro Carvalho Chehab {
33959a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
33969a0bf528SMauro Carvalho Chehab 	u16 i, val = 0;
339770315b3eSMauro Carvalho Chehab 	fe_status_t stat = 0;
33989a0bf528SMauro Carvalho Chehab 	u8 index_frontend, sub_index_frontend;
33999a0bf528SMauro Carvalho Chehab 
34009a0bf528SMauro Carvalho Chehab 	fe->dtv_property_cache.bandwidth_hz = 6000000;
34019a0bf528SMauro Carvalho Chehab 
340270315b3eSMauro Carvalho Chehab 	/*
340370315b3eSMauro Carvalho Chehab 	 * If called to early, get_frontend makes dib8000_tune to either
340470315b3eSMauro Carvalho Chehab 	 * not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail.
340570315b3eSMauro Carvalho Chehab 	 * So, let's just return if frontend 0 has not locked.
340670315b3eSMauro Carvalho Chehab 	 */
340770315b3eSMauro Carvalho Chehab 	dib8000_read_status(fe, &stat);
340870315b3eSMauro Carvalho Chehab 	if (!(stat & FE_HAS_SYNC))
340970315b3eSMauro Carvalho Chehab 		return 0;
341070315b3eSMauro Carvalho Chehab 
341170315b3eSMauro Carvalho Chehab 	dprintk("TMCC lock");
34129a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
34139a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
34149a0bf528SMauro Carvalho Chehab 		if (stat&FE_HAS_SYNC) {
34159a0bf528SMauro Carvalho Chehab 			dprintk("TMCC lock on the slave%i", index_frontend);
34169a0bf528SMauro Carvalho Chehab 			/* synchronize the cache with the other frontends */
34179a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
34189a0bf528SMauro Carvalho Chehab 			for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {
34199a0bf528SMauro Carvalho Chehab 				if (sub_index_frontend != index_frontend) {
34209a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
34219a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
34229a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
34239a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
34249a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
34259a0bf528SMauro Carvalho Chehab 					for (i = 0; i < 3; i++) {
34269a0bf528SMauro 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;
34279a0bf528SMauro Carvalho Chehab 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
34289a0bf528SMauro Carvalho Chehab 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
34299a0bf528SMauro Carvalho Chehab 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
34309a0bf528SMauro Carvalho Chehab 					}
34319a0bf528SMauro Carvalho Chehab 				}
34329a0bf528SMauro Carvalho Chehab 			}
34339a0bf528SMauro Carvalho Chehab 			return 0;
34349a0bf528SMauro Carvalho Chehab 		}
34359a0bf528SMauro Carvalho Chehab 	}
34369a0bf528SMauro Carvalho Chehab 
34379a0bf528SMauro Carvalho Chehab 	fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
34389a0bf528SMauro Carvalho Chehab 
34399a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
34409a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 572);
34419a0bf528SMauro Carvalho Chehab 	else
34429a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 570);
34439a0bf528SMauro Carvalho Chehab 	fe->dtv_property_cache.inversion = (val & 0x40) >> 6;
34449a0bf528SMauro Carvalho Chehab 	switch ((val & 0x30) >> 4) {
34459a0bf528SMauro Carvalho Chehab 	case 1:
34469a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
34479a0bf528SMauro Carvalho Chehab 		break;
34489a0bf528SMauro Carvalho Chehab 	case 3:
34499a0bf528SMauro Carvalho Chehab 	default:
34509a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
34519a0bf528SMauro Carvalho Chehab 		break;
34529a0bf528SMauro Carvalho Chehab 	}
34539a0bf528SMauro Carvalho Chehab 
34549a0bf528SMauro Carvalho Chehab 	switch (val & 0x3) {
34559a0bf528SMauro Carvalho Chehab 	case 0:
34569a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
34579a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend GI = 1/32 ");
34589a0bf528SMauro Carvalho Chehab 		break;
34599a0bf528SMauro Carvalho Chehab 	case 1:
34609a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
34619a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend GI = 1/16 ");
34629a0bf528SMauro Carvalho Chehab 		break;
34639a0bf528SMauro Carvalho Chehab 	case 2:
34649a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend GI = 1/8 ");
34659a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
34669a0bf528SMauro Carvalho Chehab 		break;
34679a0bf528SMauro Carvalho Chehab 	case 3:
34689a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend GI = 1/4 ");
34699a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
34709a0bf528SMauro Carvalho Chehab 		break;
34719a0bf528SMauro Carvalho Chehab 	}
34729a0bf528SMauro Carvalho Chehab 
34739a0bf528SMauro Carvalho Chehab 	val = dib8000_read_word(state, 505);
34749a0bf528SMauro Carvalho Chehab 	fe->dtv_property_cache.isdbt_partial_reception = val & 1;
34759a0bf528SMauro Carvalho Chehab 	dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
34769a0bf528SMauro Carvalho Chehab 
34779a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 3; i++) {
34789a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 493 + i);
34799a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;
34809a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);
34819a0bf528SMauro Carvalho Chehab 
348251fea113SMauro Carvalho Chehab 		val = dib8000_read_word(state, 499 + i) & 0x3;
348351fea113SMauro Carvalho Chehab 		/* Interleaving can be 0, 1, 2 or 4 */
348451fea113SMauro Carvalho Chehab 		if (val == 3)
348551fea113SMauro Carvalho Chehab 			val = 4;
348651fea113SMauro Carvalho Chehab 		fe->dtv_property_cache.layer[i].interleaving = val;
348751fea113SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ",
348851fea113SMauro Carvalho Chehab 			i, fe->dtv_property_cache.layer[i].interleaving);
34899a0bf528SMauro Carvalho Chehab 
34909a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 481 + i);
34919a0bf528SMauro Carvalho Chehab 		switch (val & 0x7) {
34929a0bf528SMauro Carvalho Chehab 		case 1:
34939a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_1_2;
34949a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i);
34959a0bf528SMauro Carvalho Chehab 			break;
34969a0bf528SMauro Carvalho Chehab 		case 2:
34979a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_2_3;
34989a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i);
34999a0bf528SMauro Carvalho Chehab 			break;
35009a0bf528SMauro Carvalho Chehab 		case 3:
35019a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_3_4;
35029a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i);
35039a0bf528SMauro Carvalho Chehab 			break;
35049a0bf528SMauro Carvalho Chehab 		case 5:
35059a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_5_6;
35069a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i);
35079a0bf528SMauro Carvalho Chehab 			break;
35089a0bf528SMauro Carvalho Chehab 		default:
35099a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_7_8;
35109a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i);
35119a0bf528SMauro Carvalho Chehab 			break;
35129a0bf528SMauro Carvalho Chehab 		}
35139a0bf528SMauro Carvalho Chehab 
35149a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 487 + i);
35159a0bf528SMauro Carvalho Chehab 		switch (val & 0x3) {
35169a0bf528SMauro Carvalho Chehab 		case 0:
35179a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d DQPSK ", i);
35189a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].modulation = DQPSK;
35199a0bf528SMauro Carvalho Chehab 			break;
35209a0bf528SMauro Carvalho Chehab 		case 1:
35219a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].modulation = QPSK;
35229a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d QPSK ", i);
35239a0bf528SMauro Carvalho Chehab 			break;
35249a0bf528SMauro Carvalho Chehab 		case 2:
35259a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].modulation = QAM_16;
35269a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d QAM16 ", i);
35279a0bf528SMauro Carvalho Chehab 			break;
35289a0bf528SMauro Carvalho Chehab 		case 3:
35299a0bf528SMauro Carvalho Chehab 		default:
35309a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d QAM64 ", i);
35319a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].modulation = QAM_64;
35329a0bf528SMauro Carvalho Chehab 			break;
35339a0bf528SMauro Carvalho Chehab 		}
35349a0bf528SMauro Carvalho Chehab 	}
35359a0bf528SMauro Carvalho Chehab 
35369a0bf528SMauro Carvalho Chehab 	/* synchronize the cache with the other frontends */
35379a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
35389a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode;
35399a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
35409a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
35419a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
35429a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception;
35439a0bf528SMauro Carvalho Chehab 		for (i = 0; i < 3; i++) {
35449a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count;
35459a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving;
35469a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec;
35479a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation;
35489a0bf528SMauro Carvalho Chehab 		}
35499a0bf528SMauro Carvalho Chehab 	}
35509a0bf528SMauro Carvalho Chehab 	return 0;
35519a0bf528SMauro Carvalho Chehab }
35529a0bf528SMauro Carvalho Chehab 
35539a0bf528SMauro Carvalho Chehab static int dib8000_set_frontend(struct dvb_frontend *fe)
35549a0bf528SMauro Carvalho Chehab {
35559a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
3556c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
35574d8d5d92SGeert Uytterhoeven 	int l, i, active, time, time_slave = FE_CALLBACK_TIME_NEVER;
3558173a64cbSPatrick Boettcher 	u8 exit_condition, index_frontend;
3559173a64cbSPatrick Boettcher 	u32 delay, callback_time;
35609a0bf528SMauro Carvalho Chehab 
3561c82056d0SMauro Carvalho Chehab 	if (c->frequency == 0) {
35629a0bf528SMauro Carvalho Chehab 		dprintk("dib8000: must at least specify frequency ");
35639a0bf528SMauro Carvalho Chehab 		return 0;
35649a0bf528SMauro Carvalho Chehab 	}
35659a0bf528SMauro Carvalho Chehab 
3566c82056d0SMauro Carvalho Chehab 	if (c->bandwidth_hz == 0) {
35679a0bf528SMauro Carvalho Chehab 		dprintk("dib8000: no bandwidth specified, set to default ");
3568c82056d0SMauro Carvalho Chehab 		c->bandwidth_hz = 6000000;
35699a0bf528SMauro Carvalho Chehab 	}
35709a0bf528SMauro Carvalho Chehab 
35719a0bf528SMauro Carvalho Chehab 	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
35729a0bf528SMauro Carvalho Chehab 		/* synchronization of the cache */
35739a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
35749a0bf528SMauro Carvalho Chehab 		memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
35759a0bf528SMauro Carvalho Chehab 
3576173a64cbSPatrick Boettcher 		/* set output mode and diversity input */
3577173a64cbSPatrick Boettcher 		if (state->revision != 0x8090) {
3578173a64cbSPatrick Boettcher 			dib8000_set_diversity_in(state->fe[index_frontend], 1);
3579173a64cbSPatrick Boettcher 			if (index_frontend != 0)
35809a0bf528SMauro Carvalho Chehab 				dib8000_set_output_mode(state->fe[index_frontend],
3581173a64cbSPatrick Boettcher 						OUTMODE_DIVERSITY);
35829a0bf528SMauro Carvalho Chehab 			else
3583173a64cbSPatrick Boettcher 				dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3584173a64cbSPatrick Boettcher 		} else {
3585173a64cbSPatrick Boettcher 			dib8096p_set_diversity_in(state->fe[index_frontend], 1);
3586173a64cbSPatrick Boettcher 			if (index_frontend != 0)
35879a0bf528SMauro Carvalho Chehab 				dib8096p_set_output_mode(state->fe[index_frontend],
3588173a64cbSPatrick Boettcher 						OUTMODE_DIVERSITY);
3589173a64cbSPatrick Boettcher 			else
3590173a64cbSPatrick Boettcher 				dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3591173a64cbSPatrick Boettcher 		}
3592173a64cbSPatrick Boettcher 
3593173a64cbSPatrick Boettcher 		/* tune the tuner */
35949a0bf528SMauro Carvalho Chehab 		if (state->fe[index_frontend]->ops.tuner_ops.set_params)
35959a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
35969a0bf528SMauro Carvalho Chehab 
35979a0bf528SMauro Carvalho Chehab 		dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
35989a0bf528SMauro Carvalho Chehab 	}
35999a0bf528SMauro Carvalho Chehab 
3600173a64cbSPatrick Boettcher 	/* turn off the diversity of the last chip */
3601173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
3602173a64cbSPatrick Boettcher 		dib8000_set_diversity_in(state->fe[index_frontend - 1], 0);
3603173a64cbSPatrick Boettcher 	else
3604173a64cbSPatrick Boettcher 		dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0);
3605173a64cbSPatrick Boettcher 
36069a0bf528SMauro Carvalho Chehab 	/* start up the AGC */
36079a0bf528SMauro Carvalho Chehab 	do {
36089a0bf528SMauro Carvalho Chehab 		time = dib8000_agc_startup(state->fe[0]);
36099a0bf528SMauro Carvalho Chehab 		for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
36109a0bf528SMauro Carvalho Chehab 			time_slave = dib8000_agc_startup(state->fe[index_frontend]);
36119a0bf528SMauro Carvalho Chehab 			if (time == FE_CALLBACK_TIME_NEVER)
36129a0bf528SMauro Carvalho Chehab 				time = time_slave;
36139a0bf528SMauro Carvalho Chehab 			else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time))
36149a0bf528SMauro Carvalho Chehab 				time = time_slave;
36159a0bf528SMauro Carvalho Chehab 		}
36169a0bf528SMauro Carvalho Chehab 		if (time != FE_CALLBACK_TIME_NEVER)
36179a0bf528SMauro Carvalho Chehab 			msleep(time / 10);
36189a0bf528SMauro Carvalho Chehab 		else
36199a0bf528SMauro Carvalho Chehab 			break;
36209a0bf528SMauro Carvalho Chehab 		exit_condition = 1;
36219a0bf528SMauro Carvalho Chehab 		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
36229a0bf528SMauro Carvalho Chehab 			if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
36239a0bf528SMauro Carvalho Chehab 				exit_condition = 0;
36249a0bf528SMauro Carvalho Chehab 				break;
36259a0bf528SMauro Carvalho Chehab 			}
36269a0bf528SMauro Carvalho Chehab 		}
36279a0bf528SMauro Carvalho Chehab 	} while (exit_condition == 0);
36289a0bf528SMauro Carvalho Chehab 
36299a0bf528SMauro Carvalho Chehab 	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
36309a0bf528SMauro Carvalho Chehab 		dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
36319a0bf528SMauro Carvalho Chehab 
3632173a64cbSPatrick Boettcher 	active = 1;
36339a0bf528SMauro Carvalho Chehab 	do {
3634173a64cbSPatrick Boettcher 		callback_time = FE_CALLBACK_TIME_NEVER;
36359a0bf528SMauro Carvalho Chehab 		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3636173a64cbSPatrick Boettcher 			delay = dib8000_tune(state->fe[index_frontend]);
3637173a64cbSPatrick Boettcher 			if (delay != FE_CALLBACK_TIME_NEVER)
3638173a64cbSPatrick Boettcher 				delay += systime();
3639173a64cbSPatrick Boettcher 
3640173a64cbSPatrick Boettcher 			/* we are in autosearch */
3641173a64cbSPatrick Boettcher 			if (state->channel_parameters_set == 0) { /* searching */
3642173a64cbSPatrick Boettcher 				if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) {
3643173a64cbSPatrick Boettcher 					dprintk("autosearch succeeded on fe%i", index_frontend);
3644173a64cbSPatrick Boettcher 					dib8000_get_frontend(state->fe[index_frontend]); /* we read the channel parameters from the frontend which was successful */
3645173a64cbSPatrick Boettcher 					state->channel_parameters_set = 1;
3646173a64cbSPatrick Boettcher 
3647173a64cbSPatrick Boettcher 					for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
3648173a64cbSPatrick Boettcher 						if (l != index_frontend) { /* and for all frontend except the successful one */
3649173a64cbSPatrick Boettcher 							dib8000_tune_restart_from_demod(state->fe[l]);
3650173a64cbSPatrick Boettcher 
3651173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3652173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3653173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3654173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3655173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3656173a64cbSPatrick Boettcher 							for (i = 0; i < 3; i++) {
3657173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3658173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3659173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3660173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3661173a64cbSPatrick Boettcher 							}
3662173a64cbSPatrick Boettcher 
36639a0bf528SMauro Carvalho Chehab 						}
36649a0bf528SMauro Carvalho Chehab 					}
36659a0bf528SMauro Carvalho Chehab 				}
3666173a64cbSPatrick Boettcher 			}
3667173a64cbSPatrick Boettcher 			if (delay < callback_time)
3668173a64cbSPatrick Boettcher 				callback_time = delay;
3669173a64cbSPatrick Boettcher 		}
3670173a64cbSPatrick Boettcher 		/* tuning is done when the master frontend is done (failed or success) */
3671173a64cbSPatrick Boettcher 		if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
3672173a64cbSPatrick Boettcher 				dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED ||
3673173a64cbSPatrick Boettcher 				dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) {
3674173a64cbSPatrick Boettcher 			active = 0;
3675173a64cbSPatrick Boettcher 			/* we need to wait for all frontends to be finished */
3676173a64cbSPatrick Boettcher 			for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3677173a64cbSPatrick Boettcher 				if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP)
3678173a64cbSPatrick Boettcher 					active = 1;
3679173a64cbSPatrick Boettcher 			}
3680173a64cbSPatrick Boettcher 			if (active == 0)
3681173a64cbSPatrick Boettcher 				dprintk("tuning done with status %d", dib8000_get_status(state->fe[0]));
36829a0bf528SMauro Carvalho Chehab 		}
36839a0bf528SMauro Carvalho Chehab 
3684173a64cbSPatrick Boettcher 		if ((active == 1) && (callback_time == FE_CALLBACK_TIME_NEVER)) {
3685173a64cbSPatrick Boettcher 			dprintk("strange callback time something went wrong");
3686173a64cbSPatrick Boettcher 			active = 0;
36879a0bf528SMauro Carvalho Chehab 		}
36889a0bf528SMauro Carvalho Chehab 
3689173a64cbSPatrick Boettcher 		while ((active == 1) && (systime() < callback_time))
3690173a64cbSPatrick Boettcher 			msleep(100);
3691173a64cbSPatrick Boettcher 	} while (active);
36929a0bf528SMauro Carvalho Chehab 
3693173a64cbSPatrick Boettcher 	/* set output mode */
3694173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
36959a0bf528SMauro Carvalho Chehab 		dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
3696173a64cbSPatrick Boettcher 	else {
36979a0bf528SMauro Carvalho Chehab 		dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
36989a0bf528SMauro Carvalho Chehab 		if (state->cfg.enMpegOutput == 0) {
36999a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
37009a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
37019a0bf528SMauro Carvalho Chehab 		}
37029a0bf528SMauro Carvalho Chehab 	}
37039a0bf528SMauro Carvalho Chehab 
37044d8d5d92SGeert Uytterhoeven 	return 0;
37059a0bf528SMauro Carvalho Chehab }
37069a0bf528SMauro Carvalho Chehab 
37076ef06e78SMauro Carvalho Chehab static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat);
37086ef06e78SMauro Carvalho Chehab 
37099a0bf528SMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
37109a0bf528SMauro Carvalho Chehab {
37119a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37129a0bf528SMauro Carvalho Chehab 	u16 lock_slave = 0, lock;
37139a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
37149a0bf528SMauro Carvalho Chehab 
3715173a64cbSPatrick Boettcher 	lock = dib8000_read_lock(fe);
37169a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
37179a0bf528SMauro Carvalho Chehab 		lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
37189a0bf528SMauro Carvalho Chehab 
37199a0bf528SMauro Carvalho Chehab 	*stat = 0;
37209a0bf528SMauro Carvalho Chehab 
37219a0bf528SMauro Carvalho Chehab 	if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
37229a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SIGNAL;
37239a0bf528SMauro Carvalho Chehab 
37249a0bf528SMauro Carvalho Chehab 	if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
37259a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_CARRIER;
37269a0bf528SMauro Carvalho Chehab 
37279a0bf528SMauro Carvalho Chehab 	if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
37289a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SYNC;
37299a0bf528SMauro Carvalho Chehab 
37309a0bf528SMauro Carvalho Chehab 	if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
37319a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_LOCK;
37329a0bf528SMauro Carvalho Chehab 
37339a0bf528SMauro Carvalho Chehab 	if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
37349a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
37359a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
37369a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
37379a0bf528SMauro Carvalho Chehab 
37389a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
37399a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
37409a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
37419a0bf528SMauro Carvalho Chehab 
37429a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
37439a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
37449a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
37459a0bf528SMauro Carvalho Chehab 	}
37466ef06e78SMauro Carvalho Chehab 	dib8000_get_stats(fe, *stat);
37479a0bf528SMauro Carvalho Chehab 
37489a0bf528SMauro Carvalho Chehab 	return 0;
37499a0bf528SMauro Carvalho Chehab }
37509a0bf528SMauro Carvalho Chehab 
37519a0bf528SMauro Carvalho Chehab static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
37529a0bf528SMauro Carvalho Chehab {
37539a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37549a0bf528SMauro Carvalho Chehab 
37559a0bf528SMauro Carvalho Chehab 	/* 13 segments */
37569a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
37579a0bf528SMauro Carvalho Chehab 		*ber = (dib8000_read_word(state, 562) << 16) |
37589a0bf528SMauro Carvalho Chehab 			dib8000_read_word(state, 563);
37599a0bf528SMauro Carvalho Chehab 	else
37609a0bf528SMauro Carvalho Chehab 		*ber = (dib8000_read_word(state, 560) << 16) |
37619a0bf528SMauro Carvalho Chehab 			dib8000_read_word(state, 561);
37629a0bf528SMauro Carvalho Chehab 	return 0;
37639a0bf528SMauro Carvalho Chehab }
37649a0bf528SMauro Carvalho Chehab 
37659a0bf528SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
37669a0bf528SMauro Carvalho Chehab {
37679a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37689a0bf528SMauro Carvalho Chehab 
37699a0bf528SMauro Carvalho Chehab 	/* packet error on 13 seg */
37709a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
37719a0bf528SMauro Carvalho Chehab 		*unc = dib8000_read_word(state, 567);
37729a0bf528SMauro Carvalho Chehab 	else
37739a0bf528SMauro Carvalho Chehab 		*unc = dib8000_read_word(state, 565);
37749a0bf528SMauro Carvalho Chehab 	return 0;
37759a0bf528SMauro Carvalho Chehab }
37769a0bf528SMauro Carvalho Chehab 
37779a0bf528SMauro Carvalho Chehab static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
37789a0bf528SMauro Carvalho Chehab {
37799a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37809a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
37819a0bf528SMauro Carvalho Chehab 	u16 val;
37829a0bf528SMauro Carvalho Chehab 
37839a0bf528SMauro Carvalho Chehab 	*strength = 0;
37849a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
37859a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
37869a0bf528SMauro Carvalho Chehab 		if (val > 65535 - *strength)
37879a0bf528SMauro Carvalho Chehab 			*strength = 65535;
37889a0bf528SMauro Carvalho Chehab 		else
37899a0bf528SMauro Carvalho Chehab 			*strength += val;
37909a0bf528SMauro Carvalho Chehab 	}
37919a0bf528SMauro Carvalho Chehab 
37929a0bf528SMauro Carvalho Chehab 	val = 65535 - dib8000_read_word(state, 390);
37939a0bf528SMauro Carvalho Chehab 	if (val > 65535 - *strength)
37949a0bf528SMauro Carvalho Chehab 		*strength = 65535;
37959a0bf528SMauro Carvalho Chehab 	else
37969a0bf528SMauro Carvalho Chehab 		*strength += val;
37979a0bf528SMauro Carvalho Chehab 	return 0;
37989a0bf528SMauro Carvalho Chehab }
37999a0bf528SMauro Carvalho Chehab 
38009a0bf528SMauro Carvalho Chehab static u32 dib8000_get_snr(struct dvb_frontend *fe)
38019a0bf528SMauro Carvalho Chehab {
38029a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
38039a0bf528SMauro Carvalho Chehab 	u32 n, s, exp;
38049a0bf528SMauro Carvalho Chehab 	u16 val;
38059a0bf528SMauro Carvalho Chehab 
38069a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
38079a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 542);
38089a0bf528SMauro Carvalho Chehab 	else
38099a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 544);
38109a0bf528SMauro Carvalho Chehab 	n = (val >> 6) & 0xff;
38119a0bf528SMauro Carvalho Chehab 	exp = (val & 0x3f);
38129a0bf528SMauro Carvalho Chehab 	if ((exp & 0x20) != 0)
38139a0bf528SMauro Carvalho Chehab 		exp -= 0x40;
38149a0bf528SMauro Carvalho Chehab 	n <<= exp+16;
38159a0bf528SMauro Carvalho Chehab 
38169a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
38179a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 543);
38189a0bf528SMauro Carvalho Chehab 	else
38199a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 545);
38209a0bf528SMauro Carvalho Chehab 	s = (val >> 6) & 0xff;
38219a0bf528SMauro Carvalho Chehab 	exp = (val & 0x3f);
38229a0bf528SMauro Carvalho Chehab 	if ((exp & 0x20) != 0)
38239a0bf528SMauro Carvalho Chehab 		exp -= 0x40;
38249a0bf528SMauro Carvalho Chehab 	s <<= exp+16;
38259a0bf528SMauro Carvalho Chehab 
38269a0bf528SMauro Carvalho Chehab 	if (n > 0) {
38279a0bf528SMauro Carvalho Chehab 		u32 t = (s/n) << 16;
38289a0bf528SMauro Carvalho Chehab 		return t + ((s << 16) - n*t) / n;
38299a0bf528SMauro Carvalho Chehab 	}
38309a0bf528SMauro Carvalho Chehab 	return 0xffffffff;
38319a0bf528SMauro Carvalho Chehab }
38329a0bf528SMauro Carvalho Chehab 
38339a0bf528SMauro Carvalho Chehab static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
38349a0bf528SMauro Carvalho Chehab {
38359a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
38369a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
38379a0bf528SMauro Carvalho Chehab 	u32 snr_master;
38389a0bf528SMauro Carvalho Chehab 
38399a0bf528SMauro Carvalho Chehab 	snr_master = dib8000_get_snr(fe);
38409a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
38419a0bf528SMauro Carvalho Chehab 		snr_master += dib8000_get_snr(state->fe[index_frontend]);
38429a0bf528SMauro Carvalho Chehab 
38439a0bf528SMauro Carvalho Chehab 	if ((snr_master >> 16) != 0) {
38449a0bf528SMauro Carvalho Chehab 		snr_master = 10*intlog10(snr_master>>16);
38459a0bf528SMauro Carvalho Chehab 		*snr = snr_master / ((1 << 24) / 10);
38469a0bf528SMauro Carvalho Chehab 	}
38479a0bf528SMauro Carvalho Chehab 	else
38489a0bf528SMauro Carvalho Chehab 		*snr = 0;
38499a0bf528SMauro Carvalho Chehab 
38509a0bf528SMauro Carvalho Chehab 	return 0;
38519a0bf528SMauro Carvalho Chehab }
38529a0bf528SMauro Carvalho Chehab 
38536ef06e78SMauro Carvalho Chehab struct per_layer_regs {
38546ef06e78SMauro Carvalho Chehab 	u16 lock, ber, per;
38556ef06e78SMauro Carvalho Chehab };
38566ef06e78SMauro Carvalho Chehab 
38576ef06e78SMauro Carvalho Chehab static const struct per_layer_regs per_layer_regs[] = {
38586ef06e78SMauro Carvalho Chehab 	{ 554, 560, 562 },
38596ef06e78SMauro Carvalho Chehab 	{ 555, 576, 578 },
38606ef06e78SMauro Carvalho Chehab 	{ 556, 581, 583 },
38616ef06e78SMauro Carvalho Chehab };
38626ef06e78SMauro Carvalho Chehab 
386342ff76bdSMauro Carvalho Chehab struct linear_segments {
386442ff76bdSMauro Carvalho Chehab 	unsigned x;
386542ff76bdSMauro Carvalho Chehab 	signed y;
386642ff76bdSMauro Carvalho Chehab };
386742ff76bdSMauro Carvalho Chehab 
386842ff76bdSMauro Carvalho Chehab /*
386942ff76bdSMauro Carvalho Chehab  * Table to estimate signal strength in dBm.
387042ff76bdSMauro Carvalho Chehab  * This table was empirically determinated by measuring the signal
387142ff76bdSMauro Carvalho Chehab  * strength generated by a DTA-2111 RF generator directly connected into
387242ff76bdSMauro Carvalho Chehab  * a dib8076 device (a PixelView PV-D231U stick), using a good quality
387342ff76bdSMauro Carvalho Chehab  * 3 meters RC6 cable and good RC6 connectors.
387442ff76bdSMauro Carvalho Chehab  * The real value can actually be different on other devices, depending
387542ff76bdSMauro Carvalho Chehab  * on several factors, like if LNA is enabled or not, if diversity is
387642ff76bdSMauro Carvalho Chehab  * enabled, type of connectors, etc.
387742ff76bdSMauro Carvalho Chehab  * Yet, it is better to use this measure in dB than a random non-linear
387842ff76bdSMauro Carvalho Chehab  * percentage value, especially for antenna adjustments.
387942ff76bdSMauro Carvalho Chehab  * On my tests, the precision of the measure using this table is about
388042ff76bdSMauro Carvalho Chehab  * 0.5 dB, with sounds reasonable enough.
388142ff76bdSMauro Carvalho Chehab  */
388242ff76bdSMauro Carvalho Chehab static struct linear_segments strength_to_db_table[] = {
388342ff76bdSMauro Carvalho Chehab 	{ 55953, 108500 },	/* -22.5 dBm */
388442ff76bdSMauro Carvalho Chehab 	{ 55394, 108000 },
388542ff76bdSMauro Carvalho Chehab 	{ 53834, 107000 },
388642ff76bdSMauro Carvalho Chehab 	{ 52863, 106000 },
388742ff76bdSMauro Carvalho Chehab 	{ 52239, 105000 },
388842ff76bdSMauro Carvalho Chehab 	{ 52012, 104000 },
388942ff76bdSMauro Carvalho Chehab 	{ 51803, 103000 },
389042ff76bdSMauro Carvalho Chehab 	{ 51566, 102000 },
389142ff76bdSMauro Carvalho Chehab 	{ 51356, 101000 },
389242ff76bdSMauro Carvalho Chehab 	{ 51112, 100000 },
389342ff76bdSMauro Carvalho Chehab 	{ 50869,  99000 },
389442ff76bdSMauro Carvalho Chehab 	{ 50600,  98000 },
389542ff76bdSMauro Carvalho Chehab 	{ 50363,  97000 },
389642ff76bdSMauro Carvalho Chehab 	{ 50117,  96000 },	/* -35 dBm */
389742ff76bdSMauro Carvalho Chehab 	{ 49889,  95000 },
389842ff76bdSMauro Carvalho Chehab 	{ 49680,  94000 },
389942ff76bdSMauro Carvalho Chehab 	{ 49493,  93000 },
390042ff76bdSMauro Carvalho Chehab 	{ 49302,  92000 },
390142ff76bdSMauro Carvalho Chehab 	{ 48929,  91000 },
390242ff76bdSMauro Carvalho Chehab 	{ 48416,  90000 },
390342ff76bdSMauro Carvalho Chehab 	{ 48035,  89000 },
390442ff76bdSMauro Carvalho Chehab 	{ 47593,  88000 },
390542ff76bdSMauro Carvalho Chehab 	{ 47282,  87000 },
390642ff76bdSMauro Carvalho Chehab 	{ 46953,  86000 },
390742ff76bdSMauro Carvalho Chehab 	{ 46698,  85000 },
390842ff76bdSMauro Carvalho Chehab 	{ 45617,  84000 },
390942ff76bdSMauro Carvalho Chehab 	{ 44773,  83000 },
391042ff76bdSMauro Carvalho Chehab 	{ 43845,  82000 },
391142ff76bdSMauro Carvalho Chehab 	{ 43020,  81000 },
391242ff76bdSMauro Carvalho Chehab 	{ 42010,  80000 },	/* -51 dBm */
391342ff76bdSMauro Carvalho Chehab 	{     0,      0 },
391442ff76bdSMauro Carvalho Chehab };
391542ff76bdSMauro Carvalho Chehab 
391642ff76bdSMauro Carvalho Chehab static u32 interpolate_value(u32 value, struct linear_segments *segments,
391742ff76bdSMauro Carvalho Chehab 			     unsigned len)
391842ff76bdSMauro Carvalho Chehab {
391942ff76bdSMauro Carvalho Chehab 	u64 tmp64;
392042ff76bdSMauro Carvalho Chehab 	u32 dx;
392142ff76bdSMauro Carvalho Chehab 	s32 dy;
392242ff76bdSMauro Carvalho Chehab 	int i, ret;
392342ff76bdSMauro Carvalho Chehab 
392442ff76bdSMauro Carvalho Chehab 	if (value >= segments[0].x)
392542ff76bdSMauro Carvalho Chehab 		return segments[0].y;
392642ff76bdSMauro Carvalho Chehab 	if (value < segments[len-1].x)
392742ff76bdSMauro Carvalho Chehab 		return segments[len-1].y;
392842ff76bdSMauro Carvalho Chehab 
392942ff76bdSMauro Carvalho Chehab 	for (i = 1; i < len - 1; i++) {
393042ff76bdSMauro Carvalho Chehab 		/* If value is identical, no need to interpolate */
393142ff76bdSMauro Carvalho Chehab 		if (value == segments[i].x)
393242ff76bdSMauro Carvalho Chehab 			return segments[i].y;
393342ff76bdSMauro Carvalho Chehab 		if (value > segments[i].x)
393442ff76bdSMauro Carvalho Chehab 			break;
393542ff76bdSMauro Carvalho Chehab 	}
393642ff76bdSMauro Carvalho Chehab 
393742ff76bdSMauro Carvalho Chehab 	/* Linear interpolation between the two (x,y) points */
393842ff76bdSMauro Carvalho Chehab 	dy = segments[i - 1].y - segments[i].y;
393942ff76bdSMauro Carvalho Chehab 	dx = segments[i - 1].x - segments[i].x;
394042ff76bdSMauro Carvalho Chehab 
394142ff76bdSMauro Carvalho Chehab 	tmp64 = value - segments[i].x;
394242ff76bdSMauro Carvalho Chehab 	tmp64 *= dy;
394342ff76bdSMauro Carvalho Chehab 	do_div(tmp64, dx);
394442ff76bdSMauro Carvalho Chehab 	ret = segments[i].y + tmp64;
394542ff76bdSMauro Carvalho Chehab 
394642ff76bdSMauro Carvalho Chehab 	return ret;
394742ff76bdSMauro Carvalho Chehab }
394842ff76bdSMauro Carvalho Chehab 
3949704f01bbSMauro Carvalho Chehab static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer)
3950704f01bbSMauro Carvalho Chehab {
3951704f01bbSMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
3952704f01bbSMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3953704f01bbSMauro Carvalho Chehab 	int ini_layer, end_layer, i;
39544bf48150SMauro Carvalho Chehab 	u64 time_us, tmp64;
3955704f01bbSMauro Carvalho Chehab 	u32 tmp, denom;
3956e4a3bc1cSMauro Carvalho Chehab 	int guard, rate_num, rate_denum = 1, bits_per_symbol, nsegs;
3957e4a3bc1cSMauro Carvalho Chehab 	int interleaving = 0, fft_div;
3958704f01bbSMauro Carvalho Chehab 
3959704f01bbSMauro Carvalho Chehab 	if (layer >= 0) {
3960704f01bbSMauro Carvalho Chehab 		ini_layer = layer;
3961704f01bbSMauro Carvalho Chehab 		end_layer = layer + 1;
3962704f01bbSMauro Carvalho Chehab 	} else {
3963704f01bbSMauro Carvalho Chehab 		ini_layer = 0;
3964704f01bbSMauro Carvalho Chehab 		end_layer = 3;
3965704f01bbSMauro Carvalho Chehab 	}
3966704f01bbSMauro Carvalho Chehab 
3967704f01bbSMauro Carvalho Chehab 	switch (c->guard_interval) {
3968704f01bbSMauro Carvalho Chehab 	case GUARD_INTERVAL_1_4:
3969704f01bbSMauro Carvalho Chehab 		guard = 4;
3970704f01bbSMauro Carvalho Chehab 		break;
3971704f01bbSMauro Carvalho Chehab 	case GUARD_INTERVAL_1_8:
3972704f01bbSMauro Carvalho Chehab 		guard = 8;
3973704f01bbSMauro Carvalho Chehab 		break;
3974704f01bbSMauro Carvalho Chehab 	case GUARD_INTERVAL_1_16:
3975704f01bbSMauro Carvalho Chehab 		guard = 16;
3976704f01bbSMauro Carvalho Chehab 		break;
3977704f01bbSMauro Carvalho Chehab 	default:
3978704f01bbSMauro Carvalho Chehab 	case GUARD_INTERVAL_1_32:
3979704f01bbSMauro Carvalho Chehab 		guard = 32;
3980704f01bbSMauro Carvalho Chehab 		break;
3981704f01bbSMauro Carvalho Chehab 	}
3982704f01bbSMauro Carvalho Chehab 
3983704f01bbSMauro Carvalho Chehab 	switch (c->transmission_mode) {
3984704f01bbSMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
3985704f01bbSMauro Carvalho Chehab 		fft_div = 4;
3986704f01bbSMauro Carvalho Chehab 		break;
3987704f01bbSMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
3988704f01bbSMauro Carvalho Chehab 		fft_div = 2;
3989704f01bbSMauro Carvalho Chehab 		break;
3990704f01bbSMauro Carvalho Chehab 	default:
3991704f01bbSMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
3992704f01bbSMauro Carvalho Chehab 		fft_div = 1;
3993704f01bbSMauro Carvalho Chehab 		break;
3994704f01bbSMauro Carvalho Chehab 	}
3995704f01bbSMauro Carvalho Chehab 
3996704f01bbSMauro Carvalho Chehab 	denom = 0;
3997704f01bbSMauro Carvalho Chehab 	for (i = ini_layer; i < end_layer; i++) {
3998704f01bbSMauro Carvalho Chehab 		nsegs = c->layer[i].segment_count;
3999704f01bbSMauro Carvalho Chehab 		if (nsegs == 0 || nsegs > 13)
4000704f01bbSMauro Carvalho Chehab 			continue;
4001704f01bbSMauro Carvalho Chehab 
4002704f01bbSMauro Carvalho Chehab 		switch (c->layer[i].modulation) {
4003704f01bbSMauro Carvalho Chehab 		case DQPSK:
4004704f01bbSMauro Carvalho Chehab 		case QPSK:
4005704f01bbSMauro Carvalho Chehab 			bits_per_symbol = 2;
4006704f01bbSMauro Carvalho Chehab 			break;
4007704f01bbSMauro Carvalho Chehab 		case QAM_16:
4008704f01bbSMauro Carvalho Chehab 			bits_per_symbol = 4;
4009704f01bbSMauro Carvalho Chehab 			break;
4010704f01bbSMauro Carvalho Chehab 		default:
4011704f01bbSMauro Carvalho Chehab 		case QAM_64:
4012704f01bbSMauro Carvalho Chehab 			bits_per_symbol = 6;
4013704f01bbSMauro Carvalho Chehab 			break;
4014704f01bbSMauro Carvalho Chehab 		}
4015704f01bbSMauro Carvalho Chehab 
4016704f01bbSMauro Carvalho Chehab 		switch (c->layer[i].fec) {
4017704f01bbSMauro Carvalho Chehab 		case FEC_1_2:
4018704f01bbSMauro Carvalho Chehab 			rate_num = 1;
4019704f01bbSMauro Carvalho Chehab 			rate_denum = 2;
4020704f01bbSMauro Carvalho Chehab 			break;
4021704f01bbSMauro Carvalho Chehab 		case FEC_2_3:
4022704f01bbSMauro Carvalho Chehab 			rate_num = 2;
4023704f01bbSMauro Carvalho Chehab 			rate_denum = 3;
4024704f01bbSMauro Carvalho Chehab 			break;
4025704f01bbSMauro Carvalho Chehab 		case FEC_3_4:
4026704f01bbSMauro Carvalho Chehab 			rate_num = 3;
4027704f01bbSMauro Carvalho Chehab 			rate_denum = 4;
4028704f01bbSMauro Carvalho Chehab 			break;
4029704f01bbSMauro Carvalho Chehab 		case FEC_5_6:
4030704f01bbSMauro Carvalho Chehab 			rate_num = 5;
4031704f01bbSMauro Carvalho Chehab 			rate_denum = 6;
4032704f01bbSMauro Carvalho Chehab 			break;
4033704f01bbSMauro Carvalho Chehab 		default:
4034704f01bbSMauro Carvalho Chehab 		case FEC_7_8:
4035704f01bbSMauro Carvalho Chehab 			rate_num = 7;
4036704f01bbSMauro Carvalho Chehab 			rate_denum = 8;
4037704f01bbSMauro Carvalho Chehab 			break;
4038704f01bbSMauro Carvalho Chehab 		}
4039704f01bbSMauro Carvalho Chehab 
4040704f01bbSMauro Carvalho Chehab 		interleaving = c->layer[i].interleaving;
4041704f01bbSMauro Carvalho Chehab 
4042704f01bbSMauro Carvalho Chehab 		denom += bits_per_symbol * rate_num * fft_div * nsegs * 384;
4043704f01bbSMauro Carvalho Chehab 	}
4044704f01bbSMauro Carvalho Chehab 
4045704f01bbSMauro Carvalho Chehab 	/* If all goes wrong, wait for 1s for the next stats */
4046704f01bbSMauro Carvalho Chehab 	if (!denom)
4047704f01bbSMauro Carvalho Chehab 		return 0;
4048704f01bbSMauro Carvalho Chehab 
4049704f01bbSMauro Carvalho Chehab 	/* Estimate the period for the total bit rate */
4050704f01bbSMauro Carvalho Chehab 	time_us = rate_denum * (1008 * 1562500L);
40514bf48150SMauro Carvalho Chehab 	tmp64 = time_us;
40524bf48150SMauro Carvalho Chehab 	do_div(tmp64, guard);
40534bf48150SMauro Carvalho Chehab 	time_us = time_us + tmp64;
4054704f01bbSMauro Carvalho Chehab 	time_us += denom / 2;
4055704f01bbSMauro Carvalho Chehab 	do_div(time_us, denom);
4056704f01bbSMauro Carvalho Chehab 
4057704f01bbSMauro Carvalho Chehab 	tmp = 1008 * 96 * interleaving;
4058704f01bbSMauro Carvalho Chehab 	time_us += tmp + tmp / guard;
4059704f01bbSMauro Carvalho Chehab 
4060704f01bbSMauro Carvalho Chehab 	return time_us;
4061704f01bbSMauro Carvalho Chehab }
4062704f01bbSMauro Carvalho Chehab 
40636ef06e78SMauro Carvalho Chehab static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
40646ef06e78SMauro Carvalho Chehab {
40656ef06e78SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
40666ef06e78SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
4067704f01bbSMauro Carvalho Chehab 	int i;
40680400c535SMauro Carvalho Chehab 	int show_per_stats = 0;
40690400c535SMauro Carvalho Chehab 	u32 time_us = 0, snr, val;
40700400c535SMauro Carvalho Chehab 	u64 blocks;
407142ff76bdSMauro Carvalho Chehab 	s32 db;
40726ef06e78SMauro Carvalho Chehab 	u16 strength;
40736ef06e78SMauro Carvalho Chehab 
40746ef06e78SMauro Carvalho Chehab 	/* Get Signal strength */
40756ef06e78SMauro Carvalho Chehab 	dib8000_read_signal_strength(fe, &strength);
407642ff76bdSMauro Carvalho Chehab 	val = strength;
407742ff76bdSMauro Carvalho Chehab 	db = interpolate_value(val,
407842ff76bdSMauro Carvalho Chehab 			       strength_to_db_table,
407942ff76bdSMauro Carvalho Chehab 			       ARRAY_SIZE(strength_to_db_table)) - 131000;
408042ff76bdSMauro Carvalho Chehab 	c->strength.stat[0].svalue = db;
40816ef06e78SMauro Carvalho Chehab 
4082704f01bbSMauro Carvalho Chehab 	/* UCB/BER/CNR measures require lock */
4083704f01bbSMauro Carvalho Chehab 	if (!(stat & FE_HAS_LOCK)) {
4084704f01bbSMauro Carvalho Chehab 		c->cnr.len = 1;
40850400c535SMauro Carvalho Chehab 		c->block_count.len = 1;
4086704f01bbSMauro Carvalho Chehab 		c->block_error.len = 1;
4087704f01bbSMauro Carvalho Chehab 		c->post_bit_error.len = 1;
4088704f01bbSMauro Carvalho Chehab 		c->post_bit_count.len = 1;
4089704f01bbSMauro Carvalho Chehab 		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4090704f01bbSMauro Carvalho Chehab 		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4091704f01bbSMauro Carvalho Chehab 		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4092704f01bbSMauro Carvalho Chehab 		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
40930400c535SMauro Carvalho Chehab 		c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
40946ef06e78SMauro Carvalho Chehab 		return 0;
4095704f01bbSMauro Carvalho Chehab 	}
4096704f01bbSMauro Carvalho Chehab 
4097704f01bbSMauro Carvalho Chehab 	/* Check if time for stats was elapsed */
40980400c535SMauro Carvalho Chehab 	if (time_after(jiffies, state->per_jiffies_stats)) {
40990400c535SMauro Carvalho Chehab 		state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
41006ef06e78SMauro Carvalho Chehab 
41016ef06e78SMauro Carvalho Chehab 		/* Get SNR */
41026ef06e78SMauro Carvalho Chehab 		snr = dib8000_get_snr(fe);
41036ef06e78SMauro Carvalho Chehab 		for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) {
41046ef06e78SMauro Carvalho Chehab 			if (state->fe[i])
41056ef06e78SMauro Carvalho Chehab 				snr += dib8000_get_snr(state->fe[i]);
41066ef06e78SMauro Carvalho Chehab 		}
41076ef06e78SMauro Carvalho Chehab 		snr = snr >> 16;
41086ef06e78SMauro Carvalho Chehab 
41096ef06e78SMauro Carvalho Chehab 		if (snr) {
41106ef06e78SMauro Carvalho Chehab 			snr = 10 * intlog10(snr);
41116ef06e78SMauro Carvalho Chehab 			snr = (1000L * snr) >> 24;
41126ef06e78SMauro Carvalho Chehab 		} else {
41136ef06e78SMauro Carvalho Chehab 			snr = 0;
41146ef06e78SMauro Carvalho Chehab 		}
41156ef06e78SMauro Carvalho Chehab 		c->cnr.stat[0].svalue = snr;
41166ef06e78SMauro Carvalho Chehab 		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
41176ef06e78SMauro Carvalho Chehab 
41180400c535SMauro Carvalho Chehab 		/* Get UCB measures */
41190400c535SMauro Carvalho Chehab 		dib8000_read_unc_blocks(fe, &val);
41200400c535SMauro Carvalho Chehab 		if (val < state->init_ucb)
41215dc8526bSMauro Carvalho Chehab 			state->init_ucb += 0x100000000LL;
41220400c535SMauro Carvalho Chehab 
41230400c535SMauro Carvalho Chehab 		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
41240400c535SMauro Carvalho Chehab 		c->block_error.stat[0].uvalue = val + state->init_ucb;
41250400c535SMauro Carvalho Chehab 
41260400c535SMauro Carvalho Chehab 		/* Estimate the number of packets based on bitrate */
41270400c535SMauro Carvalho Chehab 		if (!time_us)
41280400c535SMauro Carvalho Chehab 			time_us = dib8000_get_time_us(fe, -1);
41290400c535SMauro Carvalho Chehab 
41300400c535SMauro Carvalho Chehab 		if (time_us) {
41315dc8526bSMauro Carvalho Chehab 			blocks = 1250000ULL * 1000000ULL;
41320400c535SMauro Carvalho Chehab 			do_div(blocks, time_us * 8 * 204);
41330400c535SMauro Carvalho Chehab 			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
41340400c535SMauro Carvalho Chehab 			c->block_count.stat[0].uvalue += blocks;
41350400c535SMauro Carvalho Chehab 		}
41360400c535SMauro Carvalho Chehab 
41370400c535SMauro Carvalho Chehab 		show_per_stats = 1;
41380400c535SMauro Carvalho Chehab 	}
41390400c535SMauro Carvalho Chehab 
41400400c535SMauro Carvalho Chehab 	/* Get post-BER measures */
41410400c535SMauro Carvalho Chehab 	if (time_after(jiffies, state->ber_jiffies_stats)) {
41420400c535SMauro Carvalho Chehab 		time_us = dib8000_get_time_us(fe, -1);
41430400c535SMauro Carvalho Chehab 		state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
41440400c535SMauro Carvalho Chehab 
41450400c535SMauro Carvalho Chehab 		dprintk("Next all layers stats available in %u us.", time_us);
41466ef06e78SMauro Carvalho Chehab 
41476ef06e78SMauro Carvalho Chehab 		dib8000_read_ber(fe, &val);
41486ef06e78SMauro Carvalho Chehab 		c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
41496ef06e78SMauro Carvalho Chehab 		c->post_bit_error.stat[0].uvalue += val;
41506ef06e78SMauro Carvalho Chehab 
41516ef06e78SMauro Carvalho Chehab 		c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
41526ef06e78SMauro Carvalho Chehab 		c->post_bit_count.stat[0].uvalue += 100000000;
4153704f01bbSMauro Carvalho Chehab 	}
41546ef06e78SMauro Carvalho Chehab 
41556ef06e78SMauro Carvalho Chehab 	if (state->revision < 0x8002)
41566ef06e78SMauro Carvalho Chehab 		return 0;
41576ef06e78SMauro Carvalho Chehab 
41586ef06e78SMauro Carvalho Chehab 	c->block_error.len = 4;
41596ef06e78SMauro Carvalho Chehab 	c->post_bit_error.len = 4;
41606ef06e78SMauro Carvalho Chehab 	c->post_bit_count.len = 4;
41616ef06e78SMauro Carvalho Chehab 
41626ef06e78SMauro Carvalho Chehab 	for (i = 0; i < 3; i++) {
41630400c535SMauro Carvalho Chehab 		unsigned nsegs = c->layer[i].segment_count;
41640400c535SMauro Carvalho Chehab 
41650400c535SMauro Carvalho Chehab 		if (nsegs == 0 || nsegs > 13)
4166704f01bbSMauro Carvalho Chehab 			continue;
4167704f01bbSMauro Carvalho Chehab 
41680400c535SMauro Carvalho Chehab 		time_us = 0;
41690400c535SMauro Carvalho Chehab 
41700400c535SMauro Carvalho Chehab 		if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) {
41710400c535SMauro Carvalho Chehab 			time_us = dib8000_get_time_us(fe, i);
41720400c535SMauro Carvalho Chehab 
41730400c535SMauro Carvalho Chehab 			state->ber_jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
4174704f01bbSMauro Carvalho Chehab 			dprintk("Next layer %c  stats will be available in %u us\n",
4175704f01bbSMauro Carvalho Chehab 				'A' + i, time_us);
4176704f01bbSMauro Carvalho Chehab 
41776ef06e78SMauro Carvalho Chehab 			val = dib8000_read_word(state, per_layer_regs[i].ber);
41786ef06e78SMauro Carvalho Chehab 			c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
41796ef06e78SMauro Carvalho Chehab 			c->post_bit_error.stat[1 + i].uvalue += val;
41806ef06e78SMauro Carvalho Chehab 
41816ef06e78SMauro Carvalho Chehab 			c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
41826ef06e78SMauro Carvalho Chehab 			c->post_bit_count.stat[1 + i].uvalue += 100000000;
41830400c535SMauro Carvalho Chehab 		}
41846ef06e78SMauro Carvalho Chehab 
41850400c535SMauro Carvalho Chehab 		if (show_per_stats) {
41866ef06e78SMauro Carvalho Chehab 			val = dib8000_read_word(state, per_layer_regs[i].per);
41876ef06e78SMauro Carvalho Chehab 
41886ef06e78SMauro Carvalho Chehab 			c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
41896ef06e78SMauro Carvalho Chehab 			c->block_error.stat[1 + i].uvalue += val;
41900400c535SMauro Carvalho Chehab 
41910400c535SMauro Carvalho Chehab 			if (!time_us)
41920400c535SMauro Carvalho Chehab 				time_us = dib8000_get_time_us(fe, i);
41930400c535SMauro Carvalho Chehab 			if (time_us) {
41945dc8526bSMauro Carvalho Chehab 				blocks = 1250000ULL * 1000000ULL;
41950400c535SMauro Carvalho Chehab 				do_div(blocks, time_us * 8 * 204);
41960400c535SMauro Carvalho Chehab 				c->block_count.stat[0].scale = FE_SCALE_COUNTER;
41970400c535SMauro Carvalho Chehab 				c->block_count.stat[0].uvalue += blocks;
41980400c535SMauro Carvalho Chehab 			}
41990400c535SMauro Carvalho Chehab 		}
42006ef06e78SMauro Carvalho Chehab 	}
42016ef06e78SMauro Carvalho Chehab 	return 0;
42026ef06e78SMauro Carvalho Chehab }
42036ef06e78SMauro Carvalho Chehab 
42049a0bf528SMauro Carvalho Chehab int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
42059a0bf528SMauro Carvalho Chehab {
42069a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
42079a0bf528SMauro Carvalho Chehab 	u8 index_frontend = 1;
42089a0bf528SMauro Carvalho Chehab 
42099a0bf528SMauro Carvalho Chehab 	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
42109a0bf528SMauro Carvalho Chehab 		index_frontend++;
42119a0bf528SMauro Carvalho Chehab 	if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
42129a0bf528SMauro Carvalho Chehab 		dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
42139a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend] = fe_slave;
42149a0bf528SMauro Carvalho Chehab 		return 0;
42159a0bf528SMauro Carvalho Chehab 	}
42169a0bf528SMauro Carvalho Chehab 
42179a0bf528SMauro Carvalho Chehab 	dprintk("too many slave frontend");
42189a0bf528SMauro Carvalho Chehab 	return -ENOMEM;
42199a0bf528SMauro Carvalho Chehab }
42209a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_set_slave_frontend);
42219a0bf528SMauro Carvalho Chehab 
42229a0bf528SMauro Carvalho Chehab int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
42239a0bf528SMauro Carvalho Chehab {
42249a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
42259a0bf528SMauro Carvalho Chehab 	u8 index_frontend = 1;
42269a0bf528SMauro Carvalho Chehab 
42279a0bf528SMauro Carvalho Chehab 	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
42289a0bf528SMauro Carvalho Chehab 		index_frontend++;
42299a0bf528SMauro Carvalho Chehab 	if (index_frontend != 1) {
42309a0bf528SMauro Carvalho Chehab 		dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1);
42319a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend] = NULL;
42329a0bf528SMauro Carvalho Chehab 		return 0;
42339a0bf528SMauro Carvalho Chehab 	}
42349a0bf528SMauro Carvalho Chehab 
42359a0bf528SMauro Carvalho Chehab 	dprintk("no frontend to be removed");
42369a0bf528SMauro Carvalho Chehab 	return -ENODEV;
42379a0bf528SMauro Carvalho Chehab }
42389a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_remove_slave_frontend);
42399a0bf528SMauro Carvalho Chehab 
42409a0bf528SMauro Carvalho Chehab struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
42419a0bf528SMauro Carvalho Chehab {
42429a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
42439a0bf528SMauro Carvalho Chehab 
42449a0bf528SMauro Carvalho Chehab 	if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
42459a0bf528SMauro Carvalho Chehab 		return NULL;
42469a0bf528SMauro Carvalho Chehab 	return state->fe[slave_index];
42479a0bf528SMauro Carvalho Chehab }
42489a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_get_slave_frontend);
42499a0bf528SMauro Carvalho Chehab 
42509a0bf528SMauro Carvalho Chehab 
42519a0bf528SMauro Carvalho Chehab int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
42529a0bf528SMauro Carvalho Chehab 		u8 default_addr, u8 first_addr, u8 is_dib8096p)
42539a0bf528SMauro Carvalho Chehab {
42549a0bf528SMauro Carvalho Chehab 	int k = 0, ret = 0;
42559a0bf528SMauro Carvalho Chehab 	u8 new_addr = 0;
42569a0bf528SMauro Carvalho Chehab 	struct i2c_device client = {.adap = host };
42579a0bf528SMauro Carvalho Chehab 
42589a0bf528SMauro Carvalho Chehab 	client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
42599a0bf528SMauro Carvalho Chehab 	if (!client.i2c_write_buffer) {
42609a0bf528SMauro Carvalho Chehab 		dprintk("%s: not enough memory", __func__);
42619a0bf528SMauro Carvalho Chehab 		return -ENOMEM;
42629a0bf528SMauro Carvalho Chehab 	}
42639a0bf528SMauro Carvalho Chehab 	client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
42649a0bf528SMauro Carvalho Chehab 	if (!client.i2c_read_buffer) {
42659a0bf528SMauro Carvalho Chehab 		dprintk("%s: not enough memory", __func__);
42669a0bf528SMauro Carvalho Chehab 		ret = -ENOMEM;
42679a0bf528SMauro Carvalho Chehab 		goto error_memory_read;
42689a0bf528SMauro Carvalho Chehab 	}
42699a0bf528SMauro Carvalho Chehab 	client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
42709a0bf528SMauro Carvalho Chehab 	if (!client.i2c_buffer_lock) {
42719a0bf528SMauro Carvalho Chehab 		dprintk("%s: not enough memory", __func__);
42729a0bf528SMauro Carvalho Chehab 		ret = -ENOMEM;
42739a0bf528SMauro Carvalho Chehab 		goto error_memory_lock;
42749a0bf528SMauro Carvalho Chehab 	}
42759a0bf528SMauro Carvalho Chehab 	mutex_init(client.i2c_buffer_lock);
42769a0bf528SMauro Carvalho Chehab 
42779a0bf528SMauro Carvalho Chehab 	for (k = no_of_demods - 1; k >= 0; k--) {
42789a0bf528SMauro Carvalho Chehab 		/* designated i2c address */
42799a0bf528SMauro Carvalho Chehab 		new_addr = first_addr + (k << 1);
42809a0bf528SMauro Carvalho Chehab 
42819a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
42829a0bf528SMauro Carvalho Chehab 		if (!is_dib8096p)
42839a0bf528SMauro Carvalho Chehab 			dib8000_i2c_write16(&client, 1287, 0x0003);	/* sram lead in, rdy */
42849a0bf528SMauro Carvalho Chehab 		if (dib8000_identify(&client) == 0) {
42859a0bf528SMauro Carvalho Chehab 			/* sram lead in, rdy */
42869a0bf528SMauro Carvalho Chehab 			if (!is_dib8096p)
42879a0bf528SMauro Carvalho Chehab 				dib8000_i2c_write16(&client, 1287, 0x0003);
42889a0bf528SMauro Carvalho Chehab 			client.addr = default_addr;
42899a0bf528SMauro Carvalho Chehab 			if (dib8000_identify(&client) == 0) {
42909a0bf528SMauro Carvalho Chehab 				dprintk("#%d: not identified", k);
42919a0bf528SMauro Carvalho Chehab 				ret  = -EINVAL;
42929a0bf528SMauro Carvalho Chehab 				goto error;
42939a0bf528SMauro Carvalho Chehab 			}
42949a0bf528SMauro Carvalho Chehab 		}
42959a0bf528SMauro Carvalho Chehab 
42969a0bf528SMauro Carvalho Chehab 		/* start diversity to pull_down div_str - just for i2c-enumeration */
42979a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
42989a0bf528SMauro Carvalho Chehab 
42999a0bf528SMauro Carvalho Chehab 		/* set new i2c address and force divstart */
43009a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
43019a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
43029a0bf528SMauro Carvalho Chehab 		dib8000_identify(&client);
43039a0bf528SMauro Carvalho Chehab 
43049a0bf528SMauro Carvalho Chehab 		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
43059a0bf528SMauro Carvalho Chehab 	}
43069a0bf528SMauro Carvalho Chehab 
43079a0bf528SMauro Carvalho Chehab 	for (k = 0; k < no_of_demods; k++) {
43089a0bf528SMauro Carvalho Chehab 		new_addr = first_addr | (k << 1);
43099a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
43109a0bf528SMauro Carvalho Chehab 
43119a0bf528SMauro Carvalho Chehab 		// unforce divstr
43129a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1285, new_addr << 2);
43139a0bf528SMauro Carvalho Chehab 
43149a0bf528SMauro Carvalho Chehab 		/* deactivate div - it was just for i2c-enumeration */
43159a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1286, 0);
43169a0bf528SMauro Carvalho Chehab 	}
43179a0bf528SMauro Carvalho Chehab 
43189a0bf528SMauro Carvalho Chehab error:
43199a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_buffer_lock);
43209a0bf528SMauro Carvalho Chehab error_memory_lock:
43219a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_read_buffer);
43229a0bf528SMauro Carvalho Chehab error_memory_read:
43239a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_write_buffer);
43249a0bf528SMauro Carvalho Chehab 
43259a0bf528SMauro Carvalho Chehab 	return ret;
43269a0bf528SMauro Carvalho Chehab }
43279a0bf528SMauro Carvalho Chehab 
43289a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_i2c_enumeration);
43299a0bf528SMauro Carvalho Chehab static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
43309a0bf528SMauro Carvalho Chehab {
43319a0bf528SMauro Carvalho Chehab 	tune->min_delay_ms = 1000;
43329a0bf528SMauro Carvalho Chehab 	tune->step_size = 0;
43339a0bf528SMauro Carvalho Chehab 	tune->max_drift = 0;
43349a0bf528SMauro Carvalho Chehab 	return 0;
43359a0bf528SMauro Carvalho Chehab }
43369a0bf528SMauro Carvalho Chehab 
43379a0bf528SMauro Carvalho Chehab static void dib8000_release(struct dvb_frontend *fe)
43389a0bf528SMauro Carvalho Chehab {
43399a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
43409a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
43419a0bf528SMauro Carvalho Chehab 
43429a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
43439a0bf528SMauro Carvalho Chehab 		dvb_frontend_detach(st->fe[index_frontend]);
43449a0bf528SMauro Carvalho Chehab 
43459a0bf528SMauro Carvalho Chehab 	dibx000_exit_i2c_master(&st->i2c_master);
43469a0bf528SMauro Carvalho Chehab 	i2c_del_adapter(&st->dib8096p_tuner_adap);
43479a0bf528SMauro Carvalho Chehab 	kfree(st->fe[0]);
43489a0bf528SMauro Carvalho Chehab 	kfree(st);
43499a0bf528SMauro Carvalho Chehab }
43509a0bf528SMauro Carvalho Chehab 
43519a0bf528SMauro Carvalho Chehab struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
43529a0bf528SMauro Carvalho Chehab {
43539a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
43549a0bf528SMauro Carvalho Chehab 	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
43559a0bf528SMauro Carvalho Chehab }
43569a0bf528SMauro Carvalho Chehab 
43579a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_get_i2c_master);
43589a0bf528SMauro Carvalho Chehab 
43599a0bf528SMauro Carvalho Chehab int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
43609a0bf528SMauro Carvalho Chehab {
43619a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
43629a0bf528SMauro Carvalho Chehab 	u16 val = dib8000_read_word(st, 299) & 0xffef;
43639a0bf528SMauro Carvalho Chehab 	val |= (onoff & 0x1) << 4;
43649a0bf528SMauro Carvalho Chehab 
43659a0bf528SMauro Carvalho Chehab 	dprintk("pid filter enabled %d", onoff);
43669a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(st, 299, val);
43679a0bf528SMauro Carvalho Chehab }
43689a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_pid_filter_ctrl);
43699a0bf528SMauro Carvalho Chehab 
43709a0bf528SMauro Carvalho Chehab int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
43719a0bf528SMauro Carvalho Chehab {
43729a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
43739a0bf528SMauro Carvalho Chehab 	dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
43749a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
43759a0bf528SMauro Carvalho Chehab }
43769a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_pid_filter);
43779a0bf528SMauro Carvalho Chehab 
43789a0bf528SMauro Carvalho Chehab static const struct dvb_frontend_ops dib8000_ops = {
43799a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ISDBT },
43809a0bf528SMauro Carvalho Chehab 	.info = {
43819a0bf528SMauro Carvalho Chehab 		 .name = "DiBcom 8000 ISDB-T",
43829a0bf528SMauro Carvalho Chehab 		 .frequency_min = 44250000,
43839a0bf528SMauro Carvalho Chehab 		 .frequency_max = 867250000,
43849a0bf528SMauro Carvalho Chehab 		 .frequency_stepsize = 62500,
43859a0bf528SMauro Carvalho Chehab 		 .caps = FE_CAN_INVERSION_AUTO |
43869a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
43879a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
43889a0bf528SMauro Carvalho Chehab 		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
43899a0bf528SMauro Carvalho Chehab 		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
43909a0bf528SMauro Carvalho Chehab 		 },
43919a0bf528SMauro Carvalho Chehab 
43929a0bf528SMauro Carvalho Chehab 	.release = dib8000_release,
43939a0bf528SMauro Carvalho Chehab 
43949a0bf528SMauro Carvalho Chehab 	.init = dib8000_wakeup,
43959a0bf528SMauro Carvalho Chehab 	.sleep = dib8000_sleep,
43969a0bf528SMauro Carvalho Chehab 
43979a0bf528SMauro Carvalho Chehab 	.set_frontend = dib8000_set_frontend,
43989a0bf528SMauro Carvalho Chehab 	.get_tune_settings = dib8000_fe_get_tune_settings,
43999a0bf528SMauro Carvalho Chehab 	.get_frontend = dib8000_get_frontend,
44009a0bf528SMauro Carvalho Chehab 
44019a0bf528SMauro Carvalho Chehab 	.read_status = dib8000_read_status,
44029a0bf528SMauro Carvalho Chehab 	.read_ber = dib8000_read_ber,
44039a0bf528SMauro Carvalho Chehab 	.read_signal_strength = dib8000_read_signal_strength,
44049a0bf528SMauro Carvalho Chehab 	.read_snr = dib8000_read_snr,
44059a0bf528SMauro Carvalho Chehab 	.read_ucblocks = dib8000_read_unc_blocks,
44069a0bf528SMauro Carvalho Chehab };
44079a0bf528SMauro Carvalho Chehab 
4408b9bc7d59SMauro Carvalho Chehab struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
44099a0bf528SMauro Carvalho Chehab {
44109a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *fe;
44119a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state;
44129a0bf528SMauro Carvalho Chehab 
4413b9bc7d59SMauro Carvalho Chehab 	dprintk("dib8000_init");
44149a0bf528SMauro Carvalho Chehab 
44159a0bf528SMauro Carvalho Chehab 	state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
44169a0bf528SMauro Carvalho Chehab 	if (state == NULL)
44179a0bf528SMauro Carvalho Chehab 		return NULL;
44189a0bf528SMauro Carvalho Chehab 	fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
44199a0bf528SMauro Carvalho Chehab 	if (fe == NULL)
44209a0bf528SMauro Carvalho Chehab 		goto error;
44219a0bf528SMauro Carvalho Chehab 
44229a0bf528SMauro Carvalho Chehab 	memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
44239a0bf528SMauro Carvalho Chehab 	state->i2c.adap = i2c_adap;
44249a0bf528SMauro Carvalho Chehab 	state->i2c.addr = i2c_addr;
44259a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_write_buffer = state->i2c_write_buffer;
44269a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_read_buffer = state->i2c_read_buffer;
44279a0bf528SMauro Carvalho Chehab 	mutex_init(&state->i2c_buffer_lock);
44289a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
44299a0bf528SMauro Carvalho Chehab 	state->gpio_val = cfg->gpio_val;
44309a0bf528SMauro Carvalho Chehab 	state->gpio_dir = cfg->gpio_dir;
44319a0bf528SMauro Carvalho Chehab 
44329a0bf528SMauro Carvalho Chehab 	/* Ensure the output mode remains at the previous default if it's
44339a0bf528SMauro Carvalho Chehab 	 * not specifically set by the caller.
44349a0bf528SMauro Carvalho Chehab 	 */
44359a0bf528SMauro Carvalho Chehab 	if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
44369a0bf528SMauro Carvalho Chehab 		state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
44379a0bf528SMauro Carvalho Chehab 
44389a0bf528SMauro Carvalho Chehab 	state->fe[0] = fe;
44399a0bf528SMauro Carvalho Chehab 	fe->demodulator_priv = state;
44409a0bf528SMauro Carvalho Chehab 	memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
44419a0bf528SMauro Carvalho Chehab 
44429a0bf528SMauro Carvalho Chehab 	state->timf_default = cfg->pll->timf;
44439a0bf528SMauro Carvalho Chehab 
44449a0bf528SMauro Carvalho Chehab 	if (dib8000_identify(&state->i2c) == 0)
44459a0bf528SMauro Carvalho Chehab 		goto error;
44469a0bf528SMauro Carvalho Chehab 
44479a0bf528SMauro Carvalho Chehab 	dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
44489a0bf528SMauro Carvalho Chehab 
44499a0bf528SMauro Carvalho Chehab 	/* init 8096p tuner adapter */
44509a0bf528SMauro Carvalho Chehab 	strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
44519a0bf528SMauro Carvalho Chehab 			sizeof(state->dib8096p_tuner_adap.name));
44529a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
44539a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.algo_data = NULL;
44549a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
44559a0bf528SMauro Carvalho Chehab 	i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
44569a0bf528SMauro Carvalho Chehab 	i2c_add_adapter(&state->dib8096p_tuner_adap);
44579a0bf528SMauro Carvalho Chehab 
44589a0bf528SMauro Carvalho Chehab 	dib8000_reset(fe);
44599a0bf528SMauro Carvalho Chehab 
44609a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));	/* ber_rs_len = 3 */
4461173a64cbSPatrick Boettcher 	state->current_demod_bw = 6000;
44629a0bf528SMauro Carvalho Chehab 
44639a0bf528SMauro Carvalho Chehab 	return fe;
44649a0bf528SMauro Carvalho Chehab 
44659a0bf528SMauro Carvalho Chehab error:
44669a0bf528SMauro Carvalho Chehab 	kfree(state);
44679a0bf528SMauro Carvalho Chehab 	return NULL;
44689a0bf528SMauro Carvalho Chehab }
44699a0bf528SMauro Carvalho Chehab 
4470b9bc7d59SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_init);
44719a0bf528SMauro Carvalho Chehab 
44729a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>");
44739a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
44749a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
4475