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  */
108af16adfSMauro Carvalho Chehab 
118af16adfSMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
128af16adfSMauro Carvalho Chehab 
139a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
149a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
159a0bf528SMauro Carvalho Chehab #include <linux/i2c.h>
169a0bf528SMauro Carvalho Chehab #include <linux/mutex.h>
17b4600d70SMauro Carvalho Chehab #include <asm/div64.h>
189a0bf528SMauro Carvalho Chehab 
199a0bf528SMauro Carvalho Chehab #include "dvb_math.h"
209a0bf528SMauro Carvalho Chehab 
219a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h"
229a0bf528SMauro Carvalho Chehab 
239a0bf528SMauro Carvalho Chehab #include "dib8000.h"
249a0bf528SMauro Carvalho Chehab 
259a0bf528SMauro Carvalho Chehab #define LAYER_ALL -1
269a0bf528SMauro Carvalho Chehab #define LAYER_A   1
279a0bf528SMauro Carvalho Chehab #define LAYER_B   2
289a0bf528SMauro Carvalho Chehab #define LAYER_C   3
299a0bf528SMauro Carvalho Chehab 
309a0bf528SMauro Carvalho Chehab #define MAX_NUMBER_OF_FRONTENDS 6
31173a64cbSPatrick Boettcher /* #define DIB8000_AGC_FREEZE */
329a0bf528SMauro Carvalho Chehab 
339a0bf528SMauro Carvalho Chehab static int debug;
349a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
359a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
369a0bf528SMauro Carvalho Chehab 
378af16adfSMauro Carvalho Chehab #define dprintk(fmt, arg...) do {					\
388af16adfSMauro Carvalho Chehab 	if (debug)							\
398af16adfSMauro Carvalho Chehab 		printk(KERN_DEBUG pr_fmt("%s: " fmt),			\
408af16adfSMauro Carvalho Chehab 		       __func__, ##arg);				\
418af16adfSMauro Carvalho Chehab } while (0)
429a0bf528SMauro Carvalho Chehab 
439a0bf528SMauro Carvalho Chehab struct i2c_device {
449a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *adap;
459a0bf528SMauro Carvalho Chehab 	u8 addr;
469a0bf528SMauro Carvalho Chehab 	u8 *i2c_write_buffer;
479a0bf528SMauro Carvalho Chehab 	u8 *i2c_read_buffer;
489a0bf528SMauro Carvalho Chehab 	struct mutex *i2c_buffer_lock;
499a0bf528SMauro Carvalho Chehab };
509a0bf528SMauro Carvalho Chehab 
51173a64cbSPatrick Boettcher enum param_loop_step {
52173a64cbSPatrick Boettcher 	LOOP_TUNE_1,
53173a64cbSPatrick Boettcher 	LOOP_TUNE_2
54173a64cbSPatrick Boettcher };
55173a64cbSPatrick Boettcher 
56173a64cbSPatrick Boettcher enum dib8000_autosearch_step {
57173a64cbSPatrick Boettcher 	AS_START = 0,
58173a64cbSPatrick Boettcher 	AS_SEARCHING_FFT,
59173a64cbSPatrick Boettcher 	AS_SEARCHING_GUARD,
60173a64cbSPatrick Boettcher 	AS_DONE = 100,
61173a64cbSPatrick Boettcher };
62173a64cbSPatrick Boettcher 
63173a64cbSPatrick Boettcher enum timeout_mode {
64173a64cbSPatrick Boettcher 	SYMBOL_DEPENDENT_OFF = 0,
65173a64cbSPatrick Boettcher 	SYMBOL_DEPENDENT_ON,
66173a64cbSPatrick Boettcher };
67173a64cbSPatrick Boettcher 
689a0bf528SMauro Carvalho Chehab struct dib8000_state {
699a0bf528SMauro Carvalho Chehab 	struct dib8000_config cfg;
709a0bf528SMauro Carvalho Chehab 
719a0bf528SMauro Carvalho Chehab 	struct i2c_device i2c;
729a0bf528SMauro Carvalho Chehab 
739a0bf528SMauro Carvalho Chehab 	struct dibx000_i2c_master i2c_master;
749a0bf528SMauro Carvalho Chehab 
759a0bf528SMauro Carvalho Chehab 	u16 wbd_ref;
769a0bf528SMauro Carvalho Chehab 
779a0bf528SMauro Carvalho Chehab 	u8 current_band;
789a0bf528SMauro Carvalho Chehab 	u32 current_bandwidth;
799a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *current_agc;
809a0bf528SMauro Carvalho Chehab 	u32 timf;
819a0bf528SMauro Carvalho Chehab 	u32 timf_default;
829a0bf528SMauro Carvalho Chehab 
839a0bf528SMauro Carvalho Chehab 	u8 div_force_off:1;
849a0bf528SMauro Carvalho Chehab 	u8 div_state:1;
859a0bf528SMauro Carvalho Chehab 	u16 div_sync_wait;
869a0bf528SMauro Carvalho Chehab 
879a0bf528SMauro Carvalho Chehab 	u8 agc_state;
889a0bf528SMauro Carvalho Chehab 	u8 differential_constellation;
899a0bf528SMauro Carvalho Chehab 	u8 diversity_onoff;
909a0bf528SMauro Carvalho Chehab 
919a0bf528SMauro Carvalho Chehab 	s16 ber_monitored_layer;
929a0bf528SMauro Carvalho Chehab 	u16 gpio_dir;
939a0bf528SMauro Carvalho Chehab 	u16 gpio_val;
949a0bf528SMauro Carvalho Chehab 
959a0bf528SMauro Carvalho Chehab 	u16 revision;
969a0bf528SMauro Carvalho Chehab 	u8 isdbt_cfg_loaded;
979a0bf528SMauro Carvalho Chehab 	enum frontend_tune_state tune_state;
98173a64cbSPatrick Boettcher 	s32 status;
999a0bf528SMauro Carvalho Chehab 
1009a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
1019a0bf528SMauro Carvalho Chehab 
1029a0bf528SMauro Carvalho Chehab 	/* for the I2C transfer */
1039a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2];
1049a0bf528SMauro Carvalho Chehab 	u8 i2c_write_buffer[4];
1059a0bf528SMauro Carvalho Chehab 	u8 i2c_read_buffer[2];
1069a0bf528SMauro Carvalho Chehab 	struct mutex i2c_buffer_lock;
1079a0bf528SMauro Carvalho Chehab 	u8 input_mode_mpeg;
1089a0bf528SMauro Carvalho Chehab 
1099a0bf528SMauro Carvalho Chehab 	u16 tuner_enable;
1109a0bf528SMauro Carvalho Chehab 	struct i2c_adapter dib8096p_tuner_adap;
111173a64cbSPatrick Boettcher 	u16 current_demod_bw;
112173a64cbSPatrick Boettcher 
113173a64cbSPatrick Boettcher 	u16 seg_mask;
114173a64cbSPatrick Boettcher 	u16 seg_diff_mask;
115173a64cbSPatrick Boettcher 	u16 mode;
116173a64cbSPatrick Boettcher 	u8 layer_b_nb_seg;
117173a64cbSPatrick Boettcher 	u8 layer_c_nb_seg;
118173a64cbSPatrick Boettcher 
119173a64cbSPatrick Boettcher 	u8 channel_parameters_set;
120173a64cbSPatrick Boettcher 	u16 autosearch_state;
121173a64cbSPatrick Boettcher 	u16 found_nfft;
122173a64cbSPatrick Boettcher 	u16 found_guard;
123173a64cbSPatrick Boettcher 	u8 subchannel;
124173a64cbSPatrick Boettcher 	u8 symbol_duration;
125d6c62b76SMauro Carvalho Chehab 	unsigned long timeout;
126173a64cbSPatrick Boettcher 	u8 longest_intlv_layer;
127173a64cbSPatrick Boettcher 	u16 output_mode;
128173a64cbSPatrick Boettcher 
129704f01bbSMauro Carvalho Chehab 	/* for DVBv5 stats */
1307a9d85d5SMauro Carvalho Chehab 	s64 init_ucb;
1310400c535SMauro Carvalho Chehab 	unsigned long per_jiffies_stats;
1320400c535SMauro Carvalho Chehab 	unsigned long ber_jiffies_stats;
1330400c535SMauro Carvalho Chehab 	unsigned long ber_jiffies_stats_layer[3];
134704f01bbSMauro Carvalho Chehab 
135173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
136173a64cbSPatrick Boettcher 	u16 agc1_max;
137173a64cbSPatrick Boettcher 	u16 agc1_min;
138173a64cbSPatrick Boettcher 	u16 agc2_max;
139173a64cbSPatrick Boettcher 	u16 agc2_min;
140173a64cbSPatrick Boettcher #endif
1419a0bf528SMauro Carvalho Chehab };
1429a0bf528SMauro Carvalho Chehab 
1439a0bf528SMauro Carvalho Chehab enum dib8000_power_mode {
1449a0bf528SMauro Carvalho Chehab 	DIB8000_POWER_ALL = 0,
1459a0bf528SMauro Carvalho Chehab 	DIB8000_POWER_INTERFACE_ONLY,
1469a0bf528SMauro Carvalho Chehab };
1479a0bf528SMauro Carvalho Chehab 
1489a0bf528SMauro Carvalho Chehab static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
1499a0bf528SMauro Carvalho Chehab {
1509a0bf528SMauro Carvalho Chehab 	u16 ret;
1519a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2] = {
1529a0bf528SMauro Carvalho Chehab 		{.addr = i2c->addr >> 1, .flags = 0, .len = 2},
1539a0bf528SMauro Carvalho Chehab 		{.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
1549a0bf528SMauro Carvalho Chehab 	};
1559a0bf528SMauro Carvalho Chehab 
1569a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
1578af16adfSMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
1589a0bf528SMauro Carvalho Chehab 		return 0;
1599a0bf528SMauro Carvalho Chehab 	}
1609a0bf528SMauro Carvalho Chehab 
1619a0bf528SMauro Carvalho Chehab 	msg[0].buf    = i2c->i2c_write_buffer;
1629a0bf528SMauro Carvalho Chehab 	msg[0].buf[0] = reg >> 8;
1639a0bf528SMauro Carvalho Chehab 	msg[0].buf[1] = reg & 0xff;
1649a0bf528SMauro Carvalho Chehab 	msg[1].buf    = i2c->i2c_read_buffer;
1659a0bf528SMauro Carvalho Chehab 
1669a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(i2c->adap, msg, 2) != 2)
1678af16adfSMauro Carvalho Chehab 		dprintk("i2c read error on %d\n", reg);
1689a0bf528SMauro Carvalho Chehab 
1699a0bf528SMauro Carvalho Chehab 	ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
1709a0bf528SMauro Carvalho Chehab 	mutex_unlock(i2c->i2c_buffer_lock);
1719a0bf528SMauro Carvalho Chehab 	return ret;
1729a0bf528SMauro Carvalho Chehab }
1739a0bf528SMauro Carvalho Chehab 
1745ac64ba1SMauro Carvalho Chehab static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg)
1759a0bf528SMauro Carvalho Chehab {
1769a0bf528SMauro Carvalho Chehab 	u16 ret;
1779a0bf528SMauro Carvalho Chehab 
1789a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = reg >> 8;
1799a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
1809a0bf528SMauro Carvalho Chehab 
1819a0bf528SMauro Carvalho Chehab 	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
1829a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c.addr >> 1;
1839a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
1849a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
1859a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 2;
1869a0bf528SMauro Carvalho Chehab 	state->msg[1].addr = state->i2c.addr >> 1;
1879a0bf528SMauro Carvalho Chehab 	state->msg[1].flags = I2C_M_RD;
1889a0bf528SMauro Carvalho Chehab 	state->msg[1].buf = state->i2c_read_buffer;
1899a0bf528SMauro Carvalho Chehab 	state->msg[1].len = 2;
1909a0bf528SMauro Carvalho Chehab 
1919a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
1928af16adfSMauro Carvalho Chehab 		dprintk("i2c read error on %d\n", reg);
1939a0bf528SMauro Carvalho Chehab 
1949a0bf528SMauro Carvalho Chehab 	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
1955ac64ba1SMauro Carvalho Chehab 
1965ac64ba1SMauro Carvalho Chehab 	return ret;
1975ac64ba1SMauro Carvalho Chehab }
1985ac64ba1SMauro Carvalho Chehab 
1995ac64ba1SMauro Carvalho Chehab static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
2005ac64ba1SMauro Carvalho Chehab {
2015ac64ba1SMauro Carvalho Chehab 	u16 ret;
2025ac64ba1SMauro Carvalho Chehab 
2035ac64ba1SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2048af16adfSMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
2055ac64ba1SMauro Carvalho Chehab 		return 0;
2065ac64ba1SMauro Carvalho Chehab 	}
2075ac64ba1SMauro Carvalho Chehab 
2085ac64ba1SMauro Carvalho Chehab 	ret = __dib8000_read_word(state, reg);
2095ac64ba1SMauro Carvalho Chehab 
2109a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
2119a0bf528SMauro Carvalho Chehab 
2129a0bf528SMauro Carvalho Chehab 	return ret;
2139a0bf528SMauro Carvalho Chehab }
2149a0bf528SMauro Carvalho Chehab 
2159a0bf528SMauro Carvalho Chehab static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
2169a0bf528SMauro Carvalho Chehab {
2179a0bf528SMauro Carvalho Chehab 	u16 rw[2];
2189a0bf528SMauro Carvalho Chehab 
2195ac64ba1SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2208af16adfSMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
2215ac64ba1SMauro Carvalho Chehab 		return 0;
2225ac64ba1SMauro Carvalho Chehab 	}
2235ac64ba1SMauro Carvalho Chehab 
2245ac64ba1SMauro Carvalho Chehab 	rw[0] = __dib8000_read_word(state, reg + 0);
2255ac64ba1SMauro Carvalho Chehab 	rw[1] = __dib8000_read_word(state, reg + 1);
2265ac64ba1SMauro Carvalho Chehab 
2275ac64ba1SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
2289a0bf528SMauro Carvalho Chehab 
2299a0bf528SMauro Carvalho Chehab 	return ((rw[0] << 16) | (rw[1]));
2309a0bf528SMauro Carvalho Chehab }
2319a0bf528SMauro Carvalho Chehab 
2329a0bf528SMauro Carvalho Chehab static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
2339a0bf528SMauro Carvalho Chehab {
2349a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
2359a0bf528SMauro Carvalho Chehab 	int ret = 0;
2369a0bf528SMauro Carvalho Chehab 
2379a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
2388af16adfSMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
2399a0bf528SMauro Carvalho Chehab 		return -EINVAL;
2409a0bf528SMauro Carvalho Chehab 	}
2419a0bf528SMauro Carvalho Chehab 
2429a0bf528SMauro Carvalho Chehab 	msg.buf    = i2c->i2c_write_buffer;
2439a0bf528SMauro Carvalho Chehab 	msg.buf[0] = (reg >> 8) & 0xff;
2449a0bf528SMauro Carvalho Chehab 	msg.buf[1] = reg & 0xff;
2459a0bf528SMauro Carvalho Chehab 	msg.buf[2] = (val >> 8) & 0xff;
2469a0bf528SMauro Carvalho Chehab 	msg.buf[3] = val & 0xff;
2479a0bf528SMauro Carvalho Chehab 
2489a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
2499a0bf528SMauro Carvalho Chehab 	mutex_unlock(i2c->i2c_buffer_lock);
2509a0bf528SMauro Carvalho Chehab 
2519a0bf528SMauro Carvalho Chehab 	return ret;
2529a0bf528SMauro Carvalho Chehab }
2539a0bf528SMauro Carvalho Chehab 
2549a0bf528SMauro Carvalho Chehab static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
2559a0bf528SMauro Carvalho Chehab {
2569a0bf528SMauro Carvalho Chehab 	int ret;
2579a0bf528SMauro Carvalho Chehab 
2589a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2598af16adfSMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
2609a0bf528SMauro Carvalho Chehab 		return -EINVAL;
2619a0bf528SMauro Carvalho Chehab 	}
2629a0bf528SMauro Carvalho Chehab 
2639a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
2649a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
2659a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
2669a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[3] = val & 0xff;
2679a0bf528SMauro Carvalho Chehab 
2689a0bf528SMauro Carvalho Chehab 	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
2699a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c.addr >> 1;
2709a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
2719a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
2729a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 4;
2739a0bf528SMauro Carvalho Chehab 
2749a0bf528SMauro Carvalho Chehab 	ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
2759a0bf528SMauro Carvalho Chehab 			-EREMOTEIO : 0);
2769a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
2779a0bf528SMauro Carvalho Chehab 
2789a0bf528SMauro Carvalho Chehab 	return ret;
2799a0bf528SMauro Carvalho Chehab }
2809a0bf528SMauro Carvalho Chehab 
2819a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
2829a0bf528SMauro Carvalho Chehab 	(769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c,
2839a0bf528SMauro Carvalho Chehab 		(920 << 5) | 0x09
2849a0bf528SMauro Carvalho Chehab };
2859a0bf528SMauro Carvalho Chehab 
2869a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg[8] = {
2879a0bf528SMauro Carvalho Chehab 	(692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
2889a0bf528SMauro Carvalho Chehab };
2899a0bf528SMauro Carvalho Chehab 
2909a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
2919a0bf528SMauro Carvalho Chehab 	(832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11,
2929a0bf528SMauro Carvalho Chehab 		(-931 << 5) | 0x0f
2939a0bf528SMauro Carvalho Chehab };
2949a0bf528SMauro Carvalho Chehab 
2959a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
2969a0bf528SMauro Carvalho Chehab 	(622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e,
2979a0bf528SMauro Carvalho Chehab 		(982 << 5) | 0x0c
2989a0bf528SMauro Carvalho Chehab };
2999a0bf528SMauro Carvalho Chehab 
3009a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
3019a0bf528SMauro Carvalho Chehab 	(699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12,
3029a0bf528SMauro Carvalho Chehab 		(-720 << 5) | 0x0d
3039a0bf528SMauro Carvalho Chehab };
3049a0bf528SMauro Carvalho Chehab 
3059a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg[8] = {
3069a0bf528SMauro Carvalho Chehab 	(664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e,
3079a0bf528SMauro Carvalho Chehab 		(-610 << 5) | 0x0a
3089a0bf528SMauro Carvalho Chehab };
3099a0bf528SMauro Carvalho Chehab 
3109a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
3119a0bf528SMauro Carvalho Chehab 	(-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f,
3129a0bf528SMauro Carvalho Chehab 		(-922 << 5) | 0x0d
3139a0bf528SMauro Carvalho Chehab };
3149a0bf528SMauro Carvalho Chehab 
3159a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg[8] = {
3169a0bf528SMauro Carvalho Chehab 	(638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d,
3179a0bf528SMauro Carvalho Chehab 		(-655 << 5) | 0x0a
3189a0bf528SMauro Carvalho Chehab };
3199a0bf528SMauro Carvalho Chehab 
3209a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
3219a0bf528SMauro Carvalho Chehab 	(-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14,
3229a0bf528SMauro Carvalho Chehab 		(-958 << 5) | 0x13
3239a0bf528SMauro Carvalho Chehab };
3249a0bf528SMauro Carvalho Chehab 
3259a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
3269a0bf528SMauro Carvalho Chehab 	(-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12,
3279a0bf528SMauro Carvalho Chehab 		(-568 << 5) | 0x0f
3289a0bf528SMauro Carvalho Chehab };
3299a0bf528SMauro Carvalho Chehab 
3309a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
3319a0bf528SMauro Carvalho Chehab 	(-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14,
3329a0bf528SMauro Carvalho Chehab 		(-848 << 5) | 0x13
3339a0bf528SMauro Carvalho Chehab };
3349a0bf528SMauro Carvalho Chehab 
3359a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg[8] = {
3369a0bf528SMauro Carvalho Chehab 	(612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12,
3379a0bf528SMauro Carvalho Chehab 		(-869 << 5) | 0x13
3389a0bf528SMauro Carvalho Chehab };
3399a0bf528SMauro Carvalho Chehab 
3409a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
3419a0bf528SMauro Carvalho Chehab 	(-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13,
3429a0bf528SMauro Carvalho Chehab 		(-598 << 5) | 0x10
3439a0bf528SMauro Carvalho Chehab };
3449a0bf528SMauro Carvalho Chehab 
3459a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg[8] = {
3469a0bf528SMauro Carvalho Chehab 	(673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f,
3479a0bf528SMauro Carvalho Chehab 		(585 << 5) | 0x0f
3489a0bf528SMauro Carvalho Chehab };
3499a0bf528SMauro Carvalho Chehab 
3509a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
3519a0bf528SMauro Carvalho Chehab 	(863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18,
3529a0bf528SMauro Carvalho Chehab 		(0 << 5) | 0x14
3539a0bf528SMauro Carvalho Chehab };
3549a0bf528SMauro Carvalho Chehab 
3559a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
3569a0bf528SMauro Carvalho Chehab 	(-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15,
3579a0bf528SMauro Carvalho Chehab 		(-877 << 5) | 0x15
3589a0bf528SMauro Carvalho Chehab };
3599a0bf528SMauro Carvalho Chehab 
3609a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
3619a0bf528SMauro Carvalho Chehab 	(-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18,
3629a0bf528SMauro Carvalho Chehab 		(-921 << 5) | 0x14
3639a0bf528SMauro Carvalho Chehab };
3649a0bf528SMauro Carvalho Chehab 
3659a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg[8] = {
3669a0bf528SMauro Carvalho Chehab 	(514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15,
3679a0bf528SMauro Carvalho Chehab 		(690 << 5) | 0x14
3689a0bf528SMauro Carvalho Chehab };
3699a0bf528SMauro Carvalho Chehab 
3709a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_3seg[24] = {
3719a0bf528SMauro 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
3729a0bf528SMauro Carvalho Chehab };
3739a0bf528SMauro Carvalho Chehab 
3749a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_1seg[24] = {
3759a0bf528SMauro 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
3769a0bf528SMauro Carvalho Chehab };
3779a0bf528SMauro Carvalho Chehab 
3789a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_13seg[24] = {
3799a0bf528SMauro 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
3809a0bf528SMauro Carvalho Chehab };
3819a0bf528SMauro Carvalho Chehab 
3829a0bf528SMauro Carvalho Chehab static u16 fft_to_mode(struct dib8000_state *state)
3839a0bf528SMauro Carvalho Chehab {
3849a0bf528SMauro Carvalho Chehab 	u16 mode;
3859a0bf528SMauro Carvalho Chehab 	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
3869a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
3879a0bf528SMauro Carvalho Chehab 		mode = 1;
3889a0bf528SMauro Carvalho Chehab 		break;
3899a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
3909a0bf528SMauro Carvalho Chehab 		mode = 2;
3919a0bf528SMauro Carvalho Chehab 		break;
3929a0bf528SMauro Carvalho Chehab 	default:
3939a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_AUTO:
3949a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
3959a0bf528SMauro Carvalho Chehab 		mode = 3;
3969a0bf528SMauro Carvalho Chehab 		break;
3979a0bf528SMauro Carvalho Chehab 	}
3989a0bf528SMauro Carvalho Chehab 	return mode;
3999a0bf528SMauro Carvalho Chehab }
4009a0bf528SMauro Carvalho Chehab 
4019a0bf528SMauro Carvalho Chehab static void dib8000_set_acquisition_mode(struct dib8000_state *state)
4029a0bf528SMauro Carvalho Chehab {
4039a0bf528SMauro Carvalho Chehab 	u16 nud = dib8000_read_word(state, 298);
4049a0bf528SMauro Carvalho Chehab 	nud |= (1 << 3) | (1 << 0);
4058af16adfSMauro Carvalho Chehab 	dprintk("acquisition mode activated\n");
4069a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 298, nud);
4079a0bf528SMauro Carvalho Chehab }
4089a0bf528SMauro Carvalho Chehab static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
4099a0bf528SMauro Carvalho Chehab {
4109a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
4119a0bf528SMauro Carvalho Chehab 	u16 outreg, fifo_threshold, smo_mode, sram = 0x0205;	/* by default SDRAM deintlv is enabled */
4129a0bf528SMauro Carvalho Chehab 
413173a64cbSPatrick Boettcher 	state->output_mode = mode;
4149a0bf528SMauro Carvalho Chehab 	outreg = 0;
4159a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
4169a0bf528SMauro Carvalho Chehab 	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
4179a0bf528SMauro Carvalho Chehab 
4188af16adfSMauro Carvalho Chehab 	dprintk("-I-	Setting output mode for demod %p to %d\n",
4199a0bf528SMauro Carvalho Chehab 			&state->fe[0], mode);
4209a0bf528SMauro Carvalho Chehab 
4219a0bf528SMauro Carvalho Chehab 	switch (mode) {
4229a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:	// STBs with parallel gated clock
4239a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10);	/* 0x0400 */
4249a0bf528SMauro Carvalho Chehab 		break;
4259a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK:	// STBs with parallel continues clock
4269a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (1 << 6);	/* 0x0440 */
4279a0bf528SMauro Carvalho Chehab 		break;
4289a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:	// STBs with serial input
4299a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (2 << 6) | (0 << 1);	/* 0x0482 */
4309a0bf528SMauro Carvalho Chehab 		break;
4319a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
4329a0bf528SMauro Carvalho Chehab 		if (state->cfg.hostbus_diversity) {
4339a0bf528SMauro Carvalho Chehab 			outreg = (1 << 10) | (4 << 6);	/* 0x0500 */
4349a0bf528SMauro Carvalho Chehab 			sram &= 0xfdff;
4359a0bf528SMauro Carvalho Chehab 		} else
4369a0bf528SMauro Carvalho Chehab 			sram |= 0x0c00;
4379a0bf528SMauro Carvalho Chehab 		break;
4389a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:	// e.g. USB feeding
4399a0bf528SMauro Carvalho Chehab 		smo_mode |= (3 << 1);
4409a0bf528SMauro Carvalho Chehab 		fifo_threshold = 512;
4419a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (5 << 6);
4429a0bf528SMauro Carvalho Chehab 		break;
4439a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:	// disable
4449a0bf528SMauro Carvalho Chehab 		outreg = 0;
4459a0bf528SMauro Carvalho Chehab 		break;
4469a0bf528SMauro Carvalho Chehab 
4479a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
4489a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (3 << 6);
4499a0bf528SMauro Carvalho Chehab 		dib8000_set_acquisition_mode(state);
4509a0bf528SMauro Carvalho Chehab 		break;
4519a0bf528SMauro Carvalho Chehab 
4529a0bf528SMauro Carvalho Chehab 	default:
4538af16adfSMauro Carvalho Chehab 		dprintk("Unhandled output_mode passed to be set for demod %p\n",
4549a0bf528SMauro Carvalho Chehab 				&state->fe[0]);
4559a0bf528SMauro Carvalho Chehab 		return -EINVAL;
4569a0bf528SMauro Carvalho Chehab 	}
4579a0bf528SMauro Carvalho Chehab 
4589a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
4599a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
4609a0bf528SMauro Carvalho Chehab 
4619a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 299, smo_mode);
4629a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 300, fifo_threshold);	/* synchronous fread */
4639a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1286, outreg);
4649a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1291, sram);
4659a0bf528SMauro Carvalho Chehab 
4669a0bf528SMauro Carvalho Chehab 	return 0;
4679a0bf528SMauro Carvalho Chehab }
4689a0bf528SMauro Carvalho Chehab 
4699a0bf528SMauro Carvalho Chehab static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
4709a0bf528SMauro Carvalho Chehab {
4719a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
472173a64cbSPatrick Boettcher 	u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0;
4739a0bf528SMauro Carvalho Chehab 
4748af16adfSMauro Carvalho Chehab 	dprintk("set diversity input to %i\n", onoff);
4759a0bf528SMauro Carvalho Chehab 	if (!state->differential_constellation) {
4769a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 272, 1 << 9);	//dvsy_off_lmod4 = 1
4779a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2);	// sync_enable = 1; comb_mode = 2
4789a0bf528SMauro Carvalho Chehab 	} else {
4799a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 272, 0);	//dvsy_off_lmod4 = 0
4809a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 273, sync_wait);	// sync_enable = 0; comb_mode = 0
4819a0bf528SMauro Carvalho Chehab 	}
4829a0bf528SMauro Carvalho Chehab 	state->diversity_onoff = onoff;
4839a0bf528SMauro Carvalho Chehab 
4849a0bf528SMauro Carvalho Chehab 	switch (onoff) {
4859a0bf528SMauro Carvalho Chehab 	case 0:		/* only use the internal way - not the diversity input */
4869a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 270, 1);
4879a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 271, 0);
4889a0bf528SMauro Carvalho Chehab 		break;
4899a0bf528SMauro Carvalho Chehab 	case 1:		/* both ways */
4909a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 270, 6);
4919a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 271, 6);
4929a0bf528SMauro Carvalho Chehab 		break;
4939a0bf528SMauro Carvalho Chehab 	case 2:		/* only the diversity input */
4949a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 270, 0);
4959a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 271, 1);
4969a0bf528SMauro Carvalho Chehab 		break;
4979a0bf528SMauro Carvalho Chehab 	}
498173a64cbSPatrick Boettcher 
499173a64cbSPatrick Boettcher 	if (state->revision == 0x8002) {
500173a64cbSPatrick Boettcher 		tmp = dib8000_read_word(state, 903);
501173a64cbSPatrick Boettcher 		dib8000_write_word(state, 903, tmp & ~(1 << 3));
502173a64cbSPatrick Boettcher 		msleep(30);
503173a64cbSPatrick Boettcher 		dib8000_write_word(state, 903, tmp | (1 << 3));
504173a64cbSPatrick Boettcher 	}
5059a0bf528SMauro Carvalho Chehab 	return 0;
5069a0bf528SMauro Carvalho Chehab }
5079a0bf528SMauro Carvalho Chehab 
5089a0bf528SMauro Carvalho Chehab static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
5099a0bf528SMauro Carvalho Chehab {
5109a0bf528SMauro Carvalho Chehab 	/* by default everything is going to be powered off */
5119a0bf528SMauro Carvalho Chehab 	u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
5129a0bf528SMauro Carvalho Chehab 		reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
5139a0bf528SMauro Carvalho Chehab 		reg_1280;
5149a0bf528SMauro Carvalho Chehab 
5159a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
5169a0bf528SMauro Carvalho Chehab 		reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
5179a0bf528SMauro Carvalho Chehab 	else
5189a0bf528SMauro Carvalho Chehab 		reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80;
5199a0bf528SMauro Carvalho Chehab 
5209a0bf528SMauro Carvalho Chehab 	/* now, depending on the requested mode, we power on */
5219a0bf528SMauro Carvalho Chehab 	switch (mode) {
5229a0bf528SMauro Carvalho Chehab 		/* power up everything in the demod */
5239a0bf528SMauro Carvalho Chehab 	case DIB8000_POWER_ALL:
5249a0bf528SMauro Carvalho Chehab 		reg_774 = 0x0000;
5259a0bf528SMauro Carvalho Chehab 		reg_775 = 0x0000;
5269a0bf528SMauro Carvalho Chehab 		reg_776 = 0x0000;
5279a0bf528SMauro Carvalho Chehab 		reg_900 &= 0xfffc;
5289a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090)
5299a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x00ff;
5309a0bf528SMauro Carvalho Chehab 		else
5319a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x707f;
5329a0bf528SMauro Carvalho Chehab 		break;
5339a0bf528SMauro Carvalho Chehab 	case DIB8000_POWER_INTERFACE_ONLY:
5349a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090)
5359a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x00ff;
5369a0bf528SMauro Carvalho Chehab 		else
5379a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0xfa7b;
5389a0bf528SMauro Carvalho Chehab 		break;
5399a0bf528SMauro Carvalho Chehab 	}
5409a0bf528SMauro Carvalho Chehab 
5418af16adfSMauro Carvalho Chehab 	dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x\n", reg_774, reg_775, reg_776, reg_900, reg_1280);
5429a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 774, reg_774);
5439a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 775, reg_775);
5449a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 776, reg_776);
5459a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 900, reg_900);
5469a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1280, reg_1280);
5479a0bf528SMauro Carvalho Chehab }
5489a0bf528SMauro Carvalho Chehab 
5499a0bf528SMauro Carvalho Chehab static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
5509a0bf528SMauro Carvalho Chehab {
5519a0bf528SMauro Carvalho Chehab 	int ret = 0;
5529a0bf528SMauro Carvalho Chehab 	u16 reg, reg_907 = dib8000_read_word(state, 907);
5539a0bf528SMauro Carvalho Chehab 	u16 reg_908 = dib8000_read_word(state, 908);
5549a0bf528SMauro Carvalho Chehab 
5559a0bf528SMauro Carvalho Chehab 	switch (no) {
5569a0bf528SMauro Carvalho Chehab 	case DIBX000_SLOW_ADC_ON:
5579a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090) {
5589a0bf528SMauro Carvalho Chehab 			reg_908 |= (1 << 1) | (1 << 0);
5599a0bf528SMauro Carvalho Chehab 			ret |= dib8000_write_word(state, 908, reg_908);
5609a0bf528SMauro Carvalho Chehab 			reg_908 &= ~(1 << 1);
5619a0bf528SMauro Carvalho Chehab 		} else {
5629a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1925);
5639a0bf528SMauro Carvalho Chehab 			/* en_slowAdc = 1 & reset_sladc = 1 */
5649a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1925, reg |
5659a0bf528SMauro Carvalho Chehab 					(1<<4) | (1<<2));
5669a0bf528SMauro Carvalho Chehab 
5679a0bf528SMauro Carvalho Chehab 			/* read acces to make it works... strange ... */
5689a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1925);
5699a0bf528SMauro Carvalho Chehab 			msleep(20);
5709a0bf528SMauro Carvalho Chehab 			/* en_slowAdc = 1 & reset_sladc = 0 */
5719a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1925, reg & ~(1<<4));
5729a0bf528SMauro Carvalho Chehab 
5739a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 921) & ~((0x3 << 14)
5749a0bf528SMauro Carvalho Chehab 					| (0x3 << 12));
5759a0bf528SMauro Carvalho Chehab 			/* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ;
5769a0bf528SMauro Carvalho Chehab 			   (Vin2 = Vcm) */
5779a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 921, reg | (1 << 14)
5789a0bf528SMauro Carvalho Chehab 					| (3 << 12));
5799a0bf528SMauro Carvalho Chehab 		}
5809a0bf528SMauro Carvalho Chehab 		break;
5819a0bf528SMauro Carvalho Chehab 
5829a0bf528SMauro Carvalho Chehab 	case DIBX000_SLOW_ADC_OFF:
5839a0bf528SMauro Carvalho Chehab 		if (state->revision == 0x8090) {
5849a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1925);
5859a0bf528SMauro Carvalho Chehab 			/* reset_sladc = 1 en_slowAdc = 0 */
5869a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1925,
5879a0bf528SMauro Carvalho Chehab 					(reg & ~(1<<2)) | (1<<4));
5889a0bf528SMauro Carvalho Chehab 		}
5899a0bf528SMauro Carvalho Chehab 		reg_908 |= (1 << 1) | (1 << 0);
5909a0bf528SMauro Carvalho Chehab 		break;
5919a0bf528SMauro Carvalho Chehab 
5929a0bf528SMauro Carvalho Chehab 	case DIBX000_ADC_ON:
5939a0bf528SMauro Carvalho Chehab 		reg_907 &= 0x0fff;
5949a0bf528SMauro Carvalho Chehab 		reg_908 &= 0x0003;
5959a0bf528SMauro Carvalho Chehab 		break;
5969a0bf528SMauro Carvalho Chehab 
5979a0bf528SMauro Carvalho Chehab 	case DIBX000_ADC_OFF:	// leave the VBG voltage on
598c063c7c6SMauro Carvalho Chehab 		reg_907 = (1 << 13) | (1 << 12);
599c063c7c6SMauro Carvalho Chehab 		reg_908 = (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 1);
6009a0bf528SMauro Carvalho Chehab 		break;
6019a0bf528SMauro Carvalho Chehab 
6029a0bf528SMauro Carvalho Chehab 	case DIBX000_VBG_ENABLE:
6039a0bf528SMauro Carvalho Chehab 		reg_907 &= ~(1 << 15);
6049a0bf528SMauro Carvalho Chehab 		break;
6059a0bf528SMauro Carvalho Chehab 
6069a0bf528SMauro Carvalho Chehab 	case DIBX000_VBG_DISABLE:
6079a0bf528SMauro Carvalho Chehab 		reg_907 |= (1 << 15);
6089a0bf528SMauro Carvalho Chehab 		break;
6099a0bf528SMauro Carvalho Chehab 
6109a0bf528SMauro Carvalho Chehab 	default:
6119a0bf528SMauro Carvalho Chehab 		break;
6129a0bf528SMauro Carvalho Chehab 	}
6139a0bf528SMauro Carvalho Chehab 
6149a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 907, reg_907);
6159a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 908, reg_908);
6169a0bf528SMauro Carvalho Chehab 
6179a0bf528SMauro Carvalho Chehab 	return ret;
6189a0bf528SMauro Carvalho Chehab }
6199a0bf528SMauro Carvalho Chehab 
6209a0bf528SMauro Carvalho Chehab static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
6219a0bf528SMauro Carvalho Chehab {
6229a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
6239a0bf528SMauro Carvalho Chehab 	u32 timf;
6249a0bf528SMauro Carvalho Chehab 
6259a0bf528SMauro Carvalho Chehab 	if (bw == 0)
6269a0bf528SMauro Carvalho Chehab 		bw = 6000;
6279a0bf528SMauro Carvalho Chehab 
6289a0bf528SMauro Carvalho Chehab 	if (state->timf == 0) {
6298af16adfSMauro Carvalho Chehab 		dprintk("using default timf\n");
6309a0bf528SMauro Carvalho Chehab 		timf = state->timf_default;
6319a0bf528SMauro Carvalho Chehab 	} else {
6328af16adfSMauro Carvalho Chehab 		dprintk("using updated timf\n");
6339a0bf528SMauro Carvalho Chehab 		timf = state->timf;
6349a0bf528SMauro Carvalho Chehab 	}
6359a0bf528SMauro Carvalho Chehab 
6369a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
6379a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
6389a0bf528SMauro Carvalho Chehab 
6399a0bf528SMauro Carvalho Chehab 	return 0;
6409a0bf528SMauro Carvalho Chehab }
6419a0bf528SMauro Carvalho Chehab 
6429a0bf528SMauro Carvalho Chehab static int dib8000_sad_calib(struct dib8000_state *state)
6439a0bf528SMauro Carvalho Chehab {
644173a64cbSPatrick Boettcher 	u8 sad_sel = 3;
645173a64cbSPatrick Boettcher 
6469a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090) {
647173a64cbSPatrick Boettcher 		dib8000_write_word(state, 922, (sad_sel << 2));
648173a64cbSPatrick Boettcher 		dib8000_write_word(state, 923, 2048);
649173a64cbSPatrick Boettcher 
650173a64cbSPatrick Boettcher 		dib8000_write_word(state, 922, (sad_sel << 2) | 0x1);
651173a64cbSPatrick Boettcher 		dib8000_write_word(state, 922, (sad_sel << 2));
652173a64cbSPatrick Boettcher 	} else {
6539a0bf528SMauro Carvalho Chehab 		/* internal */
6549a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
655173a64cbSPatrick Boettcher 		dib8000_write_word(state, 924, 776);
6569a0bf528SMauro Carvalho Chehab 
6579a0bf528SMauro Carvalho Chehab 		/* do the calibration */
6589a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923, (1 << 0));
6599a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923, (0 << 0));
660173a64cbSPatrick Boettcher 	}
6619a0bf528SMauro Carvalho Chehab 
6629a0bf528SMauro Carvalho Chehab 	msleep(1);
6639a0bf528SMauro Carvalho Chehab 	return 0;
6649a0bf528SMauro Carvalho Chehab }
6659a0bf528SMauro Carvalho Chehab 
666d44913c1SMauro Carvalho Chehab static int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
6679a0bf528SMauro Carvalho Chehab {
6689a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
6699a0bf528SMauro Carvalho Chehab 	if (value > 4095)
6709a0bf528SMauro Carvalho Chehab 		value = 4095;
6719a0bf528SMauro Carvalho Chehab 	state->wbd_ref = value;
6729a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(state, 106, value);
6739a0bf528SMauro Carvalho Chehab }
674173a64cbSPatrick Boettcher 
6759a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
6769a0bf528SMauro Carvalho Chehab {
6778af16adfSMauro Carvalho Chehab 	dprintk("ifreq: %d %x, inversion: %d\n", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
6789a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
6799a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23,
6809a0bf528SMauro Carvalho Chehab 				(u16) (((bw->internal * 1000) >> 16) & 0xffff));
6819a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24,
6829a0bf528SMauro Carvalho Chehab 				(u16) ((bw->internal * 1000) & 0xffff));
6839a0bf528SMauro Carvalho Chehab 	} else {
6849a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff));
6859a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24,
6869a0bf528SMauro Carvalho Chehab 				(u16) ((bw->internal  / 2 * 1000) & 0xffff));
6879a0bf528SMauro Carvalho Chehab 	}
6889a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
6899a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
6909a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
6919a0bf528SMauro Carvalho Chehab 
6929a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
6939a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 922, bw->sad_cfg);
6949a0bf528SMauro Carvalho Chehab }
6959a0bf528SMauro Carvalho Chehab 
6969a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll(struct dib8000_state *state)
6979a0bf528SMauro Carvalho Chehab {
6989a0bf528SMauro Carvalho Chehab 	const struct dibx000_bandwidth_config *pll = state->cfg.pll;
6999a0bf528SMauro Carvalho Chehab 	u16 clk_cfg1, reg;
7009a0bf528SMauro Carvalho Chehab 
7019a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
7029a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 901,
7039a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv << 8) | (pll->pll_ratio << 0));
7049a0bf528SMauro Carvalho Chehab 
7059a0bf528SMauro Carvalho Chehab 		clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
7069a0bf528SMauro Carvalho Chehab 			(pll->bypclk_div << 5) | (pll->enable_refdiv << 4) |
7079a0bf528SMauro Carvalho Chehab 			(1 << 3) | (pll->pll_range << 1) |
7089a0bf528SMauro Carvalho Chehab 			(pll->pll_reset << 0);
7099a0bf528SMauro Carvalho Chehab 
7109a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 902, clk_cfg1);
7119a0bf528SMauro Carvalho Chehab 		clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
7129a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 902, clk_cfg1);
7139a0bf528SMauro Carvalho Chehab 
7148af16adfSMauro Carvalho Chehab 		dprintk("clk_cfg1: 0x%04x\n", clk_cfg1);
7159a0bf528SMauro Carvalho Chehab 
7169a0bf528SMauro Carvalho Chehab 		/* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
7179a0bf528SMauro Carvalho Chehab 		if (state->cfg.pll->ADClkSrc == 0)
7189a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904,
7199a0bf528SMauro Carvalho Chehab 					(0 << 15) | (0 << 12) | (0 << 10) |
7209a0bf528SMauro Carvalho Chehab 					(pll->modulo << 8) |
7219a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
7229a0bf528SMauro Carvalho Chehab 		else if (state->cfg.refclksel != 0)
7239a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
7249a0bf528SMauro Carvalho Chehab 					((state->cfg.refclksel & 0x3) << 10) |
7259a0bf528SMauro Carvalho Chehab 					(pll->modulo << 8) |
7269a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
7279a0bf528SMauro Carvalho Chehab 		else
7289a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
7299a0bf528SMauro Carvalho Chehab 					(3 << 10) | (pll->modulo << 8) |
7309a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
7319a0bf528SMauro Carvalho Chehab 	} else {
7329a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1856, (!pll->pll_reset<<13) |
7339a0bf528SMauro Carvalho Chehab 				(pll->pll_range<<12) | (pll->pll_ratio<<6) |
7349a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv));
7359a0bf528SMauro Carvalho Chehab 
7369a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 1857);
7379a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15));
7389a0bf528SMauro Carvalho Chehab 
7399a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */
7409a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1858, reg | 1);
7419a0bf528SMauro Carvalho Chehab 
7429a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 904, (pll->modulo << 8));
7439a0bf528SMauro Carvalho Chehab 	}
7449a0bf528SMauro Carvalho Chehab 
7459a0bf528SMauro Carvalho Chehab 	dib8000_reset_pll_common(state, pll);
7469a0bf528SMauro Carvalho Chehab }
7479a0bf528SMauro Carvalho Chehab 
748d44913c1SMauro Carvalho Chehab static int dib8000_update_pll(struct dvb_frontend *fe,
749173a64cbSPatrick Boettcher 		struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
7509a0bf528SMauro Carvalho Chehab {
7519a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
7529a0bf528SMauro Carvalho Chehab 	u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
753173a64cbSPatrick Boettcher 	u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ;
7549a0bf528SMauro Carvalho Chehab 	u32 internal, xtal;
7559a0bf528SMauro Carvalho Chehab 
7569a0bf528SMauro Carvalho Chehab 	/* get back old values */
7579a0bf528SMauro Carvalho Chehab 	prediv = reg_1856 & 0x3f;
7589a0bf528SMauro Carvalho Chehab 	loopdiv = (reg_1856 >> 6) & 0x3f;
7599a0bf528SMauro Carvalho Chehab 
760173a64cbSPatrick Boettcher 	if ((pll == NULL) || (pll->pll_prediv == prediv &&
761173a64cbSPatrick Boettcher 				pll->pll_ratio == loopdiv))
762173a64cbSPatrick Boettcher 		return -EINVAL;
763173a64cbSPatrick Boettcher 
7648af16adfSMauro Carvalho Chehab 	dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)\n", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
765173a64cbSPatrick Boettcher 	if (state->revision == 0x8090) {
7669a0bf528SMauro Carvalho Chehab 		reg_1856 &= 0xf000;
7679a0bf528SMauro Carvalho Chehab 		reg_1857 = dib8000_read_word(state, 1857);
7689a0bf528SMauro Carvalho Chehab 		/* disable PLL */
7699a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15));
7709a0bf528SMauro Carvalho Chehab 
7719a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1856, reg_1856 |
7729a0bf528SMauro Carvalho Chehab 				((pll->pll_ratio & 0x3f) << 6) |
7739a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv & 0x3f));
7749a0bf528SMauro Carvalho Chehab 
7759a0bf528SMauro Carvalho Chehab 		/* write new system clk into P_sec_len */
7769a0bf528SMauro Carvalho Chehab 		internal = dib8000_read32(state, 23) / 1000;
7778af16adfSMauro Carvalho Chehab 		dprintk("Old Internal = %d\n", internal);
7789a0bf528SMauro Carvalho Chehab 		xtal = 2 * (internal / loopdiv) * prediv;
7799a0bf528SMauro Carvalho Chehab 		internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio;
7808af16adfSMauro Carvalho Chehab 		dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d\n", xtal, internal/1000, internal/2000, internal/8000);
7818af16adfSMauro Carvalho Chehab 		dprintk("New Internal = %d\n", internal);
7829a0bf528SMauro Carvalho Chehab 
7839a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23,
7849a0bf528SMauro Carvalho Chehab 				(u16) (((internal / 2) >> 16) & 0xffff));
7859a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff));
7869a0bf528SMauro Carvalho Chehab 		/* enable PLL */
7879a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg_1857 | (1 << 15));
7889a0bf528SMauro Carvalho Chehab 
7899a0bf528SMauro Carvalho Chehab 		while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1)
7908af16adfSMauro Carvalho Chehab 			dprintk("Waiting for PLL to lock\n");
7919a0bf528SMauro Carvalho Chehab 
7929a0bf528SMauro Carvalho Chehab 		/* verify */
7939a0bf528SMauro Carvalho Chehab 		reg_1856 = dib8000_read_word(state, 1856);
7948af16adfSMauro Carvalho Chehab 		dprintk("PLL Updated with prediv = %d and loopdiv = %d\n",
7959a0bf528SMauro Carvalho Chehab 				reg_1856&0x3f, (reg_1856>>6)&0x3f);
796173a64cbSPatrick Boettcher 	} else {
797173a64cbSPatrick Boettcher 		if (bw != state->current_demod_bw) {
798173a64cbSPatrick Boettcher 			/** Bandwidth change => force PLL update **/
7998af16adfSMauro Carvalho Chehab 			dprintk("PLL: Bandwidth Change %d MHz -> %d MHz (prediv: %d->%d)\n", state->current_demod_bw / 1000, bw / 1000, oldprediv, state->cfg.pll->pll_prediv);
800173a64cbSPatrick Boettcher 
801173a64cbSPatrick Boettcher 			if (state->cfg.pll->pll_prediv != oldprediv) {
802173a64cbSPatrick Boettcher 				/** Full PLL change only if prediv is changed **/
803173a64cbSPatrick Boettcher 
804173a64cbSPatrick Boettcher 				/** full update => bypass and reconfigure **/
8058af16adfSMauro Carvalho Chehab 				dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)\n", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio);
806173a64cbSPatrick Boettcher 				dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */
807173a64cbSPatrick Boettcher 				dib8000_reset_pll(state);
808173a64cbSPatrick Boettcher 				dib8000_write_word(state, 898, 0x0004); /* sad */
809173a64cbSPatrick Boettcher 			} else
810173a64cbSPatrick Boettcher 				ratio = state->cfg.pll->pll_ratio;
811173a64cbSPatrick Boettcher 
812173a64cbSPatrick Boettcher 			state->current_demod_bw = bw;
813173a64cbSPatrick Boettcher 		}
814173a64cbSPatrick Boettcher 
815173a64cbSPatrick Boettcher 		if (ratio != 0) {
816173a64cbSPatrick Boettcher 			/** ratio update => only change ratio **/
8178af16adfSMauro Carvalho Chehab 			dprintk("PLL: Update ratio (prediv: %d, ratio: %d)\n", state->cfg.pll->pll_prediv, ratio);
818173a64cbSPatrick Boettcher 			dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
819173a64cbSPatrick Boettcher 		}
820173a64cbSPatrick Boettcher 	}
8219a0bf528SMauro Carvalho Chehab 
8229a0bf528SMauro Carvalho Chehab 	return 0;
8239a0bf528SMauro Carvalho Chehab }
8249a0bf528SMauro Carvalho Chehab 
8259a0bf528SMauro Carvalho Chehab static int dib8000_reset_gpio(struct dib8000_state *st)
8269a0bf528SMauro Carvalho Chehab {
8279a0bf528SMauro Carvalho Chehab 	/* reset the GPIOs */
8289a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
8299a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1030, st->cfg.gpio_val);
8309a0bf528SMauro Carvalho Chehab 
8319a0bf528SMauro Carvalho Chehab 	/* TODO 782 is P_gpio_od */
8329a0bf528SMauro Carvalho Chehab 
8339a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
8349a0bf528SMauro Carvalho Chehab 
8359a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
8369a0bf528SMauro Carvalho Chehab 	return 0;
8379a0bf528SMauro Carvalho Chehab }
8389a0bf528SMauro Carvalho Chehab 
8399a0bf528SMauro Carvalho Chehab static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
8409a0bf528SMauro Carvalho Chehab {
8419a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir = dib8000_read_word(st, 1029);
8429a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir &= ~(1 << num);	/* reset the direction bit */
8439a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
8449a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
8459a0bf528SMauro Carvalho Chehab 
8469a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val = dib8000_read_word(st, 1030);
8479a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val &= ~(1 << num);	/* reset the direction bit */
8489a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val |= (val & 0x01) << num;	/* set the new value */
8499a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1030, st->cfg.gpio_val);
8509a0bf528SMauro Carvalho Chehab 
8518af16adfSMauro Carvalho Chehab 	dprintk("gpio dir: %x: gpio val: %x\n", st->cfg.gpio_dir, st->cfg.gpio_val);
8529a0bf528SMauro Carvalho Chehab 
8539a0bf528SMauro Carvalho Chehab 	return 0;
8549a0bf528SMauro Carvalho Chehab }
8559a0bf528SMauro Carvalho Chehab 
856d44913c1SMauro Carvalho Chehab static int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
8579a0bf528SMauro Carvalho Chehab {
8589a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
8599a0bf528SMauro Carvalho Chehab 	return dib8000_cfg_gpio(state, num, dir, val);
8609a0bf528SMauro Carvalho Chehab }
8619a0bf528SMauro Carvalho Chehab 
8629a0bf528SMauro Carvalho Chehab static const u16 dib8000_defaults[] = {
8639a0bf528SMauro Carvalho Chehab 	/* auto search configuration - lock0 by default waiting
8649a0bf528SMauro Carvalho Chehab 	 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
8659a0bf528SMauro Carvalho Chehab 	3, 7,
8669a0bf528SMauro Carvalho Chehab 	0x0004,
8679a0bf528SMauro Carvalho Chehab 	0x0400,
8689a0bf528SMauro Carvalho Chehab 	0x0814,
8699a0bf528SMauro Carvalho Chehab 
8709a0bf528SMauro Carvalho Chehab 	12, 11,
8719a0bf528SMauro Carvalho Chehab 	0x001b,
8729a0bf528SMauro Carvalho Chehab 	0x7740,
8739a0bf528SMauro Carvalho Chehab 	0x005b,
8749a0bf528SMauro Carvalho Chehab 	0x8d80,
8759a0bf528SMauro Carvalho Chehab 	0x01c9,
8769a0bf528SMauro Carvalho Chehab 	0xc380,
8779a0bf528SMauro Carvalho Chehab 	0x0000,
8789a0bf528SMauro Carvalho Chehab 	0x0080,
8799a0bf528SMauro Carvalho Chehab 	0x0000,
8809a0bf528SMauro Carvalho Chehab 	0x0090,
8819a0bf528SMauro Carvalho Chehab 	0x0001,
8829a0bf528SMauro Carvalho Chehab 	0xd4c0,
8839a0bf528SMauro Carvalho Chehab 
8849a0bf528SMauro Carvalho Chehab 	/*1, 32,
8859a0bf528SMauro Carvalho Chehab 		0x6680 // P_corm_thres Lock algorithms configuration */
8869a0bf528SMauro Carvalho Chehab 
8879a0bf528SMauro Carvalho Chehab 	11, 80,			/* set ADC level to -16 */
8889a0bf528SMauro Carvalho Chehab 	(1 << 13) - 825 - 117,
8899a0bf528SMauro Carvalho Chehab 	(1 << 13) - 837 - 117,
8909a0bf528SMauro Carvalho Chehab 	(1 << 13) - 811 - 117,
8919a0bf528SMauro Carvalho Chehab 	(1 << 13) - 766 - 117,
8929a0bf528SMauro Carvalho Chehab 	(1 << 13) - 737 - 117,
8939a0bf528SMauro Carvalho Chehab 	(1 << 13) - 693 - 117,
8949a0bf528SMauro Carvalho Chehab 	(1 << 13) - 648 - 117,
8959a0bf528SMauro Carvalho Chehab 	(1 << 13) - 619 - 117,
8969a0bf528SMauro Carvalho Chehab 	(1 << 13) - 575 - 117,
8979a0bf528SMauro Carvalho Chehab 	(1 << 13) - 531 - 117,
8989a0bf528SMauro Carvalho Chehab 	(1 << 13) - 501 - 117,
8999a0bf528SMauro Carvalho Chehab 
9009a0bf528SMauro Carvalho Chehab 	4, 108,
9019a0bf528SMauro Carvalho Chehab 	0,
9029a0bf528SMauro Carvalho Chehab 	0,
9039a0bf528SMauro Carvalho Chehab 	0,
9049a0bf528SMauro Carvalho Chehab 	0,
9059a0bf528SMauro Carvalho Chehab 
9069a0bf528SMauro Carvalho Chehab 	1, 175,
9079a0bf528SMauro Carvalho Chehab 	0x0410,
9089a0bf528SMauro Carvalho Chehab 	1, 179,
9099a0bf528SMauro Carvalho Chehab 	8192,			// P_fft_nb_to_cut
9109a0bf528SMauro Carvalho Chehab 
9119a0bf528SMauro Carvalho Chehab 	6, 181,
9129a0bf528SMauro Carvalho Chehab 	0x2800,			// P_coff_corthres_ ( 2k 4k 8k ) 0x2800
9139a0bf528SMauro Carvalho Chehab 	0x2800,
9149a0bf528SMauro Carvalho Chehab 	0x2800,
9159a0bf528SMauro Carvalho Chehab 	0x2800,			// P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
9169a0bf528SMauro Carvalho Chehab 	0x2800,
9179a0bf528SMauro Carvalho Chehab 	0x2800,
9189a0bf528SMauro Carvalho Chehab 
9199a0bf528SMauro Carvalho Chehab 	2, 193,
9209a0bf528SMauro Carvalho Chehab 	0x0666,			// P_pha3_thres
9219a0bf528SMauro Carvalho Chehab 	0x0000,			// P_cti_use_cpe, P_cti_use_prog
9229a0bf528SMauro Carvalho Chehab 
9239a0bf528SMauro Carvalho Chehab 	2, 205,
9249a0bf528SMauro Carvalho Chehab 	0x200f,			// P_cspu_regul, P_cspu_win_cut
9259a0bf528SMauro Carvalho Chehab 	0x000f,			// P_des_shift_work
9269a0bf528SMauro Carvalho Chehab 
9279a0bf528SMauro Carvalho Chehab 	5, 215,
9289a0bf528SMauro Carvalho Chehab 	0x023d,			// P_adp_regul_cnt
9299a0bf528SMauro Carvalho Chehab 	0x00a4,			// P_adp_noise_cnt
9309a0bf528SMauro Carvalho Chehab 	0x00a4,			// P_adp_regul_ext
9319a0bf528SMauro Carvalho Chehab 	0x7ff0,			// P_adp_noise_ext
9329a0bf528SMauro Carvalho Chehab 	0x3ccc,			// P_adp_fil
9339a0bf528SMauro Carvalho Chehab 
9349a0bf528SMauro Carvalho Chehab 	1, 230,
9359a0bf528SMauro Carvalho Chehab 	0x0000,			// P_2d_byp_ti_num
9369a0bf528SMauro Carvalho Chehab 
9379a0bf528SMauro Carvalho Chehab 	1, 263,
9389a0bf528SMauro Carvalho Chehab 	0x800,			//P_equal_thres_wgn
9399a0bf528SMauro Carvalho Chehab 
9409a0bf528SMauro Carvalho Chehab 	1, 268,
9419a0bf528SMauro Carvalho Chehab 	(2 << 9) | 39,		// P_equal_ctrl_synchro, P_equal_speedmode
9429a0bf528SMauro Carvalho Chehab 
9439a0bf528SMauro Carvalho Chehab 	1, 270,
9449a0bf528SMauro Carvalho Chehab 	0x0001,			// P_div_lock0_wait
9459a0bf528SMauro Carvalho Chehab 	1, 285,
9469a0bf528SMauro Carvalho Chehab 	0x0020,			//p_fec_
9479a0bf528SMauro Carvalho Chehab 	1, 299,
9489a0bf528SMauro Carvalho Chehab 	0x0062,			/* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */
9499a0bf528SMauro Carvalho Chehab 
9509a0bf528SMauro Carvalho Chehab 	1, 338,
9519a0bf528SMauro Carvalho Chehab 	(1 << 12) |		// P_ctrl_corm_thres4pre_freq_inh=1
9529a0bf528SMauro Carvalho Chehab 		(1 << 10) |
9539a0bf528SMauro Carvalho Chehab 		(0 << 9) |		/* P_ctrl_pre_freq_inh=0 */
9549a0bf528SMauro Carvalho Chehab 		(3 << 5) |		/* P_ctrl_pre_freq_step=3 */
9559a0bf528SMauro Carvalho Chehab 		(1 << 0),		/* P_pre_freq_win_len=1 */
9569a0bf528SMauro Carvalho Chehab 
9579a0bf528SMauro Carvalho Chehab 	0,
9589a0bf528SMauro Carvalho Chehab };
9599a0bf528SMauro Carvalho Chehab 
9609a0bf528SMauro Carvalho Chehab static u16 dib8000_identify(struct i2c_device *client)
9619a0bf528SMauro Carvalho Chehab {
9629a0bf528SMauro Carvalho Chehab 	u16 value;
9639a0bf528SMauro Carvalho Chehab 
9649a0bf528SMauro Carvalho Chehab 	//because of glitches sometimes
9659a0bf528SMauro Carvalho Chehab 	value = dib8000_i2c_read16(client, 896);
9669a0bf528SMauro Carvalho Chehab 
9679a0bf528SMauro Carvalho Chehab 	if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
9688af16adfSMauro Carvalho Chehab 		dprintk("wrong Vendor ID (read=0x%x)\n", value);
9699a0bf528SMauro Carvalho Chehab 		return 0;
9709a0bf528SMauro Carvalho Chehab 	}
9719a0bf528SMauro Carvalho Chehab 
9729a0bf528SMauro Carvalho Chehab 	value = dib8000_i2c_read16(client, 897);
9739a0bf528SMauro Carvalho Chehab 	if (value != 0x8000 && value != 0x8001 &&
9749a0bf528SMauro Carvalho Chehab 			value != 0x8002 && value != 0x8090) {
9758af16adfSMauro Carvalho Chehab 		dprintk("wrong Device ID (%x)\n", value);
9769a0bf528SMauro Carvalho Chehab 		return 0;
9779a0bf528SMauro Carvalho Chehab 	}
9789a0bf528SMauro Carvalho Chehab 
9799a0bf528SMauro Carvalho Chehab 	switch (value) {
9809a0bf528SMauro Carvalho Chehab 	case 0x8000:
9818af16adfSMauro Carvalho Chehab 		dprintk("found DiB8000A\n");
9829a0bf528SMauro Carvalho Chehab 		break;
9839a0bf528SMauro Carvalho Chehab 	case 0x8001:
9848af16adfSMauro Carvalho Chehab 		dprintk("found DiB8000B\n");
9859a0bf528SMauro Carvalho Chehab 		break;
9869a0bf528SMauro Carvalho Chehab 	case 0x8002:
9878af16adfSMauro Carvalho Chehab 		dprintk("found DiB8000C\n");
9889a0bf528SMauro Carvalho Chehab 		break;
9899a0bf528SMauro Carvalho Chehab 	case 0x8090:
9908af16adfSMauro Carvalho Chehab 		dprintk("found DiB8096P\n");
9919a0bf528SMauro Carvalho Chehab 		break;
9929a0bf528SMauro Carvalho Chehab 	}
9939a0bf528SMauro Carvalho Chehab 	return value;
9949a0bf528SMauro Carvalho Chehab }
9959a0bf528SMauro Carvalho Chehab 
9967a9d85d5SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 *unc);
9977a9d85d5SMauro Carvalho Chehab 
9986ef06e78SMauro Carvalho Chehab static void dib8000_reset_stats(struct dvb_frontend *fe)
9996ef06e78SMauro Carvalho Chehab {
10006ef06e78SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
10016ef06e78SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
10027a9d85d5SMauro Carvalho Chehab 	u32 ucb;
10036ef06e78SMauro Carvalho Chehab 
10046ef06e78SMauro Carvalho Chehab 	memset(&c->strength, 0, sizeof(c->strength));
10056ef06e78SMauro Carvalho Chehab 	memset(&c->cnr, 0, sizeof(c->cnr));
10066ef06e78SMauro Carvalho Chehab 	memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
10076ef06e78SMauro Carvalho Chehab 	memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
10086ef06e78SMauro Carvalho Chehab 	memset(&c->block_error, 0, sizeof(c->block_error));
10096ef06e78SMauro Carvalho Chehab 
10106ef06e78SMauro Carvalho Chehab 	c->strength.len = 1;
10116ef06e78SMauro Carvalho Chehab 	c->cnr.len = 1;
10126ef06e78SMauro Carvalho Chehab 	c->block_error.len = 1;
10130400c535SMauro Carvalho Chehab 	c->block_count.len = 1;
10146ef06e78SMauro Carvalho Chehab 	c->post_bit_error.len = 1;
10156ef06e78SMauro Carvalho Chehab 	c->post_bit_count.len = 1;
10166ef06e78SMauro Carvalho Chehab 
1017b4600d70SMauro Carvalho Chehab 	c->strength.stat[0].scale = FE_SCALE_DECIBEL;
10186ef06e78SMauro Carvalho Chehab 	c->strength.stat[0].uvalue = 0;
10196ef06e78SMauro Carvalho Chehab 
10206ef06e78SMauro Carvalho Chehab 	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10216ef06e78SMauro Carvalho Chehab 	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10220400c535SMauro Carvalho Chehab 	c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10236ef06e78SMauro Carvalho Chehab 	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10246ef06e78SMauro Carvalho Chehab 	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10257a9d85d5SMauro Carvalho Chehab 
10267a9d85d5SMauro Carvalho Chehab 	dib8000_read_unc_blocks(fe, &ucb);
1027704f01bbSMauro Carvalho Chehab 
10287a9d85d5SMauro Carvalho Chehab 	state->init_ucb = -ucb;
10290400c535SMauro Carvalho Chehab 	state->ber_jiffies_stats = 0;
10300400c535SMauro Carvalho Chehab 	state->per_jiffies_stats = 0;
10310400c535SMauro Carvalho Chehab 	memset(&state->ber_jiffies_stats_layer, 0,
10320400c535SMauro Carvalho Chehab 	       sizeof(state->ber_jiffies_stats_layer));
10336ef06e78SMauro Carvalho Chehab }
10346ef06e78SMauro Carvalho Chehab 
10359a0bf528SMauro Carvalho Chehab static int dib8000_reset(struct dvb_frontend *fe)
10369a0bf528SMauro Carvalho Chehab {
10379a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
10389a0bf528SMauro Carvalho Chehab 
10399a0bf528SMauro Carvalho Chehab 	if ((state->revision = dib8000_identify(&state->i2c)) == 0)
10409a0bf528SMauro Carvalho Chehab 		return -EINVAL;
10419a0bf528SMauro Carvalho Chehab 
10429a0bf528SMauro Carvalho Chehab 	/* sram lead in, rdy */
10439a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
10449a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1287, 0x0003);
10459a0bf528SMauro Carvalho Chehab 
10469a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8000)
10478af16adfSMauro Carvalho Chehab 		dprintk("error : dib8000 MA not supported\n");
10489a0bf528SMauro Carvalho Chehab 
10499a0bf528SMauro Carvalho Chehab 	dibx000_reset_i2c_master(&state->i2c_master);
10509a0bf528SMauro Carvalho Chehab 
10519a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
10529a0bf528SMauro Carvalho Chehab 
10539a0bf528SMauro Carvalho Chehab 	/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
1054173a64cbSPatrick Boettcher 	dib8000_set_adc_state(state, DIBX000_ADC_OFF);
10559a0bf528SMauro Carvalho Chehab 
10569a0bf528SMauro Carvalho Chehab 	/* restart all parts */
10579a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0xffff);
10589a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 771, 0xffff);
10599a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 772, 0xfffc);
10606d38454aSMauro Carvalho Chehab 	dib8000_write_word(state, 898, 0x000c);	/* restart sad */
10619a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
10629a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1280, 0x0045);
10639a0bf528SMauro Carvalho Chehab 	else
10649a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1280, 0x004d);
10659a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1281, 0x000c);
10669a0bf528SMauro Carvalho Chehab 
10679a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0000);
10689a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 771, 0x0000);
10699a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 772, 0x0000);
10709a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 898, 0x0004);	// sad
10719a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1280, 0x0000);
10729a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1281, 0x0000);
10739a0bf528SMauro Carvalho Chehab 
10749a0bf528SMauro Carvalho Chehab 	/* drives */
10759a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
10769a0bf528SMauro Carvalho Chehab 		if (state->cfg.drives)
10779a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 906, state->cfg.drives);
10789a0bf528SMauro Carvalho Chehab 		else {
10798af16adfSMauro Carvalho Chehab 			dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.\n");
10809a0bf528SMauro Carvalho Chehab 			/* min drive SDRAM - not optimal - adjust */
10819a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 906, 0x2d98);
10829a0bf528SMauro Carvalho Chehab 		}
10839a0bf528SMauro Carvalho Chehab 	}
10849a0bf528SMauro Carvalho Chehab 
10859a0bf528SMauro Carvalho Chehab 	dib8000_reset_pll(state);
10869a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
10879a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 898, 0x0004);
10889a0bf528SMauro Carvalho Chehab 
10899a0bf528SMauro Carvalho Chehab 	if (dib8000_reset_gpio(state) != 0)
10908af16adfSMauro Carvalho Chehab 		dprintk("GPIO reset was not successful.\n");
10919a0bf528SMauro Carvalho Chehab 
10929a0bf528SMauro Carvalho Chehab 	if ((state->revision != 0x8090) &&
10939a0bf528SMauro Carvalho Chehab 			(dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
10948af16adfSMauro Carvalho Chehab 		dprintk("OUTPUT_MODE could not be resetted.\n");
10959a0bf528SMauro Carvalho Chehab 
10969a0bf528SMauro Carvalho Chehab 	state->current_agc = NULL;
10979a0bf528SMauro Carvalho Chehab 
10989a0bf528SMauro Carvalho Chehab 	// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
10999a0bf528SMauro Carvalho Chehab 	/* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
11009a0bf528SMauro Carvalho Chehab 	if (state->cfg.pll->ifreq == 0)
11019a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 40, 0x0755);	/* P_iqc_corr_inh = 0 enable IQcorr block */
11029a0bf528SMauro Carvalho Chehab 	else
11039a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 40, 0x1f55);	/* P_iqc_corr_inh = 1 disable IQcorr block */
11049a0bf528SMauro Carvalho Chehab 
11059a0bf528SMauro Carvalho Chehab 	{
11069a0bf528SMauro Carvalho Chehab 		u16 l = 0, r;
11079a0bf528SMauro Carvalho Chehab 		const u16 *n;
11089a0bf528SMauro Carvalho Chehab 		n = dib8000_defaults;
11099a0bf528SMauro Carvalho Chehab 		l = *n++;
11109a0bf528SMauro Carvalho Chehab 		while (l) {
11119a0bf528SMauro Carvalho Chehab 			r = *n++;
11129a0bf528SMauro Carvalho Chehab 			do {
11139a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, r, *n++);
11149a0bf528SMauro Carvalho Chehab 				r++;
11159a0bf528SMauro Carvalho Chehab 			} while (--l);
11169a0bf528SMauro Carvalho Chehab 			l = *n++;
11179a0bf528SMauro Carvalho Chehab 		}
11189a0bf528SMauro Carvalho Chehab 	}
1119173a64cbSPatrick Boettcher 
11209a0bf528SMauro Carvalho Chehab 	state->isdbt_cfg_loaded = 0;
11219a0bf528SMauro Carvalho Chehab 
11229a0bf528SMauro Carvalho Chehab 	//div_cfg override for special configs
1123173a64cbSPatrick Boettcher 	if ((state->revision != 8090) && (state->cfg.div_cfg != 0))
11249a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 903, state->cfg.div_cfg);
11259a0bf528SMauro Carvalho Chehab 
11269a0bf528SMauro Carvalho Chehab 	/* unforce divstr regardless whether i2c enumeration was done or not */
11279a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
11289a0bf528SMauro Carvalho Chehab 
11299a0bf528SMauro Carvalho Chehab 	dib8000_set_bandwidth(fe, 6000);
11309a0bf528SMauro Carvalho Chehab 
11319a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
11329a0bf528SMauro Carvalho Chehab 	dib8000_sad_calib(state);
1133173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
11349a0bf528SMauro Carvalho Chehab 		dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
1135173a64cbSPatrick Boettcher 
1136173a64cbSPatrick Boettcher 	/* ber_rs_len = 3 */
1137173a64cbSPatrick Boettcher 	dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));
11389a0bf528SMauro Carvalho Chehab 
11399a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
11409a0bf528SMauro Carvalho Chehab 
11416ef06e78SMauro Carvalho Chehab 	dib8000_reset_stats(fe);
11426ef06e78SMauro Carvalho Chehab 
11439a0bf528SMauro Carvalho Chehab 	return 0;
11449a0bf528SMauro Carvalho Chehab }
11459a0bf528SMauro Carvalho Chehab 
11469a0bf528SMauro Carvalho Chehab static void dib8000_restart_agc(struct dib8000_state *state)
11479a0bf528SMauro Carvalho Chehab {
11489a0bf528SMauro Carvalho Chehab 	// P_restart_iqc & P_restart_agc
11499a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0a00);
11509a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0000);
11519a0bf528SMauro Carvalho Chehab }
11529a0bf528SMauro Carvalho Chehab 
11539a0bf528SMauro Carvalho Chehab static int dib8000_update_lna(struct dib8000_state *state)
11549a0bf528SMauro Carvalho Chehab {
11559a0bf528SMauro Carvalho Chehab 	u16 dyn_gain;
11569a0bf528SMauro Carvalho Chehab 
11579a0bf528SMauro Carvalho Chehab 	if (state->cfg.update_lna) {
11589a0bf528SMauro Carvalho Chehab 		// read dyn_gain here (because it is demod-dependent and not tuner)
11599a0bf528SMauro Carvalho Chehab 		dyn_gain = dib8000_read_word(state, 390);
11609a0bf528SMauro Carvalho Chehab 
11619a0bf528SMauro Carvalho Chehab 		if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
11629a0bf528SMauro Carvalho Chehab 			dib8000_restart_agc(state);
11639a0bf528SMauro Carvalho Chehab 			return 1;
11649a0bf528SMauro Carvalho Chehab 		}
11659a0bf528SMauro Carvalho Chehab 	}
11669a0bf528SMauro Carvalho Chehab 	return 0;
11679a0bf528SMauro Carvalho Chehab }
11689a0bf528SMauro Carvalho Chehab 
11699a0bf528SMauro Carvalho Chehab static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
11709a0bf528SMauro Carvalho Chehab {
11719a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *agc = NULL;
11729a0bf528SMauro Carvalho Chehab 	int i;
11739a0bf528SMauro Carvalho Chehab 	u16 reg;
11749a0bf528SMauro Carvalho Chehab 
11759a0bf528SMauro Carvalho Chehab 	if (state->current_band == band && state->current_agc != NULL)
11769a0bf528SMauro Carvalho Chehab 		return 0;
11779a0bf528SMauro Carvalho Chehab 	state->current_band = band;
11789a0bf528SMauro Carvalho Chehab 
11799a0bf528SMauro Carvalho Chehab 	for (i = 0; i < state->cfg.agc_config_count; i++)
11809a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc[i].band_caps & band) {
11819a0bf528SMauro Carvalho Chehab 			agc = &state->cfg.agc[i];
11829a0bf528SMauro Carvalho Chehab 			break;
11839a0bf528SMauro Carvalho Chehab 		}
11849a0bf528SMauro Carvalho Chehab 
11859a0bf528SMauro Carvalho Chehab 	if (agc == NULL) {
11868af16adfSMauro Carvalho Chehab 		dprintk("no valid AGC configuration found for band 0x%02x\n", band);
11879a0bf528SMauro Carvalho Chehab 		return -EINVAL;
11889a0bf528SMauro Carvalho Chehab 	}
11899a0bf528SMauro Carvalho Chehab 
11909a0bf528SMauro Carvalho Chehab 	state->current_agc = agc;
11919a0bf528SMauro Carvalho Chehab 
11929a0bf528SMauro Carvalho Chehab 	/* AGC */
11939a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 76, agc->setup);
11949a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 77, agc->inv_gain);
11959a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 78, agc->time_stabiliz);
11969a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
11979a0bf528SMauro Carvalho Chehab 
11989a0bf528SMauro Carvalho Chehab 	// Demod AGC loop configuration
11999a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
12009a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
12019a0bf528SMauro Carvalho Chehab 
12028af16adfSMauro Carvalho Chehab 	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
12039a0bf528SMauro Carvalho Chehab 		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
12049a0bf528SMauro Carvalho Chehab 
12059a0bf528SMauro Carvalho Chehab 	/* AGC continued */
12069a0bf528SMauro Carvalho Chehab 	if (state->wbd_ref != 0)
12079a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 106, state->wbd_ref);
12089a0bf528SMauro Carvalho Chehab 	else			// use default
12099a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 106, agc->wbd_ref);
12109a0bf528SMauro Carvalho Chehab 
12119a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090) {
12129a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 922) & (0x3 << 2);
12139a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
12149a0bf528SMauro Carvalho Chehab 	}
12159a0bf528SMauro Carvalho Chehab 
12169a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
12179a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 108, agc->agc1_max);
12189a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 109, agc->agc1_min);
12199a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 110, agc->agc2_max);
12209a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 111, agc->agc2_min);
12219a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
12229a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
12239a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
12249a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
12259a0bf528SMauro Carvalho Chehab 
12269a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 75, agc->agc1_pt3);
12279a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
12289a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923,
12299a0bf528SMauro Carvalho Chehab 				(dib8000_read_word(state, 923) & 0xffe3) |
12309a0bf528SMauro Carvalho Chehab 				(agc->wbd_inv << 4) | (agc->wbd_sel << 2));
12319a0bf528SMauro Carvalho Chehab 
12329a0bf528SMauro Carvalho Chehab 	return 0;
12339a0bf528SMauro Carvalho Chehab }
12349a0bf528SMauro Carvalho Chehab 
1235d44913c1SMauro Carvalho Chehab static void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
12369a0bf528SMauro Carvalho Chehab {
12379a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
12389a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_ADC_ON);
12399a0bf528SMauro Carvalho Chehab 	dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
12409a0bf528SMauro Carvalho Chehab }
12419a0bf528SMauro Carvalho Chehab 
12429a0bf528SMauro Carvalho Chehab static int dib8000_agc_soft_split(struct dib8000_state *state)
12439a0bf528SMauro Carvalho Chehab {
12449a0bf528SMauro Carvalho Chehab 	u16 agc, split_offset;
12459a0bf528SMauro Carvalho Chehab 
12469a0bf528SMauro Carvalho Chehab 	if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
1247d6c62b76SMauro Carvalho Chehab 		return 0;
12489a0bf528SMauro Carvalho Chehab 
12499a0bf528SMauro Carvalho Chehab 	// n_agc_global
12509a0bf528SMauro Carvalho Chehab 	agc = dib8000_read_word(state, 390);
12519a0bf528SMauro Carvalho Chehab 
12529a0bf528SMauro Carvalho Chehab 	if (agc > state->current_agc->split.min_thres)
12539a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.min;
12549a0bf528SMauro Carvalho Chehab 	else if (agc < state->current_agc->split.max_thres)
12559a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.max;
12569a0bf528SMauro Carvalho Chehab 	else
12579a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.max *
12589a0bf528SMauro Carvalho Chehab 			(agc - state->current_agc->split.min_thres) /
12599a0bf528SMauro Carvalho Chehab 			(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
12609a0bf528SMauro Carvalho Chehab 
12618af16adfSMauro Carvalho Chehab 	dprintk("AGC split_offset: %d\n", split_offset);
12629a0bf528SMauro Carvalho Chehab 
12639a0bf528SMauro Carvalho Chehab 	// P_agc_force_split and P_agc_split_offset
12649a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
12659a0bf528SMauro Carvalho Chehab 	return 5000;
12669a0bf528SMauro Carvalho Chehab }
12679a0bf528SMauro Carvalho Chehab 
12689a0bf528SMauro Carvalho Chehab static int dib8000_agc_startup(struct dvb_frontend *fe)
12699a0bf528SMauro Carvalho Chehab {
12709a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
12719a0bf528SMauro Carvalho Chehab 	enum frontend_tune_state *tune_state = &state->tune_state;
12729a0bf528SMauro Carvalho Chehab 	int ret = 0;
1273901c4ad6SMauro Carvalho Chehab 	u16 reg;
1274901c4ad6SMauro Carvalho Chehab 	u32 upd_demod_gain_period = 0x8000;
12759a0bf528SMauro Carvalho Chehab 
12769a0bf528SMauro Carvalho Chehab 	switch (*tune_state) {
12779a0bf528SMauro Carvalho Chehab 	case CT_AGC_START:
12789a0bf528SMauro Carvalho Chehab 		// set power-up level: interf+analog+AGC
12799a0bf528SMauro Carvalho Chehab 
12809a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090)
12819a0bf528SMauro Carvalho Chehab 			dib8000_set_adc_state(state, DIBX000_ADC_ON);
12829a0bf528SMauro Carvalho Chehab 		else {
12839a0bf528SMauro Carvalho Chehab 			dib8000_set_power_mode(state, DIB8000_POWER_ALL);
12849a0bf528SMauro Carvalho Chehab 
12859a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1947)&0xff00;
12869a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1946,
12879a0bf528SMauro Carvalho Chehab 					upd_demod_gain_period & 0xFFFF);
12889a0bf528SMauro Carvalho Chehab 			/* bit 14 = enDemodGain */
12899a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1947, reg | (1<<14) |
12909a0bf528SMauro Carvalho Chehab 					((upd_demod_gain_period >> 16) & 0xFF));
12919a0bf528SMauro Carvalho Chehab 
12929a0bf528SMauro Carvalho Chehab 			/* enable adc i & q */
12939a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1920);
12949a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1920, (reg | 0x3) &
12959a0bf528SMauro Carvalho Chehab 					(~(1 << 7)));
12969a0bf528SMauro Carvalho Chehab 		}
12979a0bf528SMauro Carvalho Chehab 
12989a0bf528SMauro Carvalho Chehab 		if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
12999a0bf528SMauro Carvalho Chehab 			*tune_state = CT_AGC_STOP;
13009a0bf528SMauro Carvalho Chehab 			state->status = FE_STATUS_TUNE_FAILED;
13019a0bf528SMauro Carvalho Chehab 			break;
13029a0bf528SMauro Carvalho Chehab 		}
13039a0bf528SMauro Carvalho Chehab 
13049a0bf528SMauro Carvalho Chehab 		ret = 70;
13059a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STEP_0;
13069a0bf528SMauro Carvalho Chehab 		break;
13079a0bf528SMauro Carvalho Chehab 
13089a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_0:
13099a0bf528SMauro Carvalho Chehab 		//AGC initialization
13109a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
13119a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(fe, 1);
13129a0bf528SMauro Carvalho Chehab 
13139a0bf528SMauro Carvalho Chehab 		dib8000_restart_agc(state);
13149a0bf528SMauro Carvalho Chehab 
13159a0bf528SMauro Carvalho Chehab 		// wait AGC rough lock time
13169a0bf528SMauro Carvalho Chehab 		ret = 50;
13179a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STEP_1;
13189a0bf528SMauro Carvalho Chehab 		break;
13199a0bf528SMauro Carvalho Chehab 
13209a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_1:
13219a0bf528SMauro Carvalho Chehab 		// wait AGC accurate lock time
13229a0bf528SMauro Carvalho Chehab 		ret = 70;
13239a0bf528SMauro Carvalho Chehab 
13249a0bf528SMauro Carvalho Chehab 		if (dib8000_update_lna(state))
13259a0bf528SMauro Carvalho Chehab 			// wait only AGC rough lock time
13269a0bf528SMauro Carvalho Chehab 			ret = 50;
13279a0bf528SMauro Carvalho Chehab 		else
13289a0bf528SMauro Carvalho Chehab 			*tune_state = CT_AGC_STEP_2;
13299a0bf528SMauro Carvalho Chehab 		break;
13309a0bf528SMauro Carvalho Chehab 
13319a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_2:
13329a0bf528SMauro Carvalho Chehab 		dib8000_agc_soft_split(state);
13339a0bf528SMauro Carvalho Chehab 
13349a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
13359a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(fe, 0);
13369a0bf528SMauro Carvalho Chehab 
13379a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STOP;
13389a0bf528SMauro Carvalho Chehab 		break;
13399a0bf528SMauro Carvalho Chehab 	default:
13409a0bf528SMauro Carvalho Chehab 		ret = dib8000_agc_soft_split(state);
13419a0bf528SMauro Carvalho Chehab 		break;
13429a0bf528SMauro Carvalho Chehab 	}
13439a0bf528SMauro Carvalho Chehab 	return ret;
13449a0bf528SMauro Carvalho Chehab 
13459a0bf528SMauro Carvalho Chehab }
13469a0bf528SMauro Carvalho Chehab 
13479a0bf528SMauro Carvalho Chehab static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
13489a0bf528SMauro Carvalho Chehab {
13499a0bf528SMauro Carvalho Chehab 	u16 reg;
13509a0bf528SMauro Carvalho Chehab 
13519a0bf528SMauro Carvalho Chehab 	drive &= 0x7;
13529a0bf528SMauro Carvalho Chehab 
13539a0bf528SMauro Carvalho Chehab 	/* drive host bus 2, 3, 4 */
13549a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1798) &
13559a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
13569a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
13579a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1798, reg);
13589a0bf528SMauro Carvalho Chehab 
13599a0bf528SMauro Carvalho Chehab 	/* drive host bus 5,6 */
13609a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
13619a0bf528SMauro Carvalho Chehab 	reg |= (drive<<8) | (drive<<2);
13629a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1799, reg);
13639a0bf528SMauro Carvalho Chehab 
13649a0bf528SMauro Carvalho Chehab 	/* drive host bus 7, 8, 9 */
13659a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1800) &
13669a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
13679a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
13689a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1800, reg);
13699a0bf528SMauro Carvalho Chehab 
13709a0bf528SMauro Carvalho Chehab 	/* drive host bus 10, 11 */
13719a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
13729a0bf528SMauro Carvalho Chehab 	reg |= (drive<<8) | (drive<<2);
13739a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1801, reg);
13749a0bf528SMauro Carvalho Chehab 
13759a0bf528SMauro Carvalho Chehab 	/* drive host bus 12, 13, 14 */
13769a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1802) &
13779a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
13789a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
13799a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1802, reg);
13809a0bf528SMauro Carvalho Chehab }
13819a0bf528SMauro Carvalho Chehab 
13829a0bf528SMauro Carvalho Chehab static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
13839a0bf528SMauro Carvalho Chehab 		u32 insertExtSynchro, u32 syncSize)
13849a0bf528SMauro Carvalho Chehab {
13859a0bf528SMauro Carvalho Chehab 	u32 quantif = 3;
13869a0bf528SMauro Carvalho Chehab 	u32 nom = (insertExtSynchro * P_Kin+syncSize);
13879a0bf528SMauro Carvalho Chehab 	u32 denom = P_Kout;
13889a0bf528SMauro Carvalho Chehab 	u32 syncFreq = ((nom << quantif) / denom);
13899a0bf528SMauro Carvalho Chehab 
13909a0bf528SMauro Carvalho Chehab 	if ((syncFreq & ((1 << quantif) - 1)) != 0)
13919a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif) + 1;
13929a0bf528SMauro Carvalho Chehab 	else
13939a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif);
13949a0bf528SMauro Carvalho Chehab 
13959a0bf528SMauro Carvalho Chehab 	if (syncFreq != 0)
13969a0bf528SMauro Carvalho Chehab 		syncFreq = syncFreq - 1;
13979a0bf528SMauro Carvalho Chehab 
13989a0bf528SMauro Carvalho Chehab 	return syncFreq;
13999a0bf528SMauro Carvalho Chehab }
14009a0bf528SMauro Carvalho Chehab 
14019a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
14029a0bf528SMauro Carvalho Chehab 		u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
14039a0bf528SMauro Carvalho Chehab 		u32 syncWord, u32 syncSize)
14049a0bf528SMauro Carvalho Chehab {
14058af16adfSMauro Carvalho Chehab 	dprintk("Configure DibStream Tx\n");
14069a0bf528SMauro Carvalho Chehab 
14079a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1615, 1);
14089a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1603, P_Kin);
14099a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1605, P_Kout);
14109a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1606, insertExtSynchro);
14119a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1608, synchroMode);
14129a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
14139a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1610, syncWord & 0xffff);
14149a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1612, syncSize);
14159a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1615, 0);
14169a0bf528SMauro Carvalho Chehab }
14179a0bf528SMauro Carvalho Chehab 
14189a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
14199a0bf528SMauro Carvalho Chehab 		u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
14209a0bf528SMauro Carvalho Chehab 		u32 syncWord, u32 syncSize, u32 dataOutRate)
14219a0bf528SMauro Carvalho Chehab {
14229a0bf528SMauro Carvalho Chehab 	u32 syncFreq;
14239a0bf528SMauro Carvalho Chehab 
14248af16adfSMauro Carvalho Chehab 	dprintk("Configure DibStream Rx synchroMode = %d\n", synchroMode);
14259a0bf528SMauro Carvalho Chehab 
14269a0bf528SMauro Carvalho Chehab 	if ((P_Kin != 0) && (P_Kout != 0)) {
14279a0bf528SMauro Carvalho Chehab 		syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
14289a0bf528SMauro Carvalho Chehab 				insertExtSynchro, syncSize);
14299a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1542, syncFreq);
14309a0bf528SMauro Carvalho Chehab 	}
14319a0bf528SMauro Carvalho Chehab 
14329a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1554, 1);
14339a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1536, P_Kin);
14349a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1537, P_Kout);
14359a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1539, synchroMode);
14369a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
14379a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1541, syncWord & 0xffff);
14389a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1543, syncSize);
14399a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1544, dataOutRate);
14409a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1554, 0);
14419a0bf528SMauro Carvalho Chehab }
14429a0bf528SMauro Carvalho Chehab 
14439a0bf528SMauro Carvalho Chehab static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
14449a0bf528SMauro Carvalho Chehab {
14459a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
14469a0bf528SMauro Carvalho Chehab 
14479a0bf528SMauro Carvalho Chehab 	reg_1287 = dib8000_read_word(state, 1287);
14489a0bf528SMauro Carvalho Chehab 
14499a0bf528SMauro Carvalho Chehab 	switch (onoff) {
14509a0bf528SMauro Carvalho Chehab 	case 1:
14519a0bf528SMauro Carvalho Chehab 			reg_1287 &= ~(1 << 8);
14529a0bf528SMauro Carvalho Chehab 			break;
14539a0bf528SMauro Carvalho Chehab 	case 0:
14549a0bf528SMauro Carvalho Chehab 			reg_1287 |= (1 << 8);
14559a0bf528SMauro Carvalho Chehab 			break;
14569a0bf528SMauro Carvalho Chehab 	}
14579a0bf528SMauro Carvalho Chehab 
14589a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1287, reg_1287);
14599a0bf528SMauro Carvalho Chehab }
14609a0bf528SMauro Carvalho Chehab 
14619a0bf528SMauro Carvalho Chehab static void dib8096p_configMpegMux(struct dib8000_state *state,
14629a0bf528SMauro Carvalho Chehab 		u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
14639a0bf528SMauro Carvalho Chehab {
14649a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
14659a0bf528SMauro Carvalho Chehab 
14668af16adfSMauro Carvalho Chehab 	dprintk("Enable Mpeg mux\n");
14679a0bf528SMauro Carvalho Chehab 
14689a0bf528SMauro Carvalho Chehab 	dib8096p_enMpegMux(state, 0);
14699a0bf528SMauro Carvalho Chehab 
14709a0bf528SMauro Carvalho Chehab 	/* If the input mode is MPEG do not divide the serial clock */
14719a0bf528SMauro Carvalho Chehab 	if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
14729a0bf528SMauro Carvalho Chehab 		enSerialClkDiv2 = 0;
14739a0bf528SMauro Carvalho Chehab 
14749a0bf528SMauro Carvalho Chehab 	reg_1287 = ((pulseWidth & 0x1f) << 3) |
14759a0bf528SMauro Carvalho Chehab 		((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
14769a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1287, reg_1287);
14779a0bf528SMauro Carvalho Chehab 
14789a0bf528SMauro Carvalho Chehab 	dib8096p_enMpegMux(state, 1);
14799a0bf528SMauro Carvalho Chehab }
14809a0bf528SMauro Carvalho Chehab 
14819a0bf528SMauro Carvalho Chehab static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
14829a0bf528SMauro Carvalho Chehab {
14839a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
14849a0bf528SMauro Carvalho Chehab 
14859a0bf528SMauro Carvalho Chehab 	switch (mode) {
14869a0bf528SMauro Carvalho Chehab 	case MPEG_ON_DIBTX:
14878af16adfSMauro Carvalho Chehab 			dprintk("SET MPEG ON DIBSTREAM TX\n");
14889a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
14899a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 9); break;
14909a0bf528SMauro Carvalho Chehab 	case DIV_ON_DIBTX:
14918af16adfSMauro Carvalho Chehab 			dprintk("SET DIV_OUT ON DIBSTREAM TX\n");
14929a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
14939a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 8); break;
14949a0bf528SMauro Carvalho Chehab 	case ADC_ON_DIBTX:
14958af16adfSMauro Carvalho Chehab 			dprintk("SET ADC_OUT ON DIBSTREAM TX\n");
14969a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
14979a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 7); break;
14989a0bf528SMauro Carvalho Chehab 	default:
14999a0bf528SMauro Carvalho Chehab 			break;
15009a0bf528SMauro Carvalho Chehab 	}
15019a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1288, reg_1288);
15029a0bf528SMauro Carvalho Chehab }
15039a0bf528SMauro Carvalho Chehab 
15049a0bf528SMauro Carvalho Chehab static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
15059a0bf528SMauro Carvalho Chehab {
15069a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
15079a0bf528SMauro Carvalho Chehab 
15089a0bf528SMauro Carvalho Chehab 	switch (mode) {
15099a0bf528SMauro Carvalho Chehab 	case DEMOUT_ON_HOSTBUS:
15108af16adfSMauro Carvalho Chehab 			dprintk("SET DEM OUT OLD INTERF ON HOST BUS\n");
15119a0bf528SMauro Carvalho Chehab 			dib8096p_enMpegMux(state, 0);
15129a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 6);
15139a0bf528SMauro Carvalho Chehab 			break;
15149a0bf528SMauro Carvalho Chehab 	case DIBTX_ON_HOSTBUS:
15158af16adfSMauro Carvalho Chehab 			dprintk("SET DIBSTREAM TX ON HOST BUS\n");
15169a0bf528SMauro Carvalho Chehab 			dib8096p_enMpegMux(state, 0);
15179a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 5);
15189a0bf528SMauro Carvalho Chehab 			break;
15199a0bf528SMauro Carvalho Chehab 	case MPEG_ON_HOSTBUS:
15208af16adfSMauro Carvalho Chehab 			dprintk("SET MPEG MUX ON HOST BUS\n");
15219a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 4);
15229a0bf528SMauro Carvalho Chehab 			break;
15239a0bf528SMauro Carvalho Chehab 	default:
15249a0bf528SMauro Carvalho Chehab 			break;
15259a0bf528SMauro Carvalho Chehab 	}
15269a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1288, reg_1288);
15279a0bf528SMauro Carvalho Chehab }
15289a0bf528SMauro Carvalho Chehab 
15299a0bf528SMauro Carvalho Chehab static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
15309a0bf528SMauro Carvalho Chehab {
15319a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
15329a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
15339a0bf528SMauro Carvalho Chehab 
15349a0bf528SMauro Carvalho Chehab 	switch (onoff) {
15359a0bf528SMauro Carvalho Chehab 	case 0: /* only use the internal way - not the diversity input */
15368af16adfSMauro Carvalho Chehab 			dprintk("%s mode OFF : by default Enable Mpeg INPUT\n",
15379a0bf528SMauro Carvalho Chehab 					__func__);
15389a0bf528SMauro Carvalho Chehab 			/* outputRate = 8 */
15399a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
15409a0bf528SMauro Carvalho Chehab 
15419a0bf528SMauro Carvalho Chehab 			/* Do not divide the serial clock of MPEG MUX in
15429a0bf528SMauro Carvalho Chehab 			   SERIAL MODE in case input mode MPEG is used */
15439a0bf528SMauro Carvalho Chehab 			reg_1287 = dib8000_read_word(state, 1287);
15449a0bf528SMauro Carvalho Chehab 			/* enSerialClkDiv2 == 1 ? */
15459a0bf528SMauro Carvalho Chehab 			if ((reg_1287 & 0x1) == 1) {
15469a0bf528SMauro Carvalho Chehab 				/* force enSerialClkDiv2 = 0 */
15479a0bf528SMauro Carvalho Chehab 				reg_1287 &= ~0x1;
15489a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, 1287, reg_1287);
15499a0bf528SMauro Carvalho Chehab 			}
15509a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 1;
15519a0bf528SMauro Carvalho Chehab 			break;
15529a0bf528SMauro Carvalho Chehab 	case 1: /* both ways */
15539a0bf528SMauro Carvalho Chehab 	case 2: /* only the diversity input */
15548af16adfSMauro Carvalho Chehab 			dprintk("%s ON : Enable diversity INPUT\n", __func__);
15559a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
15569a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 0;
15579a0bf528SMauro Carvalho Chehab 			break;
15589a0bf528SMauro Carvalho Chehab 	}
15599a0bf528SMauro Carvalho Chehab 
15609a0bf528SMauro Carvalho Chehab 	dib8000_set_diversity_in(state->fe[0], onoff);
15619a0bf528SMauro Carvalho Chehab 	return 0;
15629a0bf528SMauro Carvalho Chehab }
15639a0bf528SMauro Carvalho Chehab 
15649a0bf528SMauro Carvalho Chehab static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
15659a0bf528SMauro Carvalho Chehab {
15669a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
15679a0bf528SMauro Carvalho Chehab 	u16 outreg, smo_mode, fifo_threshold;
15689a0bf528SMauro Carvalho Chehab 	u8 prefer_mpeg_mux_use = 1;
15699a0bf528SMauro Carvalho Chehab 	int ret = 0;
15709a0bf528SMauro Carvalho Chehab 
1571173a64cbSPatrick Boettcher 	state->output_mode = mode;
15729a0bf528SMauro Carvalho Chehab 	dib8096p_host_bus_drive(state, 1);
15739a0bf528SMauro Carvalho Chehab 
15749a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
15759a0bf528SMauro Carvalho Chehab 	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
15769a0bf528SMauro Carvalho Chehab 	outreg   = dib8000_read_word(state, 1286) &
15779a0bf528SMauro Carvalho Chehab 		~((1 << 10) | (0x7 << 6) | (1 << 1));
15789a0bf528SMauro Carvalho Chehab 
15799a0bf528SMauro Carvalho Chehab 	switch (mode) {
15809a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:
15819a0bf528SMauro Carvalho Chehab 			outreg = 0;
15829a0bf528SMauro Carvalho Chehab 			break;
15839a0bf528SMauro Carvalho Chehab 
15849a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:
15859a0bf528SMauro Carvalho Chehab 			if (prefer_mpeg_mux_use) {
15868af16adfSMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux\n");
15879a0bf528SMauro Carvalho Chehab 				dib8096p_configMpegMux(state, 3, 1, 1);
15889a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
15899a0bf528SMauro Carvalho Chehab 			} else {/* Use Smooth block */
15908af16adfSMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc\n");
15919a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state,
15929a0bf528SMauro Carvalho Chehab 						DEMOUT_ON_HOSTBUS);
15939a0bf528SMauro Carvalho Chehab 				outreg |= (2 << 6) | (0 << 1);
15949a0bf528SMauro Carvalho Chehab 			}
15959a0bf528SMauro Carvalho Chehab 			break;
15969a0bf528SMauro Carvalho Chehab 
15979a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:
15989a0bf528SMauro Carvalho Chehab 			if (prefer_mpeg_mux_use) {
15998af16adfSMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux\n");
16009a0bf528SMauro Carvalho Chehab 				dib8096p_configMpegMux(state, 2, 0, 0);
16019a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
16029a0bf528SMauro Carvalho Chehab 			} else { /* Use Smooth block */
16038af16adfSMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block\n");
16049a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state,
16059a0bf528SMauro Carvalho Chehab 						DEMOUT_ON_HOSTBUS);
16069a0bf528SMauro Carvalho Chehab 				outreg |= (0 << 6);
16079a0bf528SMauro Carvalho Chehab 			}
16089a0bf528SMauro Carvalho Chehab 			break;
16099a0bf528SMauro Carvalho Chehab 
16109a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
16118af16adfSMauro Carvalho Chehab 			dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block\n");
16129a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
16139a0bf528SMauro Carvalho Chehab 			outreg |= (1 << 6);
16149a0bf528SMauro Carvalho Chehab 			break;
16159a0bf528SMauro Carvalho Chehab 
16169a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:
16179a0bf528SMauro Carvalho Chehab 			/* Using Smooth block because not supported
16189a0bf528SMauro Carvalho Chehab 			   by new Mpeg Mux bloc */
16198af16adfSMauro Carvalho Chehab 			dprintk("dib8096P setting output mode TS_FIFO using Smooth block\n");
16209a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
16219a0bf528SMauro Carvalho Chehab 			outreg |= (5 << 6);
16229a0bf528SMauro Carvalho Chehab 			smo_mode |= (3 << 1);
16239a0bf528SMauro Carvalho Chehab 			fifo_threshold = 512;
16249a0bf528SMauro Carvalho Chehab 			break;
16259a0bf528SMauro Carvalho Chehab 
16269a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
16278af16adfSMauro Carvalho Chehab 			dprintk("dib8096P setting output mode MODE_DIVERSITY\n");
16289a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
16299a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
16309a0bf528SMauro Carvalho Chehab 			break;
16319a0bf528SMauro Carvalho Chehab 
16329a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
16338af16adfSMauro Carvalho Chehab 			dprintk("dib8096P setting output mode MODE_ANALOG_ADC\n");
16349a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
16359a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
16369a0bf528SMauro Carvalho Chehab 			break;
16379a0bf528SMauro Carvalho Chehab 	}
16389a0bf528SMauro Carvalho Chehab 
16399a0bf528SMauro Carvalho Chehab 	if (mode != OUTMODE_HIGH_Z)
16409a0bf528SMauro Carvalho Chehab 		outreg |= (1<<10);
16419a0bf528SMauro Carvalho Chehab 
16428af16adfSMauro Carvalho Chehab 	dprintk("output_mpeg2_in_188_bytes = %d\n",
16439a0bf528SMauro Carvalho Chehab 			state->cfg.output_mpeg2_in_188_bytes);
16449a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
16459a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
16469a0bf528SMauro Carvalho Chehab 
16479a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 299, smo_mode);
16489a0bf528SMauro Carvalho Chehab 	/* synchronous fread */
16499a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
16509a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 1286, outreg);
16519a0bf528SMauro Carvalho Chehab 
16529a0bf528SMauro Carvalho Chehab 	return ret;
16539a0bf528SMauro Carvalho Chehab }
16549a0bf528SMauro Carvalho Chehab 
16559a0bf528SMauro Carvalho Chehab static int map_addr_to_serpar_number(struct i2c_msg *msg)
16569a0bf528SMauro Carvalho Chehab {
16579a0bf528SMauro Carvalho Chehab 	if (msg->buf[0] <= 15)
16589a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 1;
16599a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 17)
16609a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 15;
16619a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 16)
16629a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 17;
16639a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 19)
16649a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 16;
16659a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
16669a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 3;
16679a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 28)
16689a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 23;
16699a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 99)
16709a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 99;
16719a0bf528SMauro Carvalho Chehab 	else
16729a0bf528SMauro Carvalho Chehab 		return -EINVAL;
16739a0bf528SMauro Carvalho Chehab 	return 0;
16749a0bf528SMauro Carvalho Chehab }
16759a0bf528SMauro Carvalho Chehab 
16769a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
16779a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
16789a0bf528SMauro Carvalho Chehab {
16799a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
16809a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1;
16819a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
16829a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
16839a0bf528SMauro Carvalho Chehab 
16849a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
16859a0bf528SMauro Carvalho Chehab 		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
16869a0bf528SMauro Carvalho Chehab 		i--;
16879a0bf528SMauro Carvalho Chehab 		if (i == 0)
16888af16adfSMauro Carvalho Chehab 			dprintk("Tuner ITF: write busy (overflow)\n");
16899a0bf528SMauro Carvalho Chehab 	}
16909a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
16919a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
16929a0bf528SMauro Carvalho Chehab 
16939a0bf528SMauro Carvalho Chehab 	return num;
16949a0bf528SMauro Carvalho Chehab }
16959a0bf528SMauro Carvalho Chehab 
16969a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
16979a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
16989a0bf528SMauro Carvalho Chehab {
16999a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
17009a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1, n_empty = 1;
17019a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
17029a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
17039a0bf528SMauro Carvalho Chehab 	u16 read_word;
17049a0bf528SMauro Carvalho Chehab 
17059a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
17069a0bf528SMauro Carvalho Chehab 		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
17079a0bf528SMauro Carvalho Chehab 		i--;
17089a0bf528SMauro Carvalho Chehab 		if (i == 0)
17098af16adfSMauro Carvalho Chehab 			dprintk("TunerITF: read busy (overflow)\n");
17109a0bf528SMauro Carvalho Chehab 	}
17119a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
17129a0bf528SMauro Carvalho Chehab 
17139a0bf528SMauro Carvalho Chehab 	i = 1000;
17149a0bf528SMauro Carvalho Chehab 	while (n_empty == 1 && i) {
17159a0bf528SMauro Carvalho Chehab 		n_empty = dib8000_read_word(state, 1984)&0x1;
17169a0bf528SMauro Carvalho Chehab 		i--;
17179a0bf528SMauro Carvalho Chehab 		if (i == 0)
17188af16adfSMauro Carvalho Chehab 			dprintk("TunerITF: read busy (empty)\n");
17199a0bf528SMauro Carvalho Chehab 	}
17209a0bf528SMauro Carvalho Chehab 
17219a0bf528SMauro Carvalho Chehab 	read_word = dib8000_read_word(state, 1987);
17229a0bf528SMauro Carvalho Chehab 	msg[1].buf[0] = (read_word >> 8) & 0xff;
17239a0bf528SMauro Carvalho Chehab 	msg[1].buf[1] = (read_word) & 0xff;
17249a0bf528SMauro Carvalho Chehab 
17259a0bf528SMauro Carvalho Chehab 	return num;
17269a0bf528SMauro Carvalho Chehab }
17279a0bf528SMauro Carvalho Chehab 
17289a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
17299a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
17309a0bf528SMauro Carvalho Chehab {
17319a0bf528SMauro Carvalho Chehab 	if (map_addr_to_serpar_number(&msg[0]) == 0) {
17329a0bf528SMauro Carvalho Chehab 		if (num == 1) /* write */
17339a0bf528SMauro Carvalho Chehab 			return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
17349a0bf528SMauro Carvalho Chehab 		else /* read */
17359a0bf528SMauro Carvalho Chehab 			return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
17369a0bf528SMauro Carvalho Chehab 	}
17379a0bf528SMauro Carvalho Chehab 	return num;
17389a0bf528SMauro Carvalho Chehab }
17399a0bf528SMauro Carvalho Chehab 
17409a0bf528SMauro Carvalho Chehab static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
17419a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num, u16 apb_address)
17429a0bf528SMauro Carvalho Chehab {
17439a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
17449a0bf528SMauro Carvalho Chehab 	u16 word;
17459a0bf528SMauro Carvalho Chehab 
17469a0bf528SMauro Carvalho Chehab 	if (num == 1) {		/* write */
17479a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, apb_address,
17489a0bf528SMauro Carvalho Chehab 				((msg[0].buf[1] << 8) | (msg[0].buf[2])));
17499a0bf528SMauro Carvalho Chehab 	} else {
17509a0bf528SMauro Carvalho Chehab 		word = dib8000_read_word(state, apb_address);
17519a0bf528SMauro Carvalho Chehab 		msg[1].buf[0] = (word >> 8) & 0xff;
17529a0bf528SMauro Carvalho Chehab 		msg[1].buf[1] = (word) & 0xff;
17539a0bf528SMauro Carvalho Chehab 	}
17549a0bf528SMauro Carvalho Chehab 	return num;
17559a0bf528SMauro Carvalho Chehab }
17569a0bf528SMauro Carvalho Chehab 
17579a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
17589a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
17599a0bf528SMauro Carvalho Chehab {
17609a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
17619a0bf528SMauro Carvalho Chehab 	u16 apb_address = 0, word;
17629a0bf528SMauro Carvalho Chehab 	int i = 0;
17639a0bf528SMauro Carvalho Chehab 
17649a0bf528SMauro Carvalho Chehab 	switch (msg[0].buf[0]) {
17659a0bf528SMauro Carvalho Chehab 	case 0x12:
17669a0bf528SMauro Carvalho Chehab 			apb_address = 1920;
17679a0bf528SMauro Carvalho Chehab 			break;
17689a0bf528SMauro Carvalho Chehab 	case 0x14:
17699a0bf528SMauro Carvalho Chehab 			apb_address = 1921;
17709a0bf528SMauro Carvalho Chehab 			break;
17719a0bf528SMauro Carvalho Chehab 	case 0x24:
17729a0bf528SMauro Carvalho Chehab 			apb_address = 1922;
17739a0bf528SMauro Carvalho Chehab 			break;
17749a0bf528SMauro Carvalho Chehab 	case 0x1a:
17759a0bf528SMauro Carvalho Chehab 			apb_address = 1923;
17769a0bf528SMauro Carvalho Chehab 			break;
17779a0bf528SMauro Carvalho Chehab 	case 0x22:
17789a0bf528SMauro Carvalho Chehab 			apb_address = 1924;
17799a0bf528SMauro Carvalho Chehab 			break;
17809a0bf528SMauro Carvalho Chehab 	case 0x33:
17819a0bf528SMauro Carvalho Chehab 			apb_address = 1926;
17829a0bf528SMauro Carvalho Chehab 			break;
17839a0bf528SMauro Carvalho Chehab 	case 0x34:
17849a0bf528SMauro Carvalho Chehab 			apb_address = 1927;
17859a0bf528SMauro Carvalho Chehab 			break;
17869a0bf528SMauro Carvalho Chehab 	case 0x35:
17879a0bf528SMauro Carvalho Chehab 			apb_address = 1928;
17889a0bf528SMauro Carvalho Chehab 			break;
17899a0bf528SMauro Carvalho Chehab 	case 0x36:
17909a0bf528SMauro Carvalho Chehab 			apb_address = 1929;
17919a0bf528SMauro Carvalho Chehab 			break;
17929a0bf528SMauro Carvalho Chehab 	case 0x37:
17939a0bf528SMauro Carvalho Chehab 			apb_address = 1930;
17949a0bf528SMauro Carvalho Chehab 			break;
17959a0bf528SMauro Carvalho Chehab 	case 0x38:
17969a0bf528SMauro Carvalho Chehab 			apb_address = 1931;
17979a0bf528SMauro Carvalho Chehab 			break;
17989a0bf528SMauro Carvalho Chehab 	case 0x39:
17999a0bf528SMauro Carvalho Chehab 			apb_address = 1932;
18009a0bf528SMauro Carvalho Chehab 			break;
18019a0bf528SMauro Carvalho Chehab 	case 0x2a:
18029a0bf528SMauro Carvalho Chehab 			apb_address = 1935;
18039a0bf528SMauro Carvalho Chehab 			break;
18049a0bf528SMauro Carvalho Chehab 	case 0x2b:
18059a0bf528SMauro Carvalho Chehab 			apb_address = 1936;
18069a0bf528SMauro Carvalho Chehab 			break;
18079a0bf528SMauro Carvalho Chehab 	case 0x2c:
18089a0bf528SMauro Carvalho Chehab 			apb_address = 1937;
18099a0bf528SMauro Carvalho Chehab 			break;
18109a0bf528SMauro Carvalho Chehab 	case 0x2d:
18119a0bf528SMauro Carvalho Chehab 			apb_address = 1938;
18129a0bf528SMauro Carvalho Chehab 			break;
18139a0bf528SMauro Carvalho Chehab 	case 0x2e:
18149a0bf528SMauro Carvalho Chehab 			apb_address = 1939;
18159a0bf528SMauro Carvalho Chehab 			break;
18169a0bf528SMauro Carvalho Chehab 	case 0x2f:
18179a0bf528SMauro Carvalho Chehab 			apb_address = 1940;
18189a0bf528SMauro Carvalho Chehab 			break;
18199a0bf528SMauro Carvalho Chehab 	case 0x30:
18209a0bf528SMauro Carvalho Chehab 			apb_address = 1941;
18219a0bf528SMauro Carvalho Chehab 			break;
18229a0bf528SMauro Carvalho Chehab 	case 0x31:
18239a0bf528SMauro Carvalho Chehab 			apb_address = 1942;
18249a0bf528SMauro Carvalho Chehab 			break;
18259a0bf528SMauro Carvalho Chehab 	case 0x32:
18269a0bf528SMauro Carvalho Chehab 			apb_address = 1943;
18279a0bf528SMauro Carvalho Chehab 			break;
18289a0bf528SMauro Carvalho Chehab 	case 0x3e:
18299a0bf528SMauro Carvalho Chehab 			apb_address = 1944;
18309a0bf528SMauro Carvalho Chehab 			break;
18319a0bf528SMauro Carvalho Chehab 	case 0x3f:
18329a0bf528SMauro Carvalho Chehab 			apb_address = 1945;
18339a0bf528SMauro Carvalho Chehab 			break;
18349a0bf528SMauro Carvalho Chehab 	case 0x40:
18359a0bf528SMauro Carvalho Chehab 			apb_address = 1948;
18369a0bf528SMauro Carvalho Chehab 			break;
18379a0bf528SMauro Carvalho Chehab 	case 0x25:
18389a0bf528SMauro Carvalho Chehab 			apb_address = 936;
18399a0bf528SMauro Carvalho Chehab 			break;
18409a0bf528SMauro Carvalho Chehab 	case 0x26:
18419a0bf528SMauro Carvalho Chehab 			apb_address = 937;
18429a0bf528SMauro Carvalho Chehab 			break;
18439a0bf528SMauro Carvalho Chehab 	case 0x27:
18449a0bf528SMauro Carvalho Chehab 			apb_address = 938;
18459a0bf528SMauro Carvalho Chehab 			break;
18469a0bf528SMauro Carvalho Chehab 	case 0x28:
18479a0bf528SMauro Carvalho Chehab 			apb_address = 939;
18489a0bf528SMauro Carvalho Chehab 			break;
18499a0bf528SMauro Carvalho Chehab 	case 0x1d:
18509a0bf528SMauro Carvalho Chehab 			/* get sad sel request */
18519a0bf528SMauro Carvalho Chehab 			i = ((dib8000_read_word(state, 921) >> 12)&0x3);
18529a0bf528SMauro Carvalho Chehab 			word = dib8000_read_word(state, 924+i);
18539a0bf528SMauro Carvalho Chehab 			msg[1].buf[0] = (word >> 8) & 0xff;
18549a0bf528SMauro Carvalho Chehab 			msg[1].buf[1] = (word) & 0xff;
18559a0bf528SMauro Carvalho Chehab 			return num;
18569a0bf528SMauro Carvalho Chehab 	case 0x1f:
18579a0bf528SMauro Carvalho Chehab 			if (num == 1) {	/* write */
18589a0bf528SMauro Carvalho Chehab 				word = (u16) ((msg[0].buf[1] << 8) |
18599a0bf528SMauro Carvalho Chehab 						msg[0].buf[2]);
18609a0bf528SMauro Carvalho Chehab 				/* in the VGAMODE Sel are located on bit 0/1 */
18619a0bf528SMauro Carvalho Chehab 				word &= 0x3;
18629a0bf528SMauro Carvalho Chehab 				word = (dib8000_read_word(state, 921) &
18639a0bf528SMauro Carvalho Chehab 						~(3<<12)) | (word<<12);
18649a0bf528SMauro Carvalho Chehab 				/* Set the proper input */
18659a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, 921, word);
18669a0bf528SMauro Carvalho Chehab 				return num;
18679a0bf528SMauro Carvalho Chehab 			}
18689a0bf528SMauro Carvalho Chehab 	}
18699a0bf528SMauro Carvalho Chehab 
18709a0bf528SMauro Carvalho Chehab 	if (apb_address != 0) /* R/W acces via APB */
18719a0bf528SMauro Carvalho Chehab 		return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
18729a0bf528SMauro Carvalho Chehab 	else  /* R/W access via SERPAR  */
18739a0bf528SMauro Carvalho Chehab 		return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
18749a0bf528SMauro Carvalho Chehab 
18759a0bf528SMauro Carvalho Chehab 	return 0;
18769a0bf528SMauro Carvalho Chehab }
18779a0bf528SMauro Carvalho Chehab 
18789a0bf528SMauro Carvalho Chehab static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
18799a0bf528SMauro Carvalho Chehab {
18809a0bf528SMauro Carvalho Chehab 	return I2C_FUNC_I2C;
18819a0bf528SMauro Carvalho Chehab }
18829a0bf528SMauro Carvalho Chehab 
18839a0bf528SMauro Carvalho Chehab static struct i2c_algorithm dib8096p_tuner_xfer_algo = {
18849a0bf528SMauro Carvalho Chehab 	.master_xfer = dib8096p_tuner_xfer,
18859a0bf528SMauro Carvalho Chehab 	.functionality = dib8096p_i2c_func,
18869a0bf528SMauro Carvalho Chehab };
18879a0bf528SMauro Carvalho Chehab 
1888d44913c1SMauro Carvalho Chehab static struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
18899a0bf528SMauro Carvalho Chehab {
18909a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
18919a0bf528SMauro Carvalho Chehab 	return &st->dib8096p_tuner_adap;
18929a0bf528SMauro Carvalho Chehab }
18939a0bf528SMauro Carvalho Chehab 
1894d44913c1SMauro Carvalho Chehab static int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
18959a0bf528SMauro Carvalho Chehab {
18969a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
18979a0bf528SMauro Carvalho Chehab 	u16 en_cur_state;
18989a0bf528SMauro Carvalho Chehab 
18998af16adfSMauro Carvalho Chehab 	dprintk("sleep dib8096p: %d\n", onoff);
19009a0bf528SMauro Carvalho Chehab 
19019a0bf528SMauro Carvalho Chehab 	en_cur_state = dib8000_read_word(state, 1922);
19029a0bf528SMauro Carvalho Chehab 
19039a0bf528SMauro Carvalho Chehab 	/* LNAs and MIX are ON and therefore it is a valid configuration */
19049a0bf528SMauro Carvalho Chehab 	if (en_cur_state > 0xff)
19059a0bf528SMauro Carvalho Chehab 		state->tuner_enable = en_cur_state ;
19069a0bf528SMauro Carvalho Chehab 
19079a0bf528SMauro Carvalho Chehab 	if (onoff)
19089a0bf528SMauro Carvalho Chehab 		en_cur_state &= 0x00ff;
19099a0bf528SMauro Carvalho Chehab 	else {
19109a0bf528SMauro Carvalho Chehab 		if (state->tuner_enable != 0)
19119a0bf528SMauro Carvalho Chehab 			en_cur_state = state->tuner_enable;
19129a0bf528SMauro Carvalho Chehab 	}
19139a0bf528SMauro Carvalho Chehab 
19149a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1922, en_cur_state);
19159a0bf528SMauro Carvalho Chehab 
19169a0bf528SMauro Carvalho Chehab 	return 0;
19179a0bf528SMauro Carvalho Chehab }
19189a0bf528SMauro Carvalho Chehab 
19199a0bf528SMauro Carvalho Chehab static const s32 lut_1000ln_mant[] =
19209a0bf528SMauro Carvalho Chehab {
19219a0bf528SMauro Carvalho Chehab 	908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
19229a0bf528SMauro Carvalho Chehab };
19239a0bf528SMauro Carvalho Chehab 
1924d44913c1SMauro Carvalho Chehab static s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
19259a0bf528SMauro Carvalho Chehab {
19269a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
19279a0bf528SMauro Carvalho Chehab 	u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
19289a0bf528SMauro Carvalho Chehab 	s32 val;
19299a0bf528SMauro Carvalho Chehab 
19309a0bf528SMauro Carvalho Chehab 	val = dib8000_read32(state, 384);
19319a0bf528SMauro Carvalho Chehab 	if (mode) {
19329a0bf528SMauro Carvalho Chehab 		tmp_val = val;
19339a0bf528SMauro Carvalho Chehab 		while (tmp_val >>= 1)
19349a0bf528SMauro Carvalho Chehab 			exp++;
19359a0bf528SMauro Carvalho Chehab 		mant = (val * 1000 / (1<<exp));
19369a0bf528SMauro Carvalho Chehab 		ix = (u8)((mant-1000)/100); /* index of the LUT */
19379a0bf528SMauro Carvalho Chehab 		val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
19389a0bf528SMauro Carvalho Chehab 		val = (val*256)/1000;
19399a0bf528SMauro Carvalho Chehab 	}
19409a0bf528SMauro Carvalho Chehab 	return val;
19419a0bf528SMauro Carvalho Chehab }
19429a0bf528SMauro Carvalho Chehab 
1943d44913c1SMauro Carvalho Chehab static int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
19449a0bf528SMauro Carvalho Chehab {
19459a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
19469a0bf528SMauro Carvalho Chehab 	int val = 0;
19479a0bf528SMauro Carvalho Chehab 
19489a0bf528SMauro Carvalho Chehab 	switch (IQ) {
19499a0bf528SMauro Carvalho Chehab 	case 1:
19509a0bf528SMauro Carvalho Chehab 			val = dib8000_read_word(state, 403);
19519a0bf528SMauro Carvalho Chehab 			break;
19529a0bf528SMauro Carvalho Chehab 	case 0:
19539a0bf528SMauro Carvalho Chehab 			val = dib8000_read_word(state, 404);
19549a0bf528SMauro Carvalho Chehab 			break;
19559a0bf528SMauro Carvalho Chehab 	}
19569a0bf528SMauro Carvalho Chehab 	if (val  & 0x200)
19579a0bf528SMauro Carvalho Chehab 		val -= 1024;
19589a0bf528SMauro Carvalho Chehab 
19599a0bf528SMauro Carvalho Chehab 	return val;
19609a0bf528SMauro Carvalho Chehab }
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));
19688af16adfSMauro Carvalho Chehab 	dprintk("Updated timing frequency: %d (default: %d)\n", state->timf, state->timf_default);
19699a0bf528SMauro Carvalho Chehab }
19709a0bf528SMauro Carvalho Chehab 
1971d44913c1SMauro Carvalho Chehab static 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 
19909a0bf528SMauro Carvalho Chehab static const u16 adc_target_16dB[11] = {
1991a768f90eSMauro Carvalho Chehab 	7250, 7238, 7264, 7309, 7338, 7382, 7427, 7456, 7500, 7544, 7574
19929a0bf528SMauro Carvalho Chehab };
1993a768f90eSMauro Carvalho Chehab 
19949a0bf528SMauro Carvalho Chehab static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
19959a0bf528SMauro Carvalho Chehab 
1996173a64cbSPatrick Boettcher static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
19979a0bf528SMauro Carvalho Chehab {
1998173a64cbSPatrick Boettcher 	u8  cr, constellation, time_intlv;
1999c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
20009a0bf528SMauro Carvalho Chehab 
2001c82056d0SMauro Carvalho Chehab 	switch (c->layer[layer_index].modulation) {
20029a0bf528SMauro Carvalho Chehab 	case DQPSK:
20039a0bf528SMauro Carvalho Chehab 			constellation = 0;
20049a0bf528SMauro Carvalho Chehab 			break;
20059a0bf528SMauro Carvalho Chehab 	case  QPSK:
20069a0bf528SMauro Carvalho Chehab 			constellation = 1;
20079a0bf528SMauro Carvalho Chehab 			break;
20089a0bf528SMauro Carvalho Chehab 	case QAM_16:
20099a0bf528SMauro Carvalho Chehab 			constellation = 2;
20109a0bf528SMauro Carvalho Chehab 			break;
20119a0bf528SMauro Carvalho Chehab 	case QAM_64:
20129a0bf528SMauro Carvalho Chehab 	default:
20139a0bf528SMauro Carvalho Chehab 			constellation = 3;
20149a0bf528SMauro Carvalho Chehab 			break;
20159a0bf528SMauro Carvalho Chehab 	}
20169a0bf528SMauro Carvalho Chehab 
2017c82056d0SMauro Carvalho Chehab 	switch (c->layer[layer_index].fec) {
20189a0bf528SMauro Carvalho Chehab 	case FEC_1_2:
2019173a64cbSPatrick Boettcher 			cr = 1;
20209a0bf528SMauro Carvalho Chehab 			break;
20219a0bf528SMauro Carvalho Chehab 	case FEC_2_3:
2022173a64cbSPatrick Boettcher 			cr = 2;
20239a0bf528SMauro Carvalho Chehab 			break;
20249a0bf528SMauro Carvalho Chehab 	case FEC_3_4:
2025173a64cbSPatrick Boettcher 			cr = 3;
20269a0bf528SMauro Carvalho Chehab 			break;
20279a0bf528SMauro Carvalho Chehab 	case FEC_5_6:
2028173a64cbSPatrick Boettcher 			cr = 5;
20299a0bf528SMauro Carvalho Chehab 			break;
20309a0bf528SMauro Carvalho Chehab 	case FEC_7_8:
20319a0bf528SMauro Carvalho Chehab 	default:
2032173a64cbSPatrick Boettcher 			cr = 7;
20339a0bf528SMauro Carvalho Chehab 			break;
20349a0bf528SMauro Carvalho Chehab 	}
20359a0bf528SMauro Carvalho Chehab 
203634ba2e65SMauro Carvalho Chehab 	time_intlv = fls(c->layer[layer_index].interleaving);
203734ba2e65SMauro Carvalho Chehab 	if (time_intlv > 3 && !(time_intlv == 4 && c->isdbt_sb_mode == 1))
2038173a64cbSPatrick Boettcher 		time_intlv = 0;
2039173a64cbSPatrick Boettcher 
2040c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
2041c82056d0SMauro Carvalho Chehab 	if (c->layer[layer_index].segment_count > 0) {
20429a0bf528SMauro Carvalho Chehab 		switch (max_constellation) {
20439a0bf528SMauro Carvalho Chehab 		case DQPSK:
20449a0bf528SMauro Carvalho Chehab 		case QPSK:
2045c82056d0SMauro Carvalho Chehab 				if (c->layer[layer_index].modulation == QAM_16 || c->layer[layer_index].modulation == QAM_64)
2046c82056d0SMauro Carvalho Chehab 					max_constellation = c->layer[layer_index].modulation;
20479a0bf528SMauro Carvalho Chehab 				break;
20489a0bf528SMauro Carvalho Chehab 		case QAM_16:
2049c82056d0SMauro Carvalho Chehab 				if (c->layer[layer_index].modulation == QAM_64)
2050c82056d0SMauro Carvalho Chehab 					max_constellation = c->layer[layer_index].modulation;
20519a0bf528SMauro Carvalho Chehab 				break;
20529a0bf528SMauro Carvalho Chehab 		}
20539a0bf528SMauro Carvalho Chehab 	}
2054173a64cbSPatrick Boettcher 
2055173a64cbSPatrick Boettcher 	return  max_constellation;
20569a0bf528SMauro Carvalho Chehab }
20579a0bf528SMauro Carvalho Chehab 
2058173a64cbSPatrick Boettcher static const u16 adp_Q64[4] = {0x0148, 0xfff0, 0x00a4, 0xfff8}; /* P_adp_regul_cnt 0.04, P_adp_noise_cnt -0.002, P_adp_regul_ext 0.02, P_adp_noise_ext -0.001 */
2059173a64cbSPatrick Boettcher static const u16 adp_Q16[4] = {0x023d, 0xffdf, 0x00a4, 0xfff0}; /* P_adp_regul_cnt 0.07, P_adp_noise_cnt -0.004, P_adp_regul_ext 0.02, P_adp_noise_ext -0.002 */
2060173a64cbSPatrick Boettcher static const u16 adp_Qdefault[4] = {0x099a, 0xffae, 0x0333, 0xfff8}; /* P_adp_regul_cnt 0.3,  P_adp_noise_cnt -0.01,  P_adp_regul_ext 0.1,  P_adp_noise_ext -0.002 */
2061173a64cbSPatrick Boettcher static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation)
2062173a64cbSPatrick Boettcher {
2063173a64cbSPatrick Boettcher 	u16 i, ana_gain = 0;
2064173a64cbSPatrick Boettcher 	const u16 *adp;
20659a0bf528SMauro Carvalho Chehab 
2066173a64cbSPatrick Boettcher 	/* channel estimation fine configuration */
2067173a64cbSPatrick Boettcher 	switch (max_constellation) {
2068173a64cbSPatrick Boettcher 	case QAM_64:
2069173a64cbSPatrick Boettcher 			ana_gain = 0x7;
2070173a64cbSPatrick Boettcher 			adp = &adp_Q64[0];
2071173a64cbSPatrick Boettcher 			break;
2072173a64cbSPatrick Boettcher 	case QAM_16:
2073173a64cbSPatrick Boettcher 			ana_gain = 0x7;
2074173a64cbSPatrick Boettcher 			adp = &adp_Q16[0];
2075173a64cbSPatrick Boettcher 			break;
2076173a64cbSPatrick Boettcher 	default:
2077173a64cbSPatrick Boettcher 			ana_gain = 0;
2078173a64cbSPatrick Boettcher 			adp = &adp_Qdefault[0];
2079173a64cbSPatrick Boettcher 			break;
20809a0bf528SMauro Carvalho Chehab 	}
20819a0bf528SMauro Carvalho Chehab 
2082173a64cbSPatrick Boettcher 	for (i = 0; i < 4; i++)
2083173a64cbSPatrick Boettcher 		dib8000_write_word(state, 215 + i, adp[i]);
20849a0bf528SMauro Carvalho Chehab 
2085173a64cbSPatrick Boettcher 	return ana_gain;
2086173a64cbSPatrick Boettcher }
20879a0bf528SMauro Carvalho Chehab 
2088173a64cbSPatrick Boettcher static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain)
2089173a64cbSPatrick Boettcher {
2090173a64cbSPatrick Boettcher 	u16 i;
20919a0bf528SMauro Carvalho Chehab 
2092173a64cbSPatrick Boettcher 	dib8000_write_word(state, 116, ana_gain);
20939a0bf528SMauro Carvalho Chehab 
2094173a64cbSPatrick Boettcher 	/* update ADC target depending on ana_gain */
2095173a64cbSPatrick Boettcher 	if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */
2096173a64cbSPatrick Boettcher 		for (i = 0; i < 10; i++)
2097173a64cbSPatrick Boettcher 			dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
2098173a64cbSPatrick Boettcher 	} else { /* set -22dB ADC target for ana_gain=0 */
2099173a64cbSPatrick Boettcher 		for (i = 0; i < 10; i++)
2100173a64cbSPatrick Boettcher 			dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
2101173a64cbSPatrick Boettcher 	}
2102173a64cbSPatrick Boettcher }
21039a0bf528SMauro Carvalho Chehab 
2104173a64cbSPatrick Boettcher static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
2105173a64cbSPatrick Boettcher {
2106173a64cbSPatrick Boettcher 	u16 mode = 0;
21079a0bf528SMauro Carvalho Chehab 
2108173a64cbSPatrick Boettcher 	if (state->isdbt_cfg_loaded == 0)
2109173a64cbSPatrick Boettcher 		for (mode = 0; mode < 24; mode++)
2110173a64cbSPatrick Boettcher 			dib8000_write_word(state, 117 + mode, ana_fe[mode]);
2111173a64cbSPatrick Boettcher }
21129a0bf528SMauro Carvalho Chehab 
2113173a64cbSPatrick Boettcher static const u16 lut_prbs_2k[14] = {
2114173a64cbSPatrick Boettcher 	0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213
2115173a64cbSPatrick Boettcher };
2116173a64cbSPatrick Boettcher static const u16 lut_prbs_4k[14] = {
2117173a64cbSPatrick Boettcher 	0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E
2118173a64cbSPatrick Boettcher };
2119173a64cbSPatrick Boettcher static const u16 lut_prbs_8k[14] = {
2120173a64cbSPatrick Boettcher 	0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684
2121173a64cbSPatrick Boettcher };
2122173a64cbSPatrick Boettcher 
2123173a64cbSPatrick Boettcher static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
2124173a64cbSPatrick Boettcher {
2125173a64cbSPatrick Boettcher 	int sub_channel_prbs_group = 0;
2126173a64cbSPatrick Boettcher 
2127173a64cbSPatrick Boettcher 	sub_channel_prbs_group = (subchannel / 3) + 1;
21288af16adfSMauro Carvalho Chehab 	dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x\n", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]);
2129173a64cbSPatrick Boettcher 
21309a0bf528SMauro Carvalho Chehab 	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
21319a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
2132173a64cbSPatrick Boettcher 			return lut_prbs_2k[sub_channel_prbs_group];
21339a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
2134173a64cbSPatrick Boettcher 			return lut_prbs_4k[sub_channel_prbs_group];
21359a0bf528SMauro Carvalho Chehab 	default:
2136173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2137173a64cbSPatrick Boettcher 			return lut_prbs_8k[sub_channel_prbs_group];
21389a0bf528SMauro Carvalho Chehab 	}
21399a0bf528SMauro Carvalho Chehab }
21409a0bf528SMauro Carvalho Chehab 
2141173a64cbSPatrick Boettcher static void dib8000_set_13seg_channel(struct dib8000_state *state)
2142173a64cbSPatrick Boettcher {
2143173a64cbSPatrick Boettcher 	u16 i;
2144173a64cbSPatrick Boettcher 	u16 coff_pow = 0x2800;
21459a0bf528SMauro Carvalho Chehab 
2146173a64cbSPatrick Boettcher 	state->seg_mask = 0x1fff; /* All 13 segments enabled */
21479a0bf528SMauro Carvalho Chehab 
2148173a64cbSPatrick Boettcher 	/* ---- COFF ---- Carloff, the most robust --- */
2149173a64cbSPatrick Boettcher 	if (state->isdbt_cfg_loaded == 0) {  /* if not Sound Broadcasting mode : put default values for 13 segments */
21509a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 180, (16 << 6) | 9);
21519a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
21529a0bf528SMauro Carvalho Chehab 		coff_pow = 0x2800;
21539a0bf528SMauro Carvalho Chehab 		for (i = 0; i < 6; i++)
21549a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 181+i, coff_pow);
21559a0bf528SMauro Carvalho Chehab 
2156173a64cbSPatrick Boettcher 		/* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */
2157173a64cbSPatrick Boettcher 		/* P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1 */
21589a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
21599a0bf528SMauro Carvalho Chehab 
2160173a64cbSPatrick Boettcher 		/* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */
21619a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
2162173a64cbSPatrick Boettcher 		/* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */
21639a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
21649a0bf528SMauro Carvalho Chehab 
2165173a64cbSPatrick Boettcher 		dib8000_write_word(state, 228, 0);  /* default value */
2166173a64cbSPatrick Boettcher 		dib8000_write_word(state, 265, 31); /* default value */
2167173a64cbSPatrick Boettcher 		dib8000_write_word(state, 205, 0x200f); /* init value */
2168173a64cbSPatrick Boettcher 	}
2169173a64cbSPatrick Boettcher 
2170173a64cbSPatrick Boettcher 	/*
2171173a64cbSPatrick Boettcher 	 * make the cpil_coff_lock more robust but slower p_coff_winlen
21729a0bf528SMauro Carvalho Chehab 	 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
21739a0bf528SMauro Carvalho Chehab 	 */
21749a0bf528SMauro Carvalho Chehab 
2175173a64cbSPatrick Boettcher 	if (state->cfg.pll->ifreq == 0)
2176173a64cbSPatrick Boettcher 		dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
21779a0bf528SMauro Carvalho Chehab 
2178173a64cbSPatrick Boettcher 	dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg);
2179173a64cbSPatrick Boettcher }
21809a0bf528SMauro Carvalho Chehab 
2181173a64cbSPatrick Boettcher static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs)
2182173a64cbSPatrick Boettcher {
2183173a64cbSPatrick Boettcher 	u16 reg_1;
21849a0bf528SMauro Carvalho Chehab 
2185173a64cbSPatrick Boettcher 	reg_1 = dib8000_read_word(state, 1);
2186173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */
2187173a64cbSPatrick Boettcher }
21889a0bf528SMauro Carvalho Chehab 
2189173a64cbSPatrick Boettcher static void dib8000_small_fine_tune(struct dib8000_state *state)
2190173a64cbSPatrick Boettcher {
2191173a64cbSPatrick Boettcher 	u16 i;
2192173a64cbSPatrick Boettcher 	const s16 *ncoeff;
2193c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
21949a0bf528SMauro Carvalho Chehab 
2195173a64cbSPatrick Boettcher 	dib8000_write_word(state, 352, state->seg_diff_mask);
2196173a64cbSPatrick Boettcher 	dib8000_write_word(state, 353, state->seg_mask);
21979a0bf528SMauro Carvalho Chehab 
2198173a64cbSPatrick Boettcher 	/* P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 */
2199c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 351, (c->isdbt_sb_mode << 9) | (c->isdbt_sb_mode << 8) | (13 << 4) | 5);
2200173a64cbSPatrick Boettcher 
2201c82056d0SMauro Carvalho Chehab 	if (c->isdbt_sb_mode) {
2202173a64cbSPatrick Boettcher 		/* ---- SMALL ---- */
2203c82056d0SMauro Carvalho Chehab 		switch (c->transmission_mode) {
2204173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_2K:
2205c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2206c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2207173a64cbSPatrick Boettcher 						ncoeff = coeff_2k_sb_1seg_dqpsk;
2208173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2209173a64cbSPatrick Boettcher 						ncoeff = coeff_2k_sb_1seg;
2210173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2211c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2212c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2213173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
2214173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2215173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg_0dqpsk;
2216173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2217c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2218173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg_1dqpsk;
2219173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2220173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg;
2221173a64cbSPatrick Boettcher 					}
2222173a64cbSPatrick Boettcher 				}
22239a0bf528SMauro Carvalho Chehab 				break;
22249a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_4K:
2225c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2226c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2227173a64cbSPatrick Boettcher 						ncoeff = coeff_4k_sb_1seg_dqpsk;
2228173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2229173a64cbSPatrick Boettcher 						ncoeff = coeff_4k_sb_1seg;
2230173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2231c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2232c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2233173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
2234173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2235173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_0dqpsk;
2236173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2237c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2238173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_1dqpsk;
2239173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2240173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg;
2241173a64cbSPatrick Boettcher 					}
2242173a64cbSPatrick Boettcher 				}
22439a0bf528SMauro Carvalho Chehab 				break;
2244173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_AUTO:
2245173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_8K:
22469a0bf528SMauro Carvalho Chehab 		default:
2247c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2248c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2249173a64cbSPatrick Boettcher 						ncoeff = coeff_8k_sb_1seg_dqpsk;
2250173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2251173a64cbSPatrick Boettcher 						ncoeff = coeff_8k_sb_1seg;
2252173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2253c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2254c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2255173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
2256173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2257173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_0dqpsk;
2258173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2259c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2260173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_1dqpsk;
2261173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2262173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg;
2263173a64cbSPatrick Boettcher 					}
2264173a64cbSPatrick Boettcher 				}
22659a0bf528SMauro Carvalho Chehab 				break;
22669a0bf528SMauro Carvalho Chehab 		}
2267173a64cbSPatrick Boettcher 
2268173a64cbSPatrick Boettcher 		for (i = 0; i < 8; i++)
2269173a64cbSPatrick Boettcher 			dib8000_write_word(state, 343 + i, ncoeff[i]);
2270173a64cbSPatrick Boettcher 	}
2271173a64cbSPatrick Boettcher }
2272173a64cbSPatrick Boettcher 
2273173a64cbSPatrick Boettcher static const u16 coff_thres_1seg[3] = {300, 150, 80};
2274173a64cbSPatrick Boettcher static const u16 coff_thres_3seg[3] = {350, 300, 250};
2275173a64cbSPatrick Boettcher static void dib8000_set_sb_channel(struct dib8000_state *state)
2276173a64cbSPatrick Boettcher {
2277c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2278173a64cbSPatrick Boettcher 	const u16 *coff;
2279173a64cbSPatrick Boettcher 	u16 i;
2280173a64cbSPatrick Boettcher 
2281c82056d0SMauro Carvalho Chehab 	if (c->transmission_mode == TRANSMISSION_MODE_2K || c->transmission_mode == TRANSMISSION_MODE_4K) {
2282173a64cbSPatrick Boettcher 		dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */
2283173a64cbSPatrick Boettcher 		dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */
2284173a64cbSPatrick Boettcher 	} else {
2285173a64cbSPatrick Boettcher 		dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */
2286173a64cbSPatrick Boettcher 		dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */
2287173a64cbSPatrick Boettcher 	}
2288173a64cbSPatrick Boettcher 
2289c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 1) /* 3-segments */
2290173a64cbSPatrick Boettcher 		state->seg_mask = 0x00E0;
2291173a64cbSPatrick Boettcher 	else /* 1-segment */
2292173a64cbSPatrick Boettcher 		state->seg_mask = 0x0040;
2293173a64cbSPatrick Boettcher 
2294173a64cbSPatrick Boettcher 	dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2295173a64cbSPatrick Boettcher 
2296173a64cbSPatrick Boettcher 	/* ---- COFF ---- Carloff, the most robust --- */
2297173a64cbSPatrick Boettcher 	/* P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64, P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1 */
2298c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 187, (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~c->isdbt_partial_reception & 1) << 2) | 0x3);
2299173a64cbSPatrick Boettcher 
2300173a64cbSPatrick Boettcher 	dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */
2301173a64cbSPatrick Boettcher 	dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));/* P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 */
2302173a64cbSPatrick Boettcher 
2303173a64cbSPatrick Boettcher 	/* Sound Broadcasting mode 1 seg */
2304c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 0) {
2305173a64cbSPatrick Boettcher 		/* P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width = (P_mode == 3) , P_coff_one_seg_sym = (P_mode-1) */
2306173a64cbSPatrick Boettcher 		if (state->mode == 3)
2307173a64cbSPatrick Boettcher 			dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14));
23089a0bf528SMauro Carvalho Chehab 		else
2309173a64cbSPatrick Boettcher 			dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14));
2310173a64cbSPatrick Boettcher 
2311173a64cbSPatrick Boettcher 		/* P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4 */
2312173a64cbSPatrick Boettcher 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
2313173a64cbSPatrick Boettcher 		coff = &coff_thres_1seg[0];
2314173a64cbSPatrick Boettcher 	} else {   /* Sound Broadcasting mode 3 seg */
2315173a64cbSPatrick Boettcher 		dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
2316173a64cbSPatrick Boettcher 		/* P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4 */
2317173a64cbSPatrick Boettcher 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
2318173a64cbSPatrick Boettcher 		coff = &coff_thres_3seg[0];
2319173a64cbSPatrick Boettcher 	}
2320173a64cbSPatrick Boettcher 
2321173a64cbSPatrick Boettcher 	dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */
2322173a64cbSPatrick Boettcher 	dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */
2323173a64cbSPatrick Boettcher 
2324c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 0 && c->transmission_mode == TRANSMISSION_MODE_2K)
2325173a64cbSPatrick Boettcher 		dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */
2326173a64cbSPatrick Boettcher 
2327173a64cbSPatrick Boettcher 	/* Write COFF thres */
2328173a64cbSPatrick Boettcher 	for (i = 0 ; i < 3; i++) {
2329173a64cbSPatrick Boettcher 		dib8000_write_word(state, 181+i, coff[i]);
2330173a64cbSPatrick Boettcher 		dib8000_write_word(state, 184+i, coff[i]);
2331173a64cbSPatrick Boettcher 	}
2332173a64cbSPatrick Boettcher 
2333173a64cbSPatrick Boettcher 	/*
2334173a64cbSPatrick Boettcher 	 * make the cpil_coff_lock more robust but slower p_coff_winlen
2335173a64cbSPatrick Boettcher 	 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2336173a64cbSPatrick Boettcher 	 */
2337173a64cbSPatrick Boettcher 
2338173a64cbSPatrick Boettcher 	dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */
2339173a64cbSPatrick Boettcher 
2340c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 0)
2341173a64cbSPatrick Boettcher 		dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */
2342173a64cbSPatrick Boettcher 	else
2343173a64cbSPatrick Boettcher 		dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2344173a64cbSPatrick Boettcher }
2345173a64cbSPatrick Boettcher 
2346173a64cbSPatrick Boettcher static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
2347173a64cbSPatrick Boettcher {
2348173a64cbSPatrick Boettcher 	u16 p_cfr_left_edge  = 0, p_cfr_right_edge = 0;
2349173a64cbSPatrick Boettcher 	u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ;
2350173a64cbSPatrick Boettcher 	u16 max_constellation = DQPSK;
2351173a64cbSPatrick Boettcher 	int init_prbs;
2352c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2353173a64cbSPatrick Boettcher 
2354dde8e115SMauro Carvalho Chehab 	if (autosearching)
2355dde8e115SMauro Carvalho Chehab 		c->isdbt_partial_reception = 1;
2356dde8e115SMauro Carvalho Chehab 
2357173a64cbSPatrick Boettcher 	/* P_mode */
2358173a64cbSPatrick Boettcher 	dib8000_write_word(state, 10, (seq << 4));
2359173a64cbSPatrick Boettcher 
2360173a64cbSPatrick Boettcher 	/* init mode */
2361173a64cbSPatrick Boettcher 	state->mode = fft_to_mode(state);
2362173a64cbSPatrick Boettcher 
2363173a64cbSPatrick Boettcher 	/* set guard */
2364173a64cbSPatrick Boettcher 	tmp = dib8000_read_word(state, 1);
2365c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3));
2366173a64cbSPatrick Boettcher 
2367c82056d0SMauro 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));
2368173a64cbSPatrick Boettcher 
2369173a64cbSPatrick Boettcher 	/* signal optimization parameter */
2370c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception) {
2371c82056d0SMauro Carvalho Chehab 		state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0];
2372173a64cbSPatrick Boettcher 		for (i = 1; i < 3; i++)
2373c82056d0SMauro Carvalho Chehab 			nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
2374173a64cbSPatrick Boettcher 		for (i = 0; i < nbseg_diff; i++)
2375173a64cbSPatrick Boettcher 			state->seg_diff_mask |= 1 << permu_seg[i+1];
2376173a64cbSPatrick Boettcher 	} else {
2377173a64cbSPatrick Boettcher 		for (i = 0; i < 3; i++)
2378c82056d0SMauro Carvalho Chehab 			nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
2379173a64cbSPatrick Boettcher 		for (i = 0; i < nbseg_diff; i++)
2380173a64cbSPatrick Boettcher 			state->seg_diff_mask |= 1 << permu_seg[i];
2381173a64cbSPatrick Boettcher 	}
2382173a64cbSPatrick Boettcher 
2383173a64cbSPatrick Boettcher 	if (state->seg_diff_mask)
2384173a64cbSPatrick Boettcher 		dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2385173a64cbSPatrick Boettcher 	else
2386173a64cbSPatrick Boettcher 		dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */
2387173a64cbSPatrick Boettcher 
2388173a64cbSPatrick Boettcher 	for (i = 0; i < 3; i++)
2389173a64cbSPatrick Boettcher 		max_constellation = dib8000_set_layer(state, i, max_constellation);
2390173a64cbSPatrick Boettcher 	if (autosearching == 0) {
2391c82056d0SMauro Carvalho Chehab 		state->layer_b_nb_seg = c->layer[1].segment_count;
2392c82056d0SMauro Carvalho Chehab 		state->layer_c_nb_seg = c->layer[2].segment_count;
2393173a64cbSPatrick Boettcher 	}
2394173a64cbSPatrick Boettcher 
2395173a64cbSPatrick Boettcher 	/* WRITE: Mode & Diff mask */
2396173a64cbSPatrick Boettcher 	dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask);
2397173a64cbSPatrick Boettcher 
2398173a64cbSPatrick Boettcher 	state->differential_constellation = (state->seg_diff_mask != 0);
23999a0bf528SMauro Carvalho Chehab 
24009a0bf528SMauro Carvalho Chehab 	/* channel estimation fine configuration */
2401173a64cbSPatrick Boettcher 	ana_gain = dib8000_adp_fine_tune(state, max_constellation);
24029a0bf528SMauro Carvalho Chehab 
2403173a64cbSPatrick Boettcher 	/* update ana_gain depending on max constellation */
2404173a64cbSPatrick Boettcher 	dib8000_update_ana_gain(state, ana_gain);
24059a0bf528SMauro Carvalho Chehab 
2406173a64cbSPatrick Boettcher 	/* ---- ANA_FE ---- */
2407c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception) /* 3-segments */
2408173a64cbSPatrick Boettcher 		dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg);
2409173a64cbSPatrick Boettcher 	else
2410173a64cbSPatrick Boettcher 		dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */
2411173a64cbSPatrick Boettcher 
2412173a64cbSPatrick Boettcher 	/* TSB or ISDBT ? apply it now */
2413c82056d0SMauro Carvalho Chehab 	if (c->isdbt_sb_mode) {
2414173a64cbSPatrick Boettcher 		dib8000_set_sb_channel(state);
2415746f7ae0SMauro Carvalho Chehab 		if (c->isdbt_sb_subchannel < 14)
2416c82056d0SMauro Carvalho Chehab 			init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel);
2417173a64cbSPatrick Boettcher 		else
2418173a64cbSPatrick Boettcher 			init_prbs = 0;
2419173a64cbSPatrick Boettcher 	} else {
2420173a64cbSPatrick Boettcher 		dib8000_set_13seg_channel(state);
2421173a64cbSPatrick Boettcher 		init_prbs = 0xfff;
2422173a64cbSPatrick Boettcher 	}
24239a0bf528SMauro Carvalho Chehab 
2424173a64cbSPatrick Boettcher 	/* SMALL */
2425173a64cbSPatrick Boettcher 	dib8000_small_fine_tune(state);
24269a0bf528SMauro Carvalho Chehab 
2427173a64cbSPatrick Boettcher 	dib8000_set_subchannel_prbs(state, init_prbs);
2428173a64cbSPatrick Boettcher 
2429173a64cbSPatrick Boettcher 	/* ---- CHAN_BLK ---- */
24309a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 13; i++) {
2431173a64cbSPatrick Boettcher 		if ((((~state->seg_diff_mask) >> i) & 1) == 1) {
2432173a64cbSPatrick Boettcher 			p_cfr_left_edge  += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0));
2433173a64cbSPatrick Boettcher 			p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0));
24349a0bf528SMauro Carvalho Chehab 		}
24359a0bf528SMauro Carvalho Chehab 	}
2436173a64cbSPatrick Boettcher 	dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */
2437173a64cbSPatrick Boettcher 	dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */
2438173a64cbSPatrick Boettcher 	/* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */
24399a0bf528SMauro Carvalho Chehab 
2440173a64cbSPatrick Boettcher 	dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */
2441173a64cbSPatrick Boettcher 	dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */
2442173a64cbSPatrick Boettcher 	dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */
2443173a64cbSPatrick Boettcher 
2444173a64cbSPatrick Boettcher 	if (!autosearching)
2445173a64cbSPatrick Boettcher 		dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
2446173a64cbSPatrick Boettcher 	else
2447173a64cbSPatrick Boettcher 		dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */
2448173a64cbSPatrick Boettcher 
2449173a64cbSPatrick Boettcher 	dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */
2450173a64cbSPatrick Boettcher 	dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */
2451173a64cbSPatrick Boettcher 
2452173a64cbSPatrick Boettcher 	dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2453173a64cbSPatrick Boettcher 
2454173a64cbSPatrick Boettcher 	/* ---- TMCC ---- */
24559a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 3; i++)
2456c82056d0SMauro Carvalho Chehab 		tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ;
2457173a64cbSPatrick Boettcher 
2458173a64cbSPatrick Boettcher 	/* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */
2459173a64cbSPatrick Boettcher 	/* Threshold is set at 1/4 of max power. */
24609a0bf528SMauro Carvalho Chehab 	tmcc_pow *= (1 << (9-2));
2461173a64cbSPatrick Boettcher 	dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */
2462173a64cbSPatrick Boettcher 	dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */
2463173a64cbSPatrick Boettcher 	dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */
2464173a64cbSPatrick Boettcher 	/*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */
24659a0bf528SMauro Carvalho Chehab 
2466173a64cbSPatrick Boettcher 	/* ---- PHA3 ---- */
24679a0bf528SMauro Carvalho Chehab 	if (state->isdbt_cfg_loaded == 0)
24689a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */
24699a0bf528SMauro Carvalho Chehab 
24709a0bf528SMauro Carvalho Chehab 	state->isdbt_cfg_loaded = 0;
2471173a64cbSPatrick Boettcher }
24729a0bf528SMauro Carvalho Chehab 
24736f7ee06fSMauro Carvalho Chehab static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal,
24746f7ee06fSMauro Carvalho Chehab 			     u32 wait0_ms, u32 wait1_ms, u32 wait2_ms)
2475173a64cbSPatrick Boettcher {
247613122f98SMauro Carvalho Chehab 	u32 value = 0;	/* P_search_end0 wait time */
2477173a64cbSPatrick Boettcher 	u16 reg = 11;	/* P_search_end0 start addr */
2478173a64cbSPatrick Boettcher 
2479173a64cbSPatrick Boettcher 	for (reg = 11; reg < 16; reg += 2) {
2480173a64cbSPatrick Boettcher 		if (reg == 11) {
2481173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
248213122f98SMauro Carvalho Chehab 				value = internal * wait1_ms;
2483173a64cbSPatrick Boettcher 			else
248413122f98SMauro Carvalho Chehab 				value = internal * wait0_ms;
2485173a64cbSPatrick Boettcher 		} else if (reg == 13)
248613122f98SMauro Carvalho Chehab 			value = internal * wait1_ms;
2487173a64cbSPatrick Boettcher 		else if (reg == 15)
248813122f98SMauro Carvalho Chehab 			value = internal * wait2_ms;
2489173a64cbSPatrick Boettcher 		dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff));
2490173a64cbSPatrick Boettcher 		dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff));
2491173a64cbSPatrick Boettcher 	}
2492173a64cbSPatrick Boettcher 	return value;
24939a0bf528SMauro Carvalho Chehab }
24949a0bf528SMauro Carvalho Chehab 
24959a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_start(struct dvb_frontend *fe)
24969a0bf528SMauro Carvalho Chehab {
24979a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
2498c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2499173a64cbSPatrick Boettcher 	u8 slist = 0;
2500173a64cbSPatrick Boettcher 	u32 value, internal = state->cfg.pll->internal;
25019a0bf528SMauro Carvalho Chehab 
2502173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
2503173a64cbSPatrick Boettcher 		internal = dib8000_read32(state, 23) / 1000;
25049a0bf528SMauro Carvalho Chehab 
2505d67350f8SOlivier Grenie 	if ((state->revision >= 0x8002) &&
2506d67350f8SOlivier Grenie 	    (state->autosearch_state == AS_SEARCHING_FFT)) {
2507173a64cbSPatrick Boettcher 		dib8000_write_word(state,  37, 0x0065); /* P_ctrl_pha_off_max default values */
2508173a64cbSPatrick Boettcher 		dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
2509173a64cbSPatrick Boettcher 
2510173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */
2511173a64cbSPatrick Boettcher 		dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */
2512173a64cbSPatrick Boettcher 		dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */
2513173a64cbSPatrick Boettcher 		dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */
2514173a64cbSPatrick Boettcher 		dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */
2515173a64cbSPatrick Boettcher 		dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */
2516173a64cbSPatrick Boettcher 
2517173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2518173a64cbSPatrick Boettcher 			value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2519173a64cbSPatrick Boettcher 		else
2520173a64cbSPatrick Boettcher 			value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2521173a64cbSPatrick Boettcher 
2522173a64cbSPatrick Boettcher 		dib8000_write_word(state, 17, 0);
2523173a64cbSPatrick Boettcher 		dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */
2524173a64cbSPatrick Boettcher 		dib8000_write_word(state, 19, 0);
2525173a64cbSPatrick Boettcher 		dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */
2526173a64cbSPatrick Boettcher 		dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */
2527173a64cbSPatrick Boettcher 		dib8000_write_word(state, 22, value & 0xffff);
2528173a64cbSPatrick Boettcher 
2529173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2530173a64cbSPatrick Boettcher 			dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */
2531173a64cbSPatrick Boettcher 		else
2532173a64cbSPatrick Boettcher 			dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */
2533173a64cbSPatrick Boettcher 		dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */
2534173a64cbSPatrick Boettcher 
2535173a64cbSPatrick Boettcher 		/* P_search_param_select = (1 | 1<<4 | 1 << 8) */
2536173a64cbSPatrick Boettcher 		dib8000_write_word(state, 356, 0);
2537173a64cbSPatrick Boettcher 		dib8000_write_word(state, 357, 0x111);
2538173a64cbSPatrick Boettcher 
2539173a64cbSPatrick Boettcher 		dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
2540173a64cbSPatrick Boettcher 		dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
2541173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */
2542d67350f8SOlivier Grenie 	} else if ((state->revision >= 0x8002) &&
2543d67350f8SOlivier Grenie 		   (state->autosearch_state == AS_SEARCHING_GUARD)) {
2544c82056d0SMauro Carvalho Chehab 		c->transmission_mode = TRANSMISSION_MODE_8K;
2545c82056d0SMauro Carvalho Chehab 		c->guard_interval = GUARD_INTERVAL_1_8;
2546c82056d0SMauro Carvalho Chehab 		c->inversion = 0;
2547c82056d0SMauro Carvalho Chehab 		c->layer[0].modulation = QAM_64;
2548c82056d0SMauro Carvalho Chehab 		c->layer[0].fec = FEC_2_3;
2549c82056d0SMauro Carvalho Chehab 		c->layer[0].interleaving = 0;
2550c82056d0SMauro Carvalho Chehab 		c->layer[0].segment_count = 13;
25519a0bf528SMauro Carvalho Chehab 
2552173a64cbSPatrick Boettcher 		slist = 16;
2553c82056d0SMauro Carvalho Chehab 		c->transmission_mode = state->found_nfft;
2554173a64cbSPatrick Boettcher 
2555173a64cbSPatrick Boettcher 		dib8000_set_isdbt_common_channel(state, slist, 1);
2556173a64cbSPatrick Boettcher 
2557173a64cbSPatrick Boettcher 		/* set lock_mask values */
2558173a64cbSPatrick Boettcher 		dib8000_write_word(state, 6, 0x4);
2559173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2560173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */
2561173a64cbSPatrick Boettcher 		else
2562173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, 0x8);
2563173a64cbSPatrick Boettcher 		dib8000_write_word(state, 8, 0x1000);
2564173a64cbSPatrick Boettcher 
2565173a64cbSPatrick Boettcher 		/* set lock_mask wait time values */
2566173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2567173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2568173a64cbSPatrick Boettcher 		else
2569173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2570173a64cbSPatrick Boettcher 
2571173a64cbSPatrick Boettcher 		dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */
2572173a64cbSPatrick Boettcher 
2573173a64cbSPatrick Boettcher 		/* P_search_param_select = 0xf; look for the 4 different guard intervals */
2574173a64cbSPatrick Boettcher 		dib8000_write_word(state, 356, 0);
2575173a64cbSPatrick Boettcher 		dib8000_write_word(state, 357, 0xf);
2576173a64cbSPatrick Boettcher 
2577173a64cbSPatrick Boettcher 		value = dib8000_read_word(state, 0);
2578173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2579173a64cbSPatrick Boettcher 		dib8000_read_word(state, 1284);  /* reset the INT. n_irq_pending */
2580173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (u16)value);
2581173a64cbSPatrick Boettcher 	} else {
2582c82056d0SMauro Carvalho Chehab 		c->inversion = 0;
2583c82056d0SMauro Carvalho Chehab 		c->layer[0].modulation = QAM_64;
2584c82056d0SMauro Carvalho Chehab 		c->layer[0].fec = FEC_2_3;
2585c82056d0SMauro Carvalho Chehab 		c->layer[0].interleaving = 0;
2586c82056d0SMauro Carvalho Chehab 		c->layer[0].segment_count = 13;
2587c82056d0SMauro Carvalho Chehab 		if (!c->isdbt_sb_mode)
2588c82056d0SMauro Carvalho Chehab 			c->layer[0].segment_count = 13;
2589173a64cbSPatrick Boettcher 
2590173a64cbSPatrick Boettcher 		/* choose the right list, in sb, always do everything */
2591c82056d0SMauro Carvalho Chehab 		if (c->isdbt_sb_mode) {
25929a0bf528SMauro Carvalho Chehab 			slist = 7;
25939a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
25949a0bf528SMauro Carvalho Chehab 		} else {
2595c82056d0SMauro Carvalho Chehab 			if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2596c82056d0SMauro Carvalho Chehab 				if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2597c82056d0SMauro Carvalho Chehab 					c->transmission_mode = TRANSMISSION_MODE_8K;
2598c82056d0SMauro Carvalho Chehab 					c->guard_interval = GUARD_INTERVAL_1_8;
25999a0bf528SMauro Carvalho Chehab 					slist = 7;
2600173a64cbSPatrick Boettcher 					dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));  /* P_mode = 1 to have autosearch start ok with mode2 */
2601173a64cbSPatrick Boettcher 				} else {
2602c82056d0SMauro Carvalho Chehab 					c->guard_interval = GUARD_INTERVAL_1_8;
26039a0bf528SMauro Carvalho Chehab 					slist = 3;
2604173a64cbSPatrick Boettcher 				}
26059a0bf528SMauro Carvalho Chehab 			} else {
2606c82056d0SMauro Carvalho Chehab 				if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2607c82056d0SMauro Carvalho Chehab 					c->transmission_mode = TRANSMISSION_MODE_8K;
26089a0bf528SMauro Carvalho Chehab 					slist = 2;
2609173a64cbSPatrick Boettcher 					dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));  /* P_mode = 1 */
26109a0bf528SMauro Carvalho Chehab 				} else
26119a0bf528SMauro Carvalho Chehab 					slist = 0;
26129a0bf528SMauro Carvalho Chehab 			}
2613173a64cbSPatrick Boettcher 		}
26148af16adfSMauro Carvalho Chehab 		dprintk("Using list for autosearch : %d\n", slist);
26159a0bf528SMauro Carvalho Chehab 
2616173a64cbSPatrick Boettcher 		dib8000_set_isdbt_common_channel(state, slist, 1);
26179a0bf528SMauro Carvalho Chehab 
2618173a64cbSPatrick Boettcher 		/* set lock_mask values */
26199a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 6, 0x4);
2620173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2621173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10));
2622173a64cbSPatrick Boettcher 		else
26239a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 7, 0x8);
26249a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 8, 0x1000);
26259a0bf528SMauro Carvalho Chehab 
2626173a64cbSPatrick Boettcher 		/* set lock_mask wait time values */
2627173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2628173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2629173a64cbSPatrick Boettcher 		else
2630173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
26319a0bf528SMauro Carvalho Chehab 
26329a0bf528SMauro Carvalho Chehab 		value = dib8000_read_word(state, 0);
26339a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2634173a64cbSPatrick Boettcher 		dib8000_read_word(state, 1284);  /* reset the INT. n_irq_pending */
26359a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 0, (u16)value);
26369a0bf528SMauro Carvalho Chehab 	}
26379a0bf528SMauro Carvalho Chehab 	return 0;
26389a0bf528SMauro Carvalho Chehab }
26399a0bf528SMauro Carvalho Chehab 
26409a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_irq(struct dvb_frontend *fe)
26419a0bf528SMauro Carvalho Chehab {
26429a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
26439a0bf528SMauro Carvalho Chehab 	u16 irq_pending = dib8000_read_word(state, 1284);
26449a0bf528SMauro Carvalho Chehab 
2645d67350f8SOlivier Grenie 	if ((state->revision >= 0x8002) &&
2646d67350f8SOlivier Grenie 	    (state->autosearch_state == AS_SEARCHING_FFT)) {
2647173a64cbSPatrick Boettcher 		if (irq_pending & 0x1) {
26488af16adfSMauro Carvalho Chehab 			dprintk("dib8000_autosearch_irq: max correlation result available\n");
2649173a64cbSPatrick Boettcher 			return 3;
2650173a64cbSPatrick Boettcher 		}
2651173a64cbSPatrick Boettcher 	} else {
2652173a64cbSPatrick Boettcher 		if (irq_pending & 0x1) {	/* failed */
26538af16adfSMauro Carvalho Chehab 			dprintk("dib8000_autosearch_irq failed\n");
26549a0bf528SMauro Carvalho Chehab 			return 1;
26559a0bf528SMauro Carvalho Chehab 		}
26569a0bf528SMauro Carvalho Chehab 
2657173a64cbSPatrick Boettcher 		if (irq_pending & 0x2) {	/* succeeded */
26588af16adfSMauro Carvalho Chehab 			dprintk("dib8000_autosearch_irq succeeded\n");
26599a0bf528SMauro Carvalho Chehab 			return 2;
26609a0bf528SMauro Carvalho Chehab 		}
2661173a64cbSPatrick Boettcher 	}
26629a0bf528SMauro Carvalho Chehab 
26639a0bf528SMauro Carvalho Chehab 	return 0;		// still pending
26649a0bf528SMauro Carvalho Chehab }
26659a0bf528SMauro Carvalho Chehab 
2666173a64cbSPatrick Boettcher static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
2667173a64cbSPatrick Boettcher {
2668173a64cbSPatrick Boettcher 	u16 tmp;
2669173a64cbSPatrick Boettcher 
2670173a64cbSPatrick Boettcher 	tmp = dib8000_read_word(state, 771);
2671173a64cbSPatrick Boettcher 	if (onoff) /* start P_restart_chd : channel_decoder */
2672173a64cbSPatrick Boettcher 		dib8000_write_word(state, 771, tmp & 0xfffd);
2673173a64cbSPatrick Boettcher 	else /* stop P_restart_chd : channel_decoder */
2674173a64cbSPatrick Boettcher 		dib8000_write_word(state, 771, tmp | (1<<1));
2675173a64cbSPatrick Boettcher }
2676173a64cbSPatrick Boettcher 
2677173a64cbSPatrick Boettcher static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
2678173a64cbSPatrick Boettcher {
2679173a64cbSPatrick Boettcher 	s16 unit_khz_dds_val;
2680173a64cbSPatrick Boettcher 	u32 abs_offset_khz = ABS(offset_khz);
2681173a64cbSPatrick Boettcher 	u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
2682173a64cbSPatrick Boettcher 	u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
2683173a64cbSPatrick Boettcher 	u8 ratio;
2684173a64cbSPatrick Boettcher 
2685173a64cbSPatrick Boettcher 	if (state->revision == 0x8090) {
2686173a64cbSPatrick Boettcher 		ratio = 4;
2687173a64cbSPatrick Boettcher 		unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000);
2688173a64cbSPatrick Boettcher 		if (offset_khz < 0)
2689173a64cbSPatrick Boettcher 			dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
2690173a64cbSPatrick Boettcher 		else
2691173a64cbSPatrick Boettcher 			dds = (abs_offset_khz * unit_khz_dds_val);
2692173a64cbSPatrick Boettcher 
2693173a64cbSPatrick Boettcher 		if (invert)
2694173a64cbSPatrick Boettcher 			dds = (1<<26) - dds;
2695173a64cbSPatrick Boettcher 	} else {
2696173a64cbSPatrick Boettcher 		ratio = 2;
2697173a64cbSPatrick Boettcher 		unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
2698173a64cbSPatrick Boettcher 
2699173a64cbSPatrick Boettcher 		if (offset_khz < 0)
2700173a64cbSPatrick Boettcher 			unit_khz_dds_val *= -1;
2701173a64cbSPatrick Boettcher 
2702173a64cbSPatrick Boettcher 		/* IF tuner */
2703173a64cbSPatrick Boettcher 		if (invert)
2704173a64cbSPatrick Boettcher 			dds -= abs_offset_khz * unit_khz_dds_val;
2705173a64cbSPatrick Boettcher 		else
2706173a64cbSPatrick Boettcher 			dds += abs_offset_khz * unit_khz_dds_val;
2707173a64cbSPatrick Boettcher 	}
2708173a64cbSPatrick Boettcher 
27098af16adfSMauro Carvalho Chehab 	dprintk("setting a DDS frequency offset of %c%dkHz\n", invert ? '-' : ' ', dds / unit_khz_dds_val);
2710173a64cbSPatrick Boettcher 
2711173a64cbSPatrick Boettcher 	if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) {
2712173a64cbSPatrick Boettcher 		/* Max dds offset is the half of the demod freq */
2713173a64cbSPatrick Boettcher 		dib8000_write_word(state, 26, invert);
2714173a64cbSPatrick Boettcher 		dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff);
2715173a64cbSPatrick Boettcher 		dib8000_write_word(state, 28, (u16)(dds & 0xffff));
2716173a64cbSPatrick Boettcher 	}
2717173a64cbSPatrick Boettcher }
2718173a64cbSPatrick Boettcher 
2719173a64cbSPatrick Boettcher static void dib8000_set_frequency_offset(struct dib8000_state *state)
2720173a64cbSPatrick Boettcher {
2721c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2722173a64cbSPatrick Boettcher 	int i;
2723173a64cbSPatrick Boettcher 	u32 current_rf;
2724173a64cbSPatrick Boettcher 	int total_dds_offset_khz;
2725173a64cbSPatrick Boettcher 
2726173a64cbSPatrick Boettcher 	if (state->fe[0]->ops.tuner_ops.get_frequency)
2727173a64cbSPatrick Boettcher 		state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], &current_rf);
2728173a64cbSPatrick Boettcher 	else
2729c82056d0SMauro Carvalho Chehab 		current_rf = c->frequency;
2730173a64cbSPatrick Boettcher 	current_rf /= 1000;
2731c82056d0SMauro Carvalho Chehab 	total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000;
2732173a64cbSPatrick Boettcher 
2733c82056d0SMauro Carvalho Chehab 	if (c->isdbt_sb_mode) {
2734c82056d0SMauro Carvalho Chehab 		state->subchannel = c->isdbt_sb_subchannel;
2735173a64cbSPatrick Boettcher 
2736173a64cbSPatrick Boettcher 		i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */
2737c82056d0SMauro Carvalho Chehab 		dib8000_write_word(state, 26, c->inversion ^ i);
2738173a64cbSPatrick Boettcher 
2739173a64cbSPatrick Boettcher 		if (state->cfg.pll->ifreq == 0) { /* low if tuner */
2740c82056d0SMauro Carvalho Chehab 			if ((c->inversion ^ i) == 0)
2741173a64cbSPatrick Boettcher 				dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
2742173a64cbSPatrick Boettcher 		} else {
2743c82056d0SMauro Carvalho Chehab 			if ((c->inversion ^ i) == 0)
2744173a64cbSPatrick Boettcher 				total_dds_offset_khz *= -1;
2745173a64cbSPatrick Boettcher 		}
2746173a64cbSPatrick Boettcher 	}
2747173a64cbSPatrick Boettcher 
27488af16adfSMauro Carvalho Chehab 	dprintk("%dkhz tuner offset (frequency = %dHz & current_rf = %dHz) total_dds_offset_hz = %d\n", c->frequency - current_rf, c->frequency, current_rf, total_dds_offset_khz);
2749173a64cbSPatrick Boettcher 
2750173a64cbSPatrick Boettcher 	/* apply dds offset now */
2751173a64cbSPatrick Boettcher 	dib8000_set_dds(state, total_dds_offset_khz);
2752173a64cbSPatrick Boettcher }
2753173a64cbSPatrick Boettcher 
2754173a64cbSPatrick Boettcher static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 };
27556f7ee06fSMauro Carvalho Chehab 
27566f7ee06fSMauro Carvalho Chehab static u32 dib8000_get_symbol_duration(struct dib8000_state *state)
2757173a64cbSPatrick Boettcher {
2758c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2759173a64cbSPatrick Boettcher 	u16 i;
2760173a64cbSPatrick Boettcher 
2761c82056d0SMauro Carvalho Chehab 	switch (c->transmission_mode) {
2762173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_2K:
2763173a64cbSPatrick Boettcher 			i = 0;
2764173a64cbSPatrick Boettcher 			break;
2765173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_4K:
2766173a64cbSPatrick Boettcher 			i = 2;
2767173a64cbSPatrick Boettcher 			break;
2768173a64cbSPatrick Boettcher 	default:
2769173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_AUTO:
2770173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2771173a64cbSPatrick Boettcher 			i = 1;
2772173a64cbSPatrick Boettcher 			break;
2773173a64cbSPatrick Boettcher 	}
2774173a64cbSPatrick Boettcher 
2775c82056d0SMauro Carvalho Chehab 	return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1;
2776173a64cbSPatrick Boettcher }
2777173a64cbSPatrick Boettcher 
2778173a64cbSPatrick Boettcher static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step)
2779173a64cbSPatrick Boettcher {
2780c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2781173a64cbSPatrick Boettcher 	u16 reg_32 = 0, reg_37 = 0;
2782173a64cbSPatrick Boettcher 
2783173a64cbSPatrick Boettcher 	switch (loop_step) {
2784173a64cbSPatrick Boettcher 	case LOOP_TUNE_1:
2785c82056d0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode)  {
2786c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) {
2787173a64cbSPatrick Boettcher 					reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */
2788173a64cbSPatrick 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)  */
2789173a64cbSPatrick Boettcher 				} else { /* Sound Broadcasting mode 3 seg */
2790173a64cbSPatrick Boettcher 					reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */
2791173a64cbSPatrick 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)  */
2792173a64cbSPatrick Boettcher 				}
2793173a64cbSPatrick Boettcher 			} else { /* 13-seg start conf offset loop parameters */
2794173a64cbSPatrick Boettcher 				reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
2795173a64cbSPatrick 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  */
2796173a64cbSPatrick Boettcher 			}
2797173a64cbSPatrick Boettcher 			break;
2798173a64cbSPatrick Boettcher 	case LOOP_TUNE_2:
2799c82056d0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode)  {
2800c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) {  /* Sound Broadcasting mode 1 seg */
2801173a64cbSPatrick Boettcher 					reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/
2802173a64cbSPatrick Boettcher 					reg_37 = (12-state->mode) | ((5 + state->mode) << 5);
2803173a64cbSPatrick Boettcher 				} else {  /* Sound Broadcasting mode 3 seg */
2804173a64cbSPatrick Boettcher 					reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */
2805173a64cbSPatrick Boettcher 					reg_37 = (11-state->mode) | ((5 + state->mode) << 5);
2806173a64cbSPatrick Boettcher 				}
2807173a64cbSPatrick Boettcher 			} else {  /* 13 seg */
2808173a64cbSPatrick Boettcher 				reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */
2809173a64cbSPatrick Boettcher 				reg_37 = ((5+state->mode) << 5) | (10 - state->mode);
2810173a64cbSPatrick Boettcher 			}
2811173a64cbSPatrick Boettcher 			break;
2812173a64cbSPatrick Boettcher 	}
2813173a64cbSPatrick Boettcher 	dib8000_write_word(state, 32, reg_32);
2814173a64cbSPatrick Boettcher 	dib8000_write_word(state, 37, reg_37);
2815173a64cbSPatrick Boettcher }
2816173a64cbSPatrick Boettcher 
2817173a64cbSPatrick Boettcher static void dib8000_demod_restart(struct dib8000_state *state)
2818173a64cbSPatrick Boettcher {
2819173a64cbSPatrick Boettcher 	dib8000_write_word(state, 770, 0x4000);
2820173a64cbSPatrick Boettcher 	dib8000_write_word(state, 770, 0x0000);
2821173a64cbSPatrick Boettcher 	return;
2822173a64cbSPatrick Boettcher }
2823173a64cbSPatrick Boettcher 
2824173a64cbSPatrick Boettcher static void dib8000_set_sync_wait(struct dib8000_state *state)
2825173a64cbSPatrick Boettcher {
2826c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2827173a64cbSPatrick Boettcher 	u16 sync_wait = 64;
2828173a64cbSPatrick Boettcher 
2829173a64cbSPatrick Boettcher 	/* P_dvsy_sync_wait - reuse mode */
2830c82056d0SMauro Carvalho Chehab 	switch (c->transmission_mode) {
2831173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2832173a64cbSPatrick Boettcher 			sync_wait = 256;
2833173a64cbSPatrick Boettcher 			break;
2834173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_4K:
2835173a64cbSPatrick Boettcher 			sync_wait = 128;
2836173a64cbSPatrick Boettcher 			break;
2837173a64cbSPatrick Boettcher 	default:
2838173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_2K:
2839173a64cbSPatrick Boettcher 			sync_wait =  64;
2840173a64cbSPatrick Boettcher 			break;
2841173a64cbSPatrick Boettcher 	}
2842173a64cbSPatrick Boettcher 
2843173a64cbSPatrick Boettcher 	if (state->cfg.diversity_delay == 0)
2844c82056d0SMauro Carvalho Chehab 		sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */
2845173a64cbSPatrick Boettcher 	else
2846c82056d0SMauro Carvalho Chehab 		sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */
2847173a64cbSPatrick Boettcher 
2848173a64cbSPatrick Boettcher 	dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
2849173a64cbSPatrick Boettcher }
2850173a64cbSPatrick Boettcher 
2851d6c62b76SMauro Carvalho Chehab static unsigned long dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
2852173a64cbSPatrick Boettcher {
2853173a64cbSPatrick Boettcher 	if (mode == SYMBOL_DEPENDENT_ON)
2854d6c62b76SMauro Carvalho Chehab 		delay *= state->symbol_duration;
2855d6c62b76SMauro Carvalho Chehab 
2856d6c62b76SMauro Carvalho Chehab 	return jiffies + usecs_to_jiffies(delay * 100);
2857173a64cbSPatrick Boettcher }
2858173a64cbSPatrick Boettcher 
2859173a64cbSPatrick Boettcher static s32 dib8000_get_status(struct dvb_frontend *fe)
2860173a64cbSPatrick Boettcher {
2861173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2862173a64cbSPatrick Boettcher 	return state->status;
2863173a64cbSPatrick Boettcher }
2864173a64cbSPatrick Boettcher 
2865d44913c1SMauro Carvalho Chehab static enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
2866173a64cbSPatrick Boettcher {
2867173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2868173a64cbSPatrick Boettcher 	return state->tune_state;
2869173a64cbSPatrick Boettcher }
2870173a64cbSPatrick Boettcher 
2871d44913c1SMauro Carvalho Chehab static int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2872173a64cbSPatrick Boettcher {
2873173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2874173a64cbSPatrick Boettcher 
2875173a64cbSPatrick Boettcher 	state->tune_state = tune_state;
2876173a64cbSPatrick Boettcher 	return 0;
2877173a64cbSPatrick Boettcher }
2878173a64cbSPatrick Boettcher 
2879173a64cbSPatrick Boettcher static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
2880173a64cbSPatrick Boettcher {
2881173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2882173a64cbSPatrick Boettcher 
2883173a64cbSPatrick Boettcher 	state->status = FE_STATUS_TUNE_PENDING;
2884173a64cbSPatrick Boettcher 	state->tune_state = CT_DEMOD_START;
2885173a64cbSPatrick Boettcher 	return 0;
2886173a64cbSPatrick Boettcher }
2887173a64cbSPatrick Boettcher 
2888173a64cbSPatrick Boettcher static u16 dib8000_read_lock(struct dvb_frontend *fe)
2889173a64cbSPatrick Boettcher {
2890173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2891173a64cbSPatrick Boettcher 
2892173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
2893173a64cbSPatrick Boettcher 		return dib8000_read_word(state, 570);
2894173a64cbSPatrick Boettcher 	return dib8000_read_word(state, 568);
2895173a64cbSPatrick Boettcher }
2896173a64cbSPatrick Boettcher 
2897173a64cbSPatrick Boettcher static int dib8090p_init_sdram(struct dib8000_state *state)
2898173a64cbSPatrick Boettcher {
2899173a64cbSPatrick Boettcher 	u16 reg = 0;
29008af16adfSMauro Carvalho Chehab 	dprintk("init sdram\n");
2901173a64cbSPatrick Boettcher 
2902173a64cbSPatrick Boettcher 	reg = dib8000_read_word(state, 274) & 0xfff0;
2903173a64cbSPatrick Boettcher 	dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */
2904173a64cbSPatrick Boettcher 
2905173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1803, (7 << 2));
2906173a64cbSPatrick Boettcher 
2907173a64cbSPatrick Boettcher 	reg = dib8000_read_word(state, 1280);
2908173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1280,  reg | (1 << 2)); /* force restart P_restart_sdram */
2909173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1280,  reg); /* release restart P_restart_sdram */
2910173a64cbSPatrick Boettcher 
2911173a64cbSPatrick Boettcher 	return 0;
2912173a64cbSPatrick Boettcher }
2913173a64cbSPatrick Boettcher 
2914ad976187SMauro Carvalho Chehab /**
2915ad976187SMauro Carvalho Chehab  * is_manual_mode - Check if TMCC should be used for parameters settings
2916ad976187SMauro Carvalho Chehab  * @c:	struct dvb_frontend_properties
2917ad976187SMauro Carvalho Chehab  *
2918ad976187SMauro Carvalho Chehab  * By default, TMCC table should be used for parameter settings on most
2919ad976187SMauro Carvalho Chehab  * usercases. However, sometimes it is desirable to lock the demod to
2920ad976187SMauro Carvalho Chehab  * use the manual parameters.
2921ad976187SMauro Carvalho Chehab  *
2922ad976187SMauro Carvalho Chehab  * On manual mode, the current dib8000_tune state machine is very restrict:
2923ad976187SMauro Carvalho Chehab  * It requires that both per-layer and per-transponder parameters to be
2924ad976187SMauro Carvalho Chehab  * properly specified, otherwise the device won't lock.
2925ad976187SMauro Carvalho Chehab  *
2926ad976187SMauro Carvalho Chehab  * Check if all those conditions are properly satisfied before allowing
2927ad976187SMauro Carvalho Chehab  * the device to use the manual frequency lock mode.
2928ad976187SMauro Carvalho Chehab  */
2929ad976187SMauro Carvalho Chehab static int is_manual_mode(struct dtv_frontend_properties *c)
2930ad976187SMauro Carvalho Chehab {
2931ad976187SMauro Carvalho Chehab 	int i, n_segs = 0;
2932ad976187SMauro Carvalho Chehab 
2933ad976187SMauro Carvalho Chehab 	/* Use auto mode on DVB-T compat mode */
2934ad976187SMauro Carvalho Chehab 	if (c->delivery_system != SYS_ISDBT)
2935ad976187SMauro Carvalho Chehab 		return 0;
2936ad976187SMauro Carvalho Chehab 
2937ad976187SMauro Carvalho Chehab 	/*
2938ad976187SMauro Carvalho Chehab 	 * Transmission mode is only detected on auto mode, currently
2939ad976187SMauro Carvalho Chehab 	 */
2940ad976187SMauro Carvalho Chehab 	if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
29418af16adfSMauro Carvalho Chehab 		dprintk("transmission mode auto\n");
2942ad976187SMauro Carvalho Chehab 		return 0;
2943ad976187SMauro Carvalho Chehab 	}
2944ad976187SMauro Carvalho Chehab 
2945ad976187SMauro Carvalho Chehab 	/*
2946ad976187SMauro Carvalho Chehab 	 * Guard interval is only detected on auto mode, currently
2947ad976187SMauro Carvalho Chehab 	 */
2948ad976187SMauro Carvalho Chehab 	if (c->guard_interval == GUARD_INTERVAL_AUTO) {
29498af16adfSMauro Carvalho Chehab 		dprintk("guard interval auto\n");
2950ad976187SMauro Carvalho Chehab 		return 0;
2951ad976187SMauro Carvalho Chehab 	}
2952ad976187SMauro Carvalho Chehab 
2953ad976187SMauro Carvalho Chehab 	/*
2954ad976187SMauro Carvalho Chehab 	 * If no layer is enabled, assume auto mode, as at least one
2955ad976187SMauro Carvalho Chehab 	 * layer should be enabled
2956ad976187SMauro Carvalho Chehab 	 */
2957ad976187SMauro Carvalho Chehab 	if (!c->isdbt_layer_enabled) {
29588af16adfSMauro Carvalho Chehab 		dprintk("no layer modulation specified\n");
2959ad976187SMauro Carvalho Chehab 		return 0;
2960ad976187SMauro Carvalho Chehab 	}
2961ad976187SMauro Carvalho Chehab 
2962ad976187SMauro Carvalho Chehab 	/*
2963ad976187SMauro Carvalho Chehab 	 * Check if the per-layer parameters aren't auto and
2964ad976187SMauro Carvalho Chehab 	 * disable a layer if segment count is 0 or invalid.
2965ad976187SMauro Carvalho Chehab 	 */
2966ad976187SMauro Carvalho Chehab 	for (i = 0; i < 3; i++) {
2967ad976187SMauro Carvalho Chehab 		if (!(c->isdbt_layer_enabled & 1 << i))
2968ad976187SMauro Carvalho Chehab 			continue;
2969ad976187SMauro Carvalho Chehab 
2970ad976187SMauro Carvalho Chehab 		if ((c->layer[i].segment_count > 13) ||
2971ad976187SMauro Carvalho Chehab 		    (c->layer[i].segment_count == 0)) {
2972ad976187SMauro Carvalho Chehab 			c->isdbt_layer_enabled &= ~(1 << i);
2973ad976187SMauro Carvalho Chehab 			continue;
2974ad976187SMauro Carvalho Chehab 		}
2975ad976187SMauro Carvalho Chehab 
2976ad976187SMauro Carvalho Chehab 		n_segs += c->layer[i].segment_count;
2977ad976187SMauro Carvalho Chehab 
2978ad976187SMauro Carvalho Chehab 		if ((c->layer[i].modulation == QAM_AUTO) ||
2979ad976187SMauro Carvalho Chehab 		    (c->layer[i].fec == FEC_AUTO)) {
29808af16adfSMauro Carvalho Chehab 			dprintk("layer %c has either modulation or FEC auto\n",
2981ad976187SMauro Carvalho Chehab 				'A' + i);
2982ad976187SMauro Carvalho Chehab 			return 0;
2983ad976187SMauro Carvalho Chehab 		}
2984ad976187SMauro Carvalho Chehab 	}
2985ad976187SMauro Carvalho Chehab 
2986ad976187SMauro Carvalho Chehab 	/*
2987ad976187SMauro Carvalho Chehab 	 * Userspace specified a wrong number of segments.
2988ad976187SMauro Carvalho Chehab 	 *	fallback to auto mode.
2989ad976187SMauro Carvalho Chehab 	 */
2990ad976187SMauro Carvalho Chehab 	if (n_segs == 0 || n_segs > 13) {
29918af16adfSMauro Carvalho Chehab 		dprintk("number of segments is invalid\n");
2992ad976187SMauro Carvalho Chehab 		return 0;
2993ad976187SMauro Carvalho Chehab 	}
2994ad976187SMauro Carvalho Chehab 
2995ad976187SMauro Carvalho Chehab 	/* Everything looks ok for manual mode */
2996ad976187SMauro Carvalho Chehab 	return 1;
2997ad976187SMauro Carvalho Chehab }
2998ad976187SMauro Carvalho Chehab 
29999a0bf528SMauro Carvalho Chehab static int dib8000_tune(struct dvb_frontend *fe)
30009a0bf528SMauro Carvalho Chehab {
30019a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
3002c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3003173a64cbSPatrick Boettcher 	enum frontend_tune_state *tune_state = &state->tune_state;
30049a0bf528SMauro Carvalho Chehab 
3005173a64cbSPatrick Boettcher 	u16 locks, deeper_interleaver = 0, i;
3006173a64cbSPatrick Boettcher 	int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
30079a0bf528SMauro Carvalho Chehab 
3008d6c62b76SMauro Carvalho Chehab 	unsigned long *timeout = &state->timeout;
3009d6c62b76SMauro Carvalho Chehab 	unsigned long now = jiffies;
3010173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3011173a64cbSPatrick Boettcher 	u16 agc1, agc2;
3012173a64cbSPatrick Boettcher #endif
30139a0bf528SMauro Carvalho Chehab 
3014173a64cbSPatrick Boettcher 	u32 corm[4] = {0, 0, 0, 0};
3015173a64cbSPatrick Boettcher 	u8 find_index, max_value;
30169a0bf528SMauro Carvalho Chehab 
3017173a64cbSPatrick Boettcher #if 0
3018173a64cbSPatrick Boettcher 	if (*tune_state < CT_DEMOD_STOP)
30198af16adfSMauro Carvalho Chehab 		dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u jiffies = %lu\n",
3020d6c62b76SMauro Carvalho Chehab 			state->channel_parameters_set, *tune_state, state->autosearch_state, now);
3021173a64cbSPatrick Boettcher #endif
30229a0bf528SMauro Carvalho Chehab 
3023173a64cbSPatrick Boettcher 	switch (*tune_state) {
3024173a64cbSPatrick Boettcher 	case CT_DEMOD_START: /* 30 */
30256ef06e78SMauro Carvalho Chehab 		dib8000_reset_stats(fe);
30266ef06e78SMauro Carvalho Chehab 
3027173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
3028173a64cbSPatrick Boettcher 			dib8090p_init_sdram(state);
3029173a64cbSPatrick Boettcher 		state->status = FE_STATUS_TUNE_PENDING;
3030ad976187SMauro Carvalho Chehab 		state->channel_parameters_set = is_manual_mode(c);
3031ad976187SMauro Carvalho Chehab 
30328af16adfSMauro Carvalho Chehab 		dprintk("Tuning channel on %s search mode\n",
3033ad976187SMauro Carvalho Chehab 			state->channel_parameters_set ? "manual" : "auto");
30349a0bf528SMauro Carvalho Chehab 
3035173a64cbSPatrick Boettcher 		dib8000_viterbi_state(state, 0); /* force chan dec in restart */
30369a0bf528SMauro Carvalho Chehab 
3037ad976187SMauro Carvalho Chehab 		/* Layer monitor */
3038173a64cbSPatrick Boettcher 		dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
3039173a64cbSPatrick Boettcher 
3040173a64cbSPatrick Boettcher 		dib8000_set_frequency_offset(state);
3041c82056d0SMauro Carvalho Chehab 		dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
3042173a64cbSPatrick Boettcher 
3043173a64cbSPatrick Boettcher 		if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
3044173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3045173a64cbSPatrick Boettcher 			if (state->revision != 0x8090) {
3046173a64cbSPatrick Boettcher 				state->agc1_max = dib8000_read_word(state, 108);
3047173a64cbSPatrick Boettcher 				state->agc1_min = dib8000_read_word(state, 109);
3048173a64cbSPatrick Boettcher 				state->agc2_max = dib8000_read_word(state, 110);
3049173a64cbSPatrick Boettcher 				state->agc2_min = dib8000_read_word(state, 111);
3050173a64cbSPatrick Boettcher 				agc1 = dib8000_read_word(state, 388);
3051173a64cbSPatrick Boettcher 				agc2 = dib8000_read_word(state, 389);
3052173a64cbSPatrick Boettcher 				dib8000_write_word(state, 108, agc1);
3053173a64cbSPatrick Boettcher 				dib8000_write_word(state, 109, agc1);
3054173a64cbSPatrick Boettcher 				dib8000_write_word(state, 110, agc2);
3055173a64cbSPatrick Boettcher 				dib8000_write_word(state, 111, agc2);
3056173a64cbSPatrick Boettcher 			}
3057173a64cbSPatrick Boettcher #endif
3058173a64cbSPatrick Boettcher 			state->autosearch_state = AS_SEARCHING_FFT;
3059173a64cbSPatrick Boettcher 			state->found_nfft = TRANSMISSION_MODE_AUTO;
3060173a64cbSPatrick Boettcher 			state->found_guard = GUARD_INTERVAL_AUTO;
3061173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_SEARCH_NEXT;
3062173a64cbSPatrick Boettcher 		} else { /* we already know the channel struct so TUNE only ! */
3063173a64cbSPatrick Boettcher 			state->autosearch_state = AS_DONE;
3064173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_3;
3065173a64cbSPatrick Boettcher 		}
3066173a64cbSPatrick Boettcher 		state->symbol_duration = dib8000_get_symbol_duration(state);
3067173a64cbSPatrick Boettcher 		break;
3068173a64cbSPatrick Boettcher 
3069173a64cbSPatrick Boettcher 	case CT_DEMOD_SEARCH_NEXT: /* 51 */
3070173a64cbSPatrick Boettcher 		dib8000_autosearch_start(fe);
3071173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
3072173a64cbSPatrick Boettcher 			ret = 50;
3073173a64cbSPatrick Boettcher 		else
3074173a64cbSPatrick Boettcher 			ret = 15;
3075173a64cbSPatrick Boettcher 		*tune_state = CT_DEMOD_STEP_1;
3076173a64cbSPatrick Boettcher 		break;
3077173a64cbSPatrick Boettcher 
3078173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_1: /* 31 */
3079173a64cbSPatrick Boettcher 		switch (dib8000_autosearch_irq(fe)) {
3080173a64cbSPatrick Boettcher 		case 1: /* fail */
3081173a64cbSPatrick Boettcher 			state->status = FE_STATUS_TUNE_FAILED;
3082173a64cbSPatrick Boettcher 			state->autosearch_state = AS_DONE;
3083173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STOP; /* else we are done here */
3084173a64cbSPatrick Boettcher 			break;
3085173a64cbSPatrick Boettcher 		case 2: /* Succes */
3086173a64cbSPatrick Boettcher 			state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
3087173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_3;
3088173a64cbSPatrick Boettcher 			if (state->autosearch_state == AS_SEARCHING_GUARD)
3089173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_2;
3090173a64cbSPatrick Boettcher 			else
3091173a64cbSPatrick Boettcher 				state->autosearch_state = AS_DONE;
3092173a64cbSPatrick Boettcher 			break;
3093173a64cbSPatrick Boettcher 		case 3: /* Autosearch FFT max correlation endded */
3094173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_2;
3095173a64cbSPatrick Boettcher 			break;
3096173a64cbSPatrick Boettcher 		}
3097173a64cbSPatrick Boettcher 		break;
3098173a64cbSPatrick Boettcher 
3099173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_2:
3100173a64cbSPatrick Boettcher 		switch (state->autosearch_state) {
3101173a64cbSPatrick Boettcher 		case AS_SEARCHING_FFT:
3102173a64cbSPatrick Boettcher 			/* searching for the correct FFT */
3103173a64cbSPatrick Boettcher 			if (state->revision == 0x8090) {
3104173a64cbSPatrick Boettcher 				corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3105173a64cbSPatrick Boettcher 				corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3106173a64cbSPatrick Boettcher 				corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
3107173a64cbSPatrick Boettcher 			} else {
3108173a64cbSPatrick Boettcher 				corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
3109173a64cbSPatrick Boettcher 				corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3110173a64cbSPatrick Boettcher 				corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3111173a64cbSPatrick Boettcher 			}
31128af16adfSMauro Carvalho Chehab 			/* dprintk("corm fft: %u %u %u\n", corm[0], corm[1], corm[2]); */
3113173a64cbSPatrick Boettcher 
3114173a64cbSPatrick Boettcher 			max_value = 0;
3115173a64cbSPatrick Boettcher 			for (find_index = 1 ; find_index < 3 ; find_index++) {
3116173a64cbSPatrick Boettcher 				if (corm[max_value] < corm[find_index])
3117173a64cbSPatrick Boettcher 					max_value = find_index ;
31189a0bf528SMauro Carvalho Chehab 			}
31199a0bf528SMauro Carvalho Chehab 
3120173a64cbSPatrick Boettcher 			switch (max_value) {
3121173a64cbSPatrick Boettcher 			case 0:
3122173a64cbSPatrick Boettcher 				state->found_nfft = TRANSMISSION_MODE_2K;
3123173a64cbSPatrick Boettcher 				break;
3124173a64cbSPatrick Boettcher 			case 1:
3125173a64cbSPatrick Boettcher 				state->found_nfft = TRANSMISSION_MODE_4K;
3126173a64cbSPatrick Boettcher 				break;
3127173a64cbSPatrick Boettcher 			case 2:
3128173a64cbSPatrick Boettcher 			default:
3129173a64cbSPatrick Boettcher 				state->found_nfft = TRANSMISSION_MODE_8K;
3130173a64cbSPatrick Boettcher 				break;
3131173a64cbSPatrick Boettcher 			}
31328af16adfSMauro Carvalho Chehab 			/* dprintk("Autosearch FFT has found Mode %d\n", max_value + 1); */
3133173a64cbSPatrick Boettcher 
3134173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_SEARCH_NEXT;
3135173a64cbSPatrick Boettcher 			state->autosearch_state = AS_SEARCHING_GUARD;
3136173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
3137173a64cbSPatrick Boettcher 				ret = 50;
3138173a64cbSPatrick Boettcher 			else
3139173a64cbSPatrick Boettcher 				ret = 10;
3140173a64cbSPatrick Boettcher 			break;
3141173a64cbSPatrick Boettcher 		case AS_SEARCHING_GUARD:
3142173a64cbSPatrick Boettcher 			/* searching for the correct guard interval */
3143173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
3144173a64cbSPatrick Boettcher 				state->found_guard = dib8000_read_word(state, 572) & 0x3;
3145173a64cbSPatrick Boettcher 			else
3146173a64cbSPatrick Boettcher 				state->found_guard = dib8000_read_word(state, 570) & 0x3;
31478af16adfSMauro Carvalho Chehab 			/* dprintk("guard interval found=%i\n", state->found_guard); */
3148173a64cbSPatrick Boettcher 
3149173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_3;
3150173a64cbSPatrick Boettcher 			break;
3151173a64cbSPatrick Boettcher 		default:
3152173a64cbSPatrick Boettcher 			/* the demod should never be in this state */
3153173a64cbSPatrick Boettcher 			state->status = FE_STATUS_TUNE_FAILED;
3154173a64cbSPatrick Boettcher 			state->autosearch_state = AS_DONE;
3155173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STOP; /* else we are done here */
3156173a64cbSPatrick Boettcher 			break;
3157173a64cbSPatrick Boettcher 		}
3158173a64cbSPatrick Boettcher 		break;
3159173a64cbSPatrick Boettcher 
3160173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_3: /* 33 */
3161173a64cbSPatrick Boettcher 		dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
3162173a64cbSPatrick Boettcher 		dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
3163173a64cbSPatrick Boettcher 		*tune_state = CT_DEMOD_STEP_4;
3164173a64cbSPatrick Boettcher 		break;
3165173a64cbSPatrick Boettcher 
3166173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_4: /* (34) */
3167173a64cbSPatrick Boettcher 		dib8000_demod_restart(state);
3168173a64cbSPatrick Boettcher 
3169173a64cbSPatrick Boettcher 		dib8000_set_sync_wait(state);
3170173a64cbSPatrick Boettcher 		dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
3171173a64cbSPatrick Boettcher 
3172173a64cbSPatrick Boettcher 		locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
317339c1cb2bSJonathan McCrohan 		/* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */
3174173a64cbSPatrick Boettcher 		*timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
3175173a64cbSPatrick Boettcher 		*tune_state = CT_DEMOD_STEP_5;
3176173a64cbSPatrick Boettcher 		break;
3177173a64cbSPatrick Boettcher 
3178173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_5: /* (35) */
3179173a64cbSPatrick Boettcher 		locks = dib8000_read_lock(fe);
3180173a64cbSPatrick Boettcher 		if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
3181173a64cbSPatrick Boettcher 			dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
3182173a64cbSPatrick Boettcher 			if (!state->differential_constellation) {
3183173a64cbSPatrick Boettcher 				/* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
3184173a64cbSPatrick Boettcher 				*timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
3185173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_7;
3186173a64cbSPatrick Boettcher 			} else {
3187173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_8;
3188173a64cbSPatrick Boettcher 			}
3189d6c62b76SMauro Carvalho Chehab 		} else if (time_after(now, *timeout)) {
3190173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3191173a64cbSPatrick Boettcher 		}
3192173a64cbSPatrick Boettcher 		break;
3193173a64cbSPatrick Boettcher 
3194173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_6: /* (36)  if there is an input (diversity) */
3195173a64cbSPatrick Boettcher 		if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
3196173a64cbSPatrick 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 */
3197173a64cbSPatrick Boettcher 			if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
3198173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
3199173a64cbSPatrick Boettcher 			else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */
3200173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3201173a64cbSPatrick Boettcher 				dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3202173a64cbSPatrick Boettcher 				dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3203173a64cbSPatrick Boettcher 				state->status = FE_STATUS_TUNE_FAILED;
3204173a64cbSPatrick Boettcher 			}
3205173a64cbSPatrick Boettcher 		} else {
3206173a64cbSPatrick Boettcher 			dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3207173a64cbSPatrick Boettcher 			dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3208173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3209173a64cbSPatrick Boettcher 			state->status = FE_STATUS_TUNE_FAILED;
3210173a64cbSPatrick Boettcher 		}
3211173a64cbSPatrick Boettcher 		break;
3212173a64cbSPatrick Boettcher 
3213173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_7: /* 37 */
3214173a64cbSPatrick Boettcher 		locks = dib8000_read_lock(fe);
3215173a64cbSPatrick Boettcher 		if (locks & (1<<10)) { /* lmod4_lock */
3216173a64cbSPatrick Boettcher 			ret = 14; /* wait for 14 symbols */
3217173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_8;
3218d6c62b76SMauro Carvalho Chehab 		} else if (time_after(now, *timeout))
3219173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3220173a64cbSPatrick Boettcher 		break;
3221173a64cbSPatrick Boettcher 
3222173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_8: /* 38 */
3223173a64cbSPatrick Boettcher 		dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3224173a64cbSPatrick Boettcher 		dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3225173a64cbSPatrick Boettcher 
3226173a64cbSPatrick Boettcher 		/* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
3227746f7ae0SMauro Carvalho Chehab 		if (c->isdbt_sb_mode
3228746f7ae0SMauro Carvalho Chehab 		    && c->isdbt_sb_subchannel < 14
3229746f7ae0SMauro Carvalho Chehab 		    && !state->differential_constellation) {
3230173a64cbSPatrick Boettcher 			state->subchannel = 0;
3231173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_11;
3232173a64cbSPatrick Boettcher 		} else {
3233173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_9;
3234173a64cbSPatrick Boettcher 			state->status = FE_STATUS_LOCKED;
3235173a64cbSPatrick Boettcher 		}
3236173a64cbSPatrick Boettcher 		break;
3237173a64cbSPatrick Boettcher 
3238173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_9: /* 39 */
3239173a64cbSPatrick Boettcher 		if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
324039c1cb2bSJonathan McCrohan 			/* defines timeout for mpeg lock depending on interleaver length of longest layer */
3241173a64cbSPatrick Boettcher 			for (i = 0; i < 3; i++) {
3242c82056d0SMauro Carvalho Chehab 				if (c->layer[i].interleaving >= deeper_interleaver) {
32438af16adfSMauro Carvalho Chehab 					dprintk("layer%i: time interleaver = %d\n", i, c->layer[i].interleaving);
3244c82056d0SMauro Carvalho Chehab 					if (c->layer[i].segment_count > 0) { /* valid layer */
3245c82056d0SMauro Carvalho Chehab 						deeper_interleaver = c->layer[0].interleaving;
3246173a64cbSPatrick Boettcher 						state->longest_intlv_layer = i;
3247173a64cbSPatrick Boettcher 					}
3248173a64cbSPatrick Boettcher 				}
3249173a64cbSPatrick Boettcher 			}
3250173a64cbSPatrick Boettcher 
3251173a64cbSPatrick Boettcher 			if (deeper_interleaver == 0)
3252173a64cbSPatrick Boettcher 				locks = 2; /* locks is the tmp local variable name */
3253173a64cbSPatrick Boettcher 			else if (deeper_interleaver == 3)
3254173a64cbSPatrick Boettcher 				locks = 8;
3255173a64cbSPatrick Boettcher 			else
3256173a64cbSPatrick Boettcher 				locks = 2 * deeper_interleaver;
3257173a64cbSPatrick Boettcher 
3258173a64cbSPatrick Boettcher 			if (state->diversity_onoff != 0) /* because of diversity sync */
3259173a64cbSPatrick Boettcher 				locks *= 2;
3260173a64cbSPatrick Boettcher 
3261d6c62b76SMauro Carvalho Chehab 			*timeout = now + msecs_to_jiffies(200 * locks); /* give the mpeg lock 800ms if sram is present */
32628af16adfSMauro Carvalho Chehab 			dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %ld\n",
3263d6c62b76SMauro Carvalho Chehab 				deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
3264173a64cbSPatrick Boettcher 
3265173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_10;
3266173a64cbSPatrick Boettcher 		} else
3267173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STOP;
3268173a64cbSPatrick Boettcher 		break;
3269173a64cbSPatrick Boettcher 
3270173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_10: /* 40 */
3271173a64cbSPatrick Boettcher 		locks = dib8000_read_lock(fe);
3272173a64cbSPatrick Boettcher 		if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
32738af16adfSMauro Carvalho Chehab 			dprintk("ISDB-T layer locks: Layer A %s, Layer B %s, Layer C %s\n",
32743c0d394eSMauro Carvalho Chehab 				c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
32753c0d394eSMauro Carvalho Chehab 				c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
32763c0d394eSMauro Carvalho Chehab 				c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
3277746f7ae0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode
3278746f7ae0SMauro Carvalho Chehab 			    && c->isdbt_sb_subchannel < 14
3279746f7ae0SMauro Carvalho Chehab 			    && !state->differential_constellation)
3280173a64cbSPatrick Boettcher 				/* signal to the upper layer, that there was a channel found and the parameters can be read */
3281173a64cbSPatrick Boettcher 				state->status = FE_STATUS_DEMOD_SUCCESS;
3282173a64cbSPatrick Boettcher 			else
3283173a64cbSPatrick Boettcher 				state->status = FE_STATUS_DATA_LOCKED;
3284173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STOP;
3285d6c62b76SMauro Carvalho Chehab 		} else if (time_after(now, *timeout)) {
3286746f7ae0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode
3287746f7ae0SMauro Carvalho Chehab 			    && c->isdbt_sb_subchannel < 14
3288746f7ae0SMauro Carvalho Chehab 			    && !state->differential_constellation) { /* continue to try init prbs autosearch */
3289173a64cbSPatrick Boettcher 				state->subchannel += 3;
3290173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_11;
3291173a64cbSPatrick 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 */
3292173a64cbSPatrick Boettcher 				if (locks & (0x7 << 5)) {
32938af16adfSMauro Carvalho Chehab 					dprintk("Not all ISDB-T layers locked in %d ms: Layer A %s, Layer B %s, Layer C %s\n",
32943c0d394eSMauro Carvalho Chehab 						jiffies_to_msecs(now - *timeout),
32953c0d394eSMauro Carvalho Chehab 						c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
32963c0d394eSMauro Carvalho Chehab 						c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
32973c0d394eSMauro Carvalho Chehab 						c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
32983c0d394eSMauro Carvalho Chehab 
3299173a64cbSPatrick Boettcher 					state->status = FE_STATUS_DATA_LOCKED;
3300173a64cbSPatrick Boettcher 				} else
3301173a64cbSPatrick Boettcher 					state->status = FE_STATUS_TUNE_FAILED;
3302173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP;
3303173a64cbSPatrick Boettcher 			}
3304173a64cbSPatrick Boettcher 		}
3305173a64cbSPatrick Boettcher 		break;
3306173a64cbSPatrick Boettcher 
3307173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_11:  /* 41 : init prbs autosearch */
3308173a64cbSPatrick Boettcher 		if (state->subchannel <= 41) {
3309173a64cbSPatrick Boettcher 			dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
3310173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_9;
3311173a64cbSPatrick Boettcher 		} else {
3312173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STOP;
3313173a64cbSPatrick Boettcher 			state->status = FE_STATUS_TUNE_FAILED;
3314173a64cbSPatrick Boettcher 		}
3315173a64cbSPatrick Boettcher 		break;
3316173a64cbSPatrick Boettcher 
3317173a64cbSPatrick Boettcher 	default:
3318173a64cbSPatrick Boettcher 		break;
3319173a64cbSPatrick Boettcher 	}
3320173a64cbSPatrick Boettcher 
3321173a64cbSPatrick Boettcher 	/* tuning is finished - cleanup the demod */
3322173a64cbSPatrick Boettcher 	switch (*tune_state) {
3323173a64cbSPatrick Boettcher 	case CT_DEMOD_STOP: /* (42) */
3324173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3325173a64cbSPatrick Boettcher 		if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
3326173a64cbSPatrick Boettcher 			dib8000_write_word(state, 108, state->agc1_max);
3327173a64cbSPatrick Boettcher 			dib8000_write_word(state, 109, state->agc1_min);
3328173a64cbSPatrick Boettcher 			dib8000_write_word(state, 110, state->agc2_max);
3329173a64cbSPatrick Boettcher 			dib8000_write_word(state, 111, state->agc2_min);
3330173a64cbSPatrick Boettcher 			state->agc1_max = 0;
3331173a64cbSPatrick Boettcher 			state->agc1_min = 0;
3332173a64cbSPatrick Boettcher 			state->agc2_max = 0;
3333173a64cbSPatrick Boettcher 			state->agc2_min = 0;
3334173a64cbSPatrick Boettcher 		}
3335173a64cbSPatrick Boettcher #endif
3336d6c62b76SMauro Carvalho Chehab 		ret = 0;
3337173a64cbSPatrick Boettcher 		break;
3338173a64cbSPatrick Boettcher 	default:
3339173a64cbSPatrick Boettcher 		break;
3340173a64cbSPatrick Boettcher 	}
3341173a64cbSPatrick Boettcher 
3342173a64cbSPatrick Boettcher 	if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
3343173a64cbSPatrick Boettcher 		return ret * state->symbol_duration;
3344173a64cbSPatrick Boettcher 	if ((ret > 0) && (ret < state->symbol_duration))
3345173a64cbSPatrick Boettcher 		return state->symbol_duration; /* at least one symbol */
33469a0bf528SMauro Carvalho Chehab 	return ret;
33479a0bf528SMauro Carvalho Chehab }
33489a0bf528SMauro Carvalho Chehab 
33499a0bf528SMauro Carvalho Chehab static int dib8000_wakeup(struct dvb_frontend *fe)
33509a0bf528SMauro Carvalho Chehab {
33519a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
33529a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
33539a0bf528SMauro Carvalho Chehab 	int ret;
33549a0bf528SMauro Carvalho Chehab 
33559a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
33569a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_ADC_ON);
33579a0bf528SMauro Carvalho Chehab 	if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
33588af16adfSMauro Carvalho Chehab 		dprintk("could not start Slow ADC\n");
33599a0bf528SMauro Carvalho Chehab 
3360173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
33619a0bf528SMauro Carvalho Chehab 		dib8000_sad_calib(state);
33629a0bf528SMauro Carvalho Chehab 
33639a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
33649a0bf528SMauro Carvalho Chehab 		ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
33659a0bf528SMauro Carvalho Chehab 		if (ret < 0)
33669a0bf528SMauro Carvalho Chehab 			return ret;
33679a0bf528SMauro Carvalho Chehab 	}
33689a0bf528SMauro Carvalho Chehab 
33699a0bf528SMauro Carvalho Chehab 	return 0;
33709a0bf528SMauro Carvalho Chehab }
33719a0bf528SMauro Carvalho Chehab 
33729a0bf528SMauro Carvalho Chehab static int dib8000_sleep(struct dvb_frontend *fe)
33739a0bf528SMauro Carvalho Chehab {
33749a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
33759a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
33769a0bf528SMauro Carvalho Chehab 	int ret;
33779a0bf528SMauro Carvalho Chehab 
33789a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
33799a0bf528SMauro Carvalho Chehab 		ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
33809a0bf528SMauro Carvalho Chehab 		if (ret < 0)
33819a0bf528SMauro Carvalho Chehab 			return ret;
33829a0bf528SMauro Carvalho Chehab 	}
33839a0bf528SMauro Carvalho Chehab 
33849a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
33859a0bf528SMauro Carvalho Chehab 		dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
33869a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
33879a0bf528SMauro Carvalho Chehab 	return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
33889a0bf528SMauro Carvalho Chehab }
33899a0bf528SMauro Carvalho Chehab 
33900df289a2SMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat);
339170315b3eSMauro Carvalho Chehab 
33927e3e68bcSMauro Carvalho Chehab static int dib8000_get_frontend(struct dvb_frontend *fe,
33937e3e68bcSMauro Carvalho Chehab 				struct dtv_frontend_properties *c)
33949a0bf528SMauro Carvalho Chehab {
33959a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
33969a0bf528SMauro Carvalho Chehab 	u16 i, val = 0;
33970df289a2SMauro Carvalho Chehab 	enum fe_status stat = 0;
33989a0bf528SMauro Carvalho Chehab 	u8 index_frontend, sub_index_frontend;
33999a0bf528SMauro Carvalho Chehab 
34007e3e68bcSMauro Carvalho Chehab 	c->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 
34118af16adfSMauro Carvalho Chehab 	dprintk("dib8000_get_frontend: TMCC lock\n");
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) {
34158af16adfSMauro Carvalho Chehab 			dprintk("TMCC lock on the slave%i\n", index_frontend);
34169a0bf528SMauro Carvalho Chehab 			/* synchronize the cache with the other frontends */
34177e3e68bcSMauro Carvalho Chehab 			state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], c);
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 
34377e3e68bcSMauro Carvalho Chehab 	c->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);
34437e3e68bcSMauro Carvalho Chehab 	c->inversion = (val & 0x40) >> 6;
34449a0bf528SMauro Carvalho Chehab 	switch ((val & 0x30) >> 4) {
34459a0bf528SMauro Carvalho Chehab 	case 1:
34467e3e68bcSMauro Carvalho Chehab 		c->transmission_mode = TRANSMISSION_MODE_2K;
34478af16adfSMauro Carvalho Chehab 		dprintk("dib8000_get_frontend: transmission mode 2K\n");
34489a0bf528SMauro Carvalho Chehab 		break;
34497fec1c80SMauro Carvalho Chehab 	case 2:
34507e3e68bcSMauro Carvalho Chehab 		c->transmission_mode = TRANSMISSION_MODE_4K;
34518af16adfSMauro Carvalho Chehab 		dprintk("dib8000_get_frontend: transmission mode 4K\n");
34527fec1c80SMauro Carvalho Chehab 		break;
34539a0bf528SMauro Carvalho Chehab 	case 3:
34549a0bf528SMauro Carvalho Chehab 	default:
34557e3e68bcSMauro Carvalho Chehab 		c->transmission_mode = TRANSMISSION_MODE_8K;
34568af16adfSMauro Carvalho Chehab 		dprintk("dib8000_get_frontend: transmission mode 8K\n");
34579a0bf528SMauro Carvalho Chehab 		break;
34589a0bf528SMauro Carvalho Chehab 	}
34599a0bf528SMauro Carvalho Chehab 
34609a0bf528SMauro Carvalho Chehab 	switch (val & 0x3) {
34619a0bf528SMauro Carvalho Chehab 	case 0:
34627e3e68bcSMauro Carvalho Chehab 		c->guard_interval = GUARD_INTERVAL_1_32;
34638af16adfSMauro Carvalho Chehab 		dprintk("dib8000_get_frontend: Guard Interval = 1/32\n");
34649a0bf528SMauro Carvalho Chehab 		break;
34659a0bf528SMauro Carvalho Chehab 	case 1:
34667e3e68bcSMauro Carvalho Chehab 		c->guard_interval = GUARD_INTERVAL_1_16;
34678af16adfSMauro Carvalho Chehab 		dprintk("dib8000_get_frontend: Guard Interval = 1/16\n");
34689a0bf528SMauro Carvalho Chehab 		break;
34699a0bf528SMauro Carvalho Chehab 	case 2:
34708af16adfSMauro Carvalho Chehab 		dprintk("dib8000_get_frontend: Guard Interval = 1/8\n");
34717e3e68bcSMauro Carvalho Chehab 		c->guard_interval = GUARD_INTERVAL_1_8;
34729a0bf528SMauro Carvalho Chehab 		break;
34739a0bf528SMauro Carvalho Chehab 	case 3:
34748af16adfSMauro Carvalho Chehab 		dprintk("dib8000_get_frontend: Guard Interval = 1/4\n");
34757e3e68bcSMauro Carvalho Chehab 		c->guard_interval = GUARD_INTERVAL_1_4;
34769a0bf528SMauro Carvalho Chehab 		break;
34779a0bf528SMauro Carvalho Chehab 	}
34789a0bf528SMauro Carvalho Chehab 
34799a0bf528SMauro Carvalho Chehab 	val = dib8000_read_word(state, 505);
34807e3e68bcSMauro Carvalho Chehab 	c->isdbt_partial_reception = val & 1;
34818af16adfSMauro Carvalho Chehab 	dprintk("dib8000_get_frontend: partial_reception = %d\n", c->isdbt_partial_reception);
34829a0bf528SMauro Carvalho Chehab 
34839a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 3; i++) {
3484ecc31d55SMauro Carvalho Chehab 		int show;
3485ecc31d55SMauro Carvalho Chehab 
3486ecc31d55SMauro Carvalho Chehab 		val = dib8000_read_word(state, 493 + i) & 0x0f;
34877e3e68bcSMauro Carvalho Chehab 		c->layer[i].segment_count = val;
3488ecc31d55SMauro Carvalho Chehab 
3489ecc31d55SMauro Carvalho Chehab 		if (val == 0 || val > 13)
3490ecc31d55SMauro Carvalho Chehab 			show = 0;
3491ecc31d55SMauro Carvalho Chehab 		else
3492ecc31d55SMauro Carvalho Chehab 			show = 1;
3493ecc31d55SMauro Carvalho Chehab 
3494ecc31d55SMauro Carvalho Chehab 		if (show)
34958af16adfSMauro Carvalho Chehab 			dprintk("dib8000_get_frontend: Layer %d segments = %d\n",
34967e3e68bcSMauro Carvalho Chehab 				i, c->layer[i].segment_count);
34979a0bf528SMauro Carvalho Chehab 
349851fea113SMauro Carvalho Chehab 		val = dib8000_read_word(state, 499 + i) & 0x3;
349951fea113SMauro Carvalho Chehab 		/* Interleaving can be 0, 1, 2 or 4 */
350051fea113SMauro Carvalho Chehab 		if (val == 3)
350151fea113SMauro Carvalho Chehab 			val = 4;
35027e3e68bcSMauro Carvalho Chehab 		c->layer[i].interleaving = val;
3503ecc31d55SMauro Carvalho Chehab 		if (show)
35048af16adfSMauro Carvalho Chehab 			dprintk("dib8000_get_frontend: Layer %d time_intlv = %d\n",
35057e3e68bcSMauro Carvalho Chehab 				i, c->layer[i].interleaving);
35069a0bf528SMauro Carvalho Chehab 
35079a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 481 + i);
35089a0bf528SMauro Carvalho Chehab 		switch (val & 0x7) {
35099a0bf528SMauro Carvalho Chehab 		case 1:
35107e3e68bcSMauro Carvalho Chehab 			c->layer[i].fec = FEC_1_2;
3511ecc31d55SMauro Carvalho Chehab 			if (show)
35128af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d Code Rate = 1/2\n", i);
35139a0bf528SMauro Carvalho Chehab 			break;
35149a0bf528SMauro Carvalho Chehab 		case 2:
35157e3e68bcSMauro Carvalho Chehab 			c->layer[i].fec = FEC_2_3;
3516ecc31d55SMauro Carvalho Chehab 			if (show)
35178af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d Code Rate = 2/3\n", i);
35189a0bf528SMauro Carvalho Chehab 			break;
35199a0bf528SMauro Carvalho Chehab 		case 3:
35207e3e68bcSMauro Carvalho Chehab 			c->layer[i].fec = FEC_3_4;
3521ecc31d55SMauro Carvalho Chehab 			if (show)
35228af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d Code Rate = 3/4\n", i);
35239a0bf528SMauro Carvalho Chehab 			break;
35249a0bf528SMauro Carvalho Chehab 		case 5:
35257e3e68bcSMauro Carvalho Chehab 			c->layer[i].fec = FEC_5_6;
3526ecc31d55SMauro Carvalho Chehab 			if (show)
35278af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d Code Rate = 5/6\n", i);
35289a0bf528SMauro Carvalho Chehab 			break;
35299a0bf528SMauro Carvalho Chehab 		default:
35307e3e68bcSMauro Carvalho Chehab 			c->layer[i].fec = FEC_7_8;
3531ecc31d55SMauro Carvalho Chehab 			if (show)
35328af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d Code Rate = 7/8\n", i);
35339a0bf528SMauro Carvalho Chehab 			break;
35349a0bf528SMauro Carvalho Chehab 		}
35359a0bf528SMauro Carvalho Chehab 
35369a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 487 + i);
35379a0bf528SMauro Carvalho Chehab 		switch (val & 0x3) {
35389a0bf528SMauro Carvalho Chehab 		case 0:
35397e3e68bcSMauro Carvalho Chehab 			c->layer[i].modulation = DQPSK;
3540ecc31d55SMauro Carvalho Chehab 			if (show)
35418af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d DQPSK\n", i);
35429a0bf528SMauro Carvalho Chehab 			break;
35439a0bf528SMauro Carvalho Chehab 		case 1:
35447e3e68bcSMauro Carvalho Chehab 			c->layer[i].modulation = QPSK;
3545ecc31d55SMauro Carvalho Chehab 			if (show)
35468af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d QPSK\n", i);
35479a0bf528SMauro Carvalho Chehab 			break;
35489a0bf528SMauro Carvalho Chehab 		case 2:
35497e3e68bcSMauro Carvalho Chehab 			c->layer[i].modulation = QAM_16;
3550ecc31d55SMauro Carvalho Chehab 			if (show)
35518af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d QAM16\n", i);
35529a0bf528SMauro Carvalho Chehab 			break;
35539a0bf528SMauro Carvalho Chehab 		case 3:
35549a0bf528SMauro Carvalho Chehab 		default:
35557e3e68bcSMauro Carvalho Chehab 			c->layer[i].modulation = QAM_64;
3556ecc31d55SMauro Carvalho Chehab 			if (show)
35578af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d QAM64\n", i);
35589a0bf528SMauro Carvalho Chehab 			break;
35599a0bf528SMauro Carvalho Chehab 		}
35609a0bf528SMauro Carvalho Chehab 	}
35619a0bf528SMauro Carvalho Chehab 
35629a0bf528SMauro Carvalho Chehab 	/* synchronize the cache with the other frontends */
35639a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
35647e3e68bcSMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = c->isdbt_sb_mode;
35657e3e68bcSMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.inversion = c->inversion;
35667e3e68bcSMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.transmission_mode = c->transmission_mode;
35677e3e68bcSMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.guard_interval = c->guard_interval;
35687e3e68bcSMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = c->isdbt_partial_reception;
35699a0bf528SMauro Carvalho Chehab 		for (i = 0; i < 3; i++) {
35707e3e68bcSMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = c->layer[i].segment_count;
35717e3e68bcSMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = c->layer[i].interleaving;
35727e3e68bcSMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].fec = c->layer[i].fec;
35737e3e68bcSMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = c->layer[i].modulation;
35749a0bf528SMauro Carvalho Chehab 		}
35759a0bf528SMauro Carvalho Chehab 	}
35769a0bf528SMauro Carvalho Chehab 	return 0;
35779a0bf528SMauro Carvalho Chehab }
35789a0bf528SMauro Carvalho Chehab 
35799a0bf528SMauro Carvalho Chehab static int dib8000_set_frontend(struct dvb_frontend *fe)
35809a0bf528SMauro Carvalho Chehab {
35819a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
3582c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3583d6c62b76SMauro Carvalho Chehab 	int l, i, active, time, time_slave = 0;
3584173a64cbSPatrick Boettcher 	u8 exit_condition, index_frontend;
3585d6c62b76SMauro Carvalho Chehab 	unsigned long delay, callback_time;
35869a0bf528SMauro Carvalho Chehab 
3587c82056d0SMauro Carvalho Chehab 	if (c->frequency == 0) {
35888af16adfSMauro Carvalho Chehab 		dprintk("dib8000: must at least specify frequency\n");
35899a0bf528SMauro Carvalho Chehab 		return 0;
35909a0bf528SMauro Carvalho Chehab 	}
35919a0bf528SMauro Carvalho Chehab 
3592c82056d0SMauro Carvalho Chehab 	if (c->bandwidth_hz == 0) {
35938af16adfSMauro Carvalho Chehab 		dprintk("dib8000: no bandwidth specified, set to default\n");
3594c82056d0SMauro Carvalho Chehab 		c->bandwidth_hz = 6000000;
35959a0bf528SMauro Carvalho Chehab 	}
35969a0bf528SMauro Carvalho Chehab 
35979a0bf528SMauro Carvalho Chehab 	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
35989a0bf528SMauro Carvalho Chehab 		/* synchronization of the cache */
35999a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
36009a0bf528SMauro Carvalho Chehab 		memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
36019a0bf528SMauro Carvalho Chehab 
3602173a64cbSPatrick Boettcher 		/* set output mode and diversity input */
3603173a64cbSPatrick Boettcher 		if (state->revision != 0x8090) {
3604173a64cbSPatrick Boettcher 			dib8000_set_diversity_in(state->fe[index_frontend], 1);
3605173a64cbSPatrick Boettcher 			if (index_frontend != 0)
36069a0bf528SMauro Carvalho Chehab 				dib8000_set_output_mode(state->fe[index_frontend],
3607173a64cbSPatrick Boettcher 						OUTMODE_DIVERSITY);
36089a0bf528SMauro Carvalho Chehab 			else
3609173a64cbSPatrick Boettcher 				dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3610173a64cbSPatrick Boettcher 		} else {
3611173a64cbSPatrick Boettcher 			dib8096p_set_diversity_in(state->fe[index_frontend], 1);
3612173a64cbSPatrick Boettcher 			if (index_frontend != 0)
36139a0bf528SMauro Carvalho Chehab 				dib8096p_set_output_mode(state->fe[index_frontend],
3614173a64cbSPatrick Boettcher 						OUTMODE_DIVERSITY);
3615173a64cbSPatrick Boettcher 			else
3616173a64cbSPatrick Boettcher 				dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3617173a64cbSPatrick Boettcher 		}
3618173a64cbSPatrick Boettcher 
3619173a64cbSPatrick Boettcher 		/* tune the tuner */
36209a0bf528SMauro Carvalho Chehab 		if (state->fe[index_frontend]->ops.tuner_ops.set_params)
36219a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
36229a0bf528SMauro Carvalho Chehab 
36239a0bf528SMauro Carvalho Chehab 		dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
36249a0bf528SMauro Carvalho Chehab 	}
36259a0bf528SMauro Carvalho Chehab 
3626173a64cbSPatrick Boettcher 	/* turn off the diversity of the last chip */
3627173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
3628173a64cbSPatrick Boettcher 		dib8000_set_diversity_in(state->fe[index_frontend - 1], 0);
3629173a64cbSPatrick Boettcher 	else
3630173a64cbSPatrick Boettcher 		dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0);
3631173a64cbSPatrick Boettcher 
36329a0bf528SMauro Carvalho Chehab 	/* start up the AGC */
36339a0bf528SMauro Carvalho Chehab 	do {
36349a0bf528SMauro Carvalho Chehab 		time = dib8000_agc_startup(state->fe[0]);
36359a0bf528SMauro Carvalho Chehab 		for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
36369a0bf528SMauro Carvalho Chehab 			time_slave = dib8000_agc_startup(state->fe[index_frontend]);
3637d6c62b76SMauro Carvalho Chehab 			if (time == 0)
36389a0bf528SMauro Carvalho Chehab 				time = time_slave;
3639d6c62b76SMauro Carvalho Chehab 			else if ((time_slave != 0) && (time_slave > time))
36409a0bf528SMauro Carvalho Chehab 				time = time_slave;
36419a0bf528SMauro Carvalho Chehab 		}
3642d6c62b76SMauro Carvalho Chehab 		if (time == 0)
36439a0bf528SMauro Carvalho Chehab 			break;
36444607bb7aSMauro Carvalho Chehab 
36454607bb7aSMauro Carvalho Chehab 		/*
36464607bb7aSMauro Carvalho Chehab 		 * Despite dib8000_agc_startup returns time at a 0.1 ms range,
36474607bb7aSMauro Carvalho Chehab 		 * the actual sleep time depends on CONFIG_HZ. The worse case
36484607bb7aSMauro Carvalho Chehab 		 * is when CONFIG_HZ=100. In such case, the minimum granularity
36494607bb7aSMauro Carvalho Chehab 		 * is 10ms. On some real field tests, the tuner sometimes don't
36504607bb7aSMauro Carvalho Chehab 		 * lock when this timer is lower than 10ms. So, enforce a 10ms
36514607bb7aSMauro Carvalho Chehab 		 * granularity.
36524607bb7aSMauro Carvalho Chehab 		 */
36534607bb7aSMauro Carvalho Chehab 		time = 10 * (time + 99)/100;
36544607bb7aSMauro Carvalho Chehab 		usleep_range(time * 1000, (time + 1) * 1000);
36559a0bf528SMauro Carvalho Chehab 		exit_condition = 1;
36569a0bf528SMauro Carvalho Chehab 		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
36579a0bf528SMauro Carvalho Chehab 			if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
36589a0bf528SMauro Carvalho Chehab 				exit_condition = 0;
36599a0bf528SMauro Carvalho Chehab 				break;
36609a0bf528SMauro Carvalho Chehab 			}
36619a0bf528SMauro Carvalho Chehab 		}
36629a0bf528SMauro Carvalho Chehab 	} while (exit_condition == 0);
36639a0bf528SMauro Carvalho Chehab 
36649a0bf528SMauro Carvalho Chehab 	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
36659a0bf528SMauro Carvalho Chehab 		dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
36669a0bf528SMauro Carvalho Chehab 
3667173a64cbSPatrick Boettcher 	active = 1;
36689a0bf528SMauro Carvalho Chehab 	do {
3669d6c62b76SMauro Carvalho Chehab 		callback_time = 0;
36709a0bf528SMauro Carvalho Chehab 		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3671173a64cbSPatrick Boettcher 			delay = dib8000_tune(state->fe[index_frontend]);
3672d6c62b76SMauro Carvalho Chehab 			if (delay != 0) {
3673d6c62b76SMauro Carvalho Chehab 				delay = jiffies + usecs_to_jiffies(100 * delay);
3674d6c62b76SMauro Carvalho Chehab 				if (!callback_time || delay < callback_time)
3675d6c62b76SMauro Carvalho Chehab 					callback_time = delay;
3676d6c62b76SMauro Carvalho Chehab 			}
3677173a64cbSPatrick Boettcher 
3678173a64cbSPatrick Boettcher 			/* we are in autosearch */
3679173a64cbSPatrick Boettcher 			if (state->channel_parameters_set == 0) { /* searching */
3680173a64cbSPatrick Boettcher 				if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) {
36818af16adfSMauro Carvalho Chehab 					dprintk("autosearch succeeded on fe%i\n", index_frontend);
36827e3e68bcSMauro Carvalho Chehab 					dib8000_get_frontend(state->fe[index_frontend], c); /* we read the channel parameters from the frontend which was successful */
3683173a64cbSPatrick Boettcher 					state->channel_parameters_set = 1;
3684173a64cbSPatrick Boettcher 
3685173a64cbSPatrick Boettcher 					for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
3686173a64cbSPatrick Boettcher 						if (l != index_frontend) { /* and for all frontend except the successful one */
3687ecc31d55SMauro Carvalho Chehab 							dprintk("Restarting frontend %d\n", l);
3688173a64cbSPatrick Boettcher 							dib8000_tune_restart_from_demod(state->fe[l]);
3689173a64cbSPatrick Boettcher 
3690173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3691173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3692173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3693173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3694173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3695173a64cbSPatrick Boettcher 							for (i = 0; i < 3; i++) {
3696173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3697173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3698173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3699173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3700173a64cbSPatrick Boettcher 							}
3701173a64cbSPatrick Boettcher 
37029a0bf528SMauro Carvalho Chehab 						}
37039a0bf528SMauro Carvalho Chehab 					}
37049a0bf528SMauro Carvalho Chehab 				}
3705173a64cbSPatrick Boettcher 			}
3706173a64cbSPatrick Boettcher 		}
3707173a64cbSPatrick Boettcher 		/* tuning is done when the master frontend is done (failed or success) */
3708173a64cbSPatrick Boettcher 		if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
3709173a64cbSPatrick Boettcher 				dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED ||
3710173a64cbSPatrick Boettcher 				dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) {
3711173a64cbSPatrick Boettcher 			active = 0;
3712173a64cbSPatrick Boettcher 			/* we need to wait for all frontends to be finished */
3713173a64cbSPatrick Boettcher 			for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3714173a64cbSPatrick Boettcher 				if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP)
3715173a64cbSPatrick Boettcher 					active = 1;
3716173a64cbSPatrick Boettcher 			}
3717173a64cbSPatrick Boettcher 			if (active == 0)
37188af16adfSMauro Carvalho Chehab 				dprintk("tuning done with status %d\n", dib8000_get_status(state->fe[0]));
37199a0bf528SMauro Carvalho Chehab 		}
37209a0bf528SMauro Carvalho Chehab 
3721d6c62b76SMauro Carvalho Chehab 		if ((active == 1) && (callback_time == 0)) {
37228af16adfSMauro Carvalho Chehab 			dprintk("strange callback time something went wrong\n");
3723173a64cbSPatrick Boettcher 			active = 0;
37249a0bf528SMauro Carvalho Chehab 		}
37259a0bf528SMauro Carvalho Chehab 
3726d6c62b76SMauro Carvalho Chehab 		while ((active == 1) && (time_before(jiffies, callback_time)))
3727173a64cbSPatrick Boettcher 			msleep(100);
3728173a64cbSPatrick Boettcher 	} while (active);
37299a0bf528SMauro Carvalho Chehab 
3730173a64cbSPatrick Boettcher 	/* set output mode */
3731173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
37329a0bf528SMauro Carvalho Chehab 		dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
3733173a64cbSPatrick Boettcher 	else {
37349a0bf528SMauro Carvalho Chehab 		dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
37359a0bf528SMauro Carvalho Chehab 		if (state->cfg.enMpegOutput == 0) {
37369a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
37379a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
37389a0bf528SMauro Carvalho Chehab 		}
37399a0bf528SMauro Carvalho Chehab 	}
37409a0bf528SMauro Carvalho Chehab 
37414d8d5d92SGeert Uytterhoeven 	return 0;
37429a0bf528SMauro Carvalho Chehab }
37439a0bf528SMauro Carvalho Chehab 
37440df289a2SMauro Carvalho Chehab static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat);
37456ef06e78SMauro Carvalho Chehab 
37460df289a2SMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat)
37479a0bf528SMauro Carvalho Chehab {
37489a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37499a0bf528SMauro Carvalho Chehab 	u16 lock_slave = 0, lock;
37509a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
37519a0bf528SMauro Carvalho Chehab 
3752173a64cbSPatrick Boettcher 	lock = dib8000_read_lock(fe);
37539a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
37549a0bf528SMauro Carvalho Chehab 		lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
37559a0bf528SMauro Carvalho Chehab 
37569a0bf528SMauro Carvalho Chehab 	*stat = 0;
37579a0bf528SMauro Carvalho Chehab 
37589a0bf528SMauro Carvalho Chehab 	if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
37599a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SIGNAL;
37609a0bf528SMauro Carvalho Chehab 
37619a0bf528SMauro Carvalho Chehab 	if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
37629a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_CARRIER;
37639a0bf528SMauro Carvalho Chehab 
37649a0bf528SMauro Carvalho Chehab 	if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
37659a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SYNC;
37669a0bf528SMauro Carvalho Chehab 
37679a0bf528SMauro Carvalho Chehab 	if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
37689a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_LOCK;
37699a0bf528SMauro Carvalho Chehab 
37709a0bf528SMauro Carvalho Chehab 	if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
37719a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
37729a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
37739a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
37749a0bf528SMauro Carvalho Chehab 
37759a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
37769a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
37779a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
37789a0bf528SMauro Carvalho Chehab 
37799a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
37809a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
37819a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
37829a0bf528SMauro Carvalho Chehab 	}
37836ef06e78SMauro Carvalho Chehab 	dib8000_get_stats(fe, *stat);
37849a0bf528SMauro Carvalho Chehab 
37859a0bf528SMauro Carvalho Chehab 	return 0;
37869a0bf528SMauro Carvalho Chehab }
37879a0bf528SMauro Carvalho Chehab 
37889a0bf528SMauro Carvalho Chehab static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
37899a0bf528SMauro Carvalho Chehab {
37909a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37919a0bf528SMauro Carvalho Chehab 
37929a0bf528SMauro Carvalho Chehab 	/* 13 segments */
37939a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
37949a0bf528SMauro Carvalho Chehab 		*ber = (dib8000_read_word(state, 562) << 16) |
37959a0bf528SMauro Carvalho Chehab 			dib8000_read_word(state, 563);
37969a0bf528SMauro Carvalho Chehab 	else
37979a0bf528SMauro Carvalho Chehab 		*ber = (dib8000_read_word(state, 560) << 16) |
37989a0bf528SMauro Carvalho Chehab 			dib8000_read_word(state, 561);
37999a0bf528SMauro Carvalho Chehab 	return 0;
38009a0bf528SMauro Carvalho Chehab }
38019a0bf528SMauro Carvalho Chehab 
38029a0bf528SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
38039a0bf528SMauro Carvalho Chehab {
38049a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
38059a0bf528SMauro Carvalho Chehab 
38069a0bf528SMauro Carvalho Chehab 	/* packet error on 13 seg */
38079a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
38089a0bf528SMauro Carvalho Chehab 		*unc = dib8000_read_word(state, 567);
38099a0bf528SMauro Carvalho Chehab 	else
38109a0bf528SMauro Carvalho Chehab 		*unc = dib8000_read_word(state, 565);
38119a0bf528SMauro Carvalho Chehab 	return 0;
38129a0bf528SMauro Carvalho Chehab }
38139a0bf528SMauro Carvalho Chehab 
38149a0bf528SMauro Carvalho Chehab static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
38159a0bf528SMauro Carvalho Chehab {
38169a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
38179a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
38189a0bf528SMauro Carvalho Chehab 	u16 val;
38199a0bf528SMauro Carvalho Chehab 
38209a0bf528SMauro Carvalho Chehab 	*strength = 0;
38219a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
38229a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
38239a0bf528SMauro Carvalho Chehab 		if (val > 65535 - *strength)
38249a0bf528SMauro Carvalho Chehab 			*strength = 65535;
38259a0bf528SMauro Carvalho Chehab 		else
38269a0bf528SMauro Carvalho Chehab 			*strength += val;
38279a0bf528SMauro Carvalho Chehab 	}
38289a0bf528SMauro Carvalho Chehab 
38299a0bf528SMauro Carvalho Chehab 	val = 65535 - dib8000_read_word(state, 390);
38309a0bf528SMauro Carvalho Chehab 	if (val > 65535 - *strength)
38319a0bf528SMauro Carvalho Chehab 		*strength = 65535;
38329a0bf528SMauro Carvalho Chehab 	else
38339a0bf528SMauro Carvalho Chehab 		*strength += val;
38349a0bf528SMauro Carvalho Chehab 	return 0;
38359a0bf528SMauro Carvalho Chehab }
38369a0bf528SMauro Carvalho Chehab 
38379a0bf528SMauro Carvalho Chehab static u32 dib8000_get_snr(struct dvb_frontend *fe)
38389a0bf528SMauro Carvalho Chehab {
38399a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
38409a0bf528SMauro Carvalho Chehab 	u32 n, s, exp;
38419a0bf528SMauro Carvalho Chehab 	u16 val;
38429a0bf528SMauro Carvalho Chehab 
38439a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
38449a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 542);
38459a0bf528SMauro Carvalho Chehab 	else
38469a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 544);
38479a0bf528SMauro Carvalho Chehab 	n = (val >> 6) & 0xff;
38489a0bf528SMauro Carvalho Chehab 	exp = (val & 0x3f);
38499a0bf528SMauro Carvalho Chehab 	if ((exp & 0x20) != 0)
38509a0bf528SMauro Carvalho Chehab 		exp -= 0x40;
38519a0bf528SMauro Carvalho Chehab 	n <<= exp+16;
38529a0bf528SMauro Carvalho Chehab 
38539a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
38549a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 543);
38559a0bf528SMauro Carvalho Chehab 	else
38569a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 545);
38579a0bf528SMauro Carvalho Chehab 	s = (val >> 6) & 0xff;
38589a0bf528SMauro Carvalho Chehab 	exp = (val & 0x3f);
38599a0bf528SMauro Carvalho Chehab 	if ((exp & 0x20) != 0)
38609a0bf528SMauro Carvalho Chehab 		exp -= 0x40;
38619a0bf528SMauro Carvalho Chehab 	s <<= exp+16;
38629a0bf528SMauro Carvalho Chehab 
38639a0bf528SMauro Carvalho Chehab 	if (n > 0) {
38649a0bf528SMauro Carvalho Chehab 		u32 t = (s/n) << 16;
38659a0bf528SMauro Carvalho Chehab 		return t + ((s << 16) - n*t) / n;
38669a0bf528SMauro Carvalho Chehab 	}
38679a0bf528SMauro Carvalho Chehab 	return 0xffffffff;
38689a0bf528SMauro Carvalho Chehab }
38699a0bf528SMauro Carvalho Chehab 
38709a0bf528SMauro Carvalho Chehab static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
38719a0bf528SMauro Carvalho Chehab {
38729a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
38739a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
38749a0bf528SMauro Carvalho Chehab 	u32 snr_master;
38759a0bf528SMauro Carvalho Chehab 
38769a0bf528SMauro Carvalho Chehab 	snr_master = dib8000_get_snr(fe);
38779a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
38789a0bf528SMauro Carvalho Chehab 		snr_master += dib8000_get_snr(state->fe[index_frontend]);
38799a0bf528SMauro Carvalho Chehab 
38809a0bf528SMauro Carvalho Chehab 	if ((snr_master >> 16) != 0) {
38819a0bf528SMauro Carvalho Chehab 		snr_master = 10*intlog10(snr_master>>16);
38829a0bf528SMauro Carvalho Chehab 		*snr = snr_master / ((1 << 24) / 10);
38839a0bf528SMauro Carvalho Chehab 	}
38849a0bf528SMauro Carvalho Chehab 	else
38859a0bf528SMauro Carvalho Chehab 		*snr = 0;
38869a0bf528SMauro Carvalho Chehab 
38879a0bf528SMauro Carvalho Chehab 	return 0;
38889a0bf528SMauro Carvalho Chehab }
38899a0bf528SMauro Carvalho Chehab 
38906ef06e78SMauro Carvalho Chehab struct per_layer_regs {
38916ef06e78SMauro Carvalho Chehab 	u16 lock, ber, per;
38926ef06e78SMauro Carvalho Chehab };
38936ef06e78SMauro Carvalho Chehab 
38946ef06e78SMauro Carvalho Chehab static const struct per_layer_regs per_layer_regs[] = {
38956ef06e78SMauro Carvalho Chehab 	{ 554, 560, 562 },
38966ef06e78SMauro Carvalho Chehab 	{ 555, 576, 578 },
38976ef06e78SMauro Carvalho Chehab 	{ 556, 581, 583 },
38986ef06e78SMauro Carvalho Chehab };
38996ef06e78SMauro Carvalho Chehab 
390042ff76bdSMauro Carvalho Chehab struct linear_segments {
390142ff76bdSMauro Carvalho Chehab 	unsigned x;
390242ff76bdSMauro Carvalho Chehab 	signed y;
390342ff76bdSMauro Carvalho Chehab };
390442ff76bdSMauro Carvalho Chehab 
390542ff76bdSMauro Carvalho Chehab /*
390642ff76bdSMauro Carvalho Chehab  * Table to estimate signal strength in dBm.
390742ff76bdSMauro Carvalho Chehab  * This table was empirically determinated by measuring the signal
390842ff76bdSMauro Carvalho Chehab  * strength generated by a DTA-2111 RF generator directly connected into
390942ff76bdSMauro Carvalho Chehab  * a dib8076 device (a PixelView PV-D231U stick), using a good quality
391042ff76bdSMauro Carvalho Chehab  * 3 meters RC6 cable and good RC6 connectors.
391142ff76bdSMauro Carvalho Chehab  * The real value can actually be different on other devices, depending
391242ff76bdSMauro Carvalho Chehab  * on several factors, like if LNA is enabled or not, if diversity is
391342ff76bdSMauro Carvalho Chehab  * enabled, type of connectors, etc.
391442ff76bdSMauro Carvalho Chehab  * Yet, it is better to use this measure in dB than a random non-linear
391542ff76bdSMauro Carvalho Chehab  * percentage value, especially for antenna adjustments.
391642ff76bdSMauro Carvalho Chehab  * On my tests, the precision of the measure using this table is about
391742ff76bdSMauro Carvalho Chehab  * 0.5 dB, with sounds reasonable enough.
391842ff76bdSMauro Carvalho Chehab  */
391942ff76bdSMauro Carvalho Chehab static struct linear_segments strength_to_db_table[] = {
392042ff76bdSMauro Carvalho Chehab 	{ 55953, 108500 },	/* -22.5 dBm */
392142ff76bdSMauro Carvalho Chehab 	{ 55394, 108000 },
392242ff76bdSMauro Carvalho Chehab 	{ 53834, 107000 },
392342ff76bdSMauro Carvalho Chehab 	{ 52863, 106000 },
392442ff76bdSMauro Carvalho Chehab 	{ 52239, 105000 },
392542ff76bdSMauro Carvalho Chehab 	{ 52012, 104000 },
392642ff76bdSMauro Carvalho Chehab 	{ 51803, 103000 },
392742ff76bdSMauro Carvalho Chehab 	{ 51566, 102000 },
392842ff76bdSMauro Carvalho Chehab 	{ 51356, 101000 },
392942ff76bdSMauro Carvalho Chehab 	{ 51112, 100000 },
393042ff76bdSMauro Carvalho Chehab 	{ 50869,  99000 },
393142ff76bdSMauro Carvalho Chehab 	{ 50600,  98000 },
393242ff76bdSMauro Carvalho Chehab 	{ 50363,  97000 },
393342ff76bdSMauro Carvalho Chehab 	{ 50117,  96000 },	/* -35 dBm */
393442ff76bdSMauro Carvalho Chehab 	{ 49889,  95000 },
393542ff76bdSMauro Carvalho Chehab 	{ 49680,  94000 },
393642ff76bdSMauro Carvalho Chehab 	{ 49493,  93000 },
393742ff76bdSMauro Carvalho Chehab 	{ 49302,  92000 },
393842ff76bdSMauro Carvalho Chehab 	{ 48929,  91000 },
393942ff76bdSMauro Carvalho Chehab 	{ 48416,  90000 },
394042ff76bdSMauro Carvalho Chehab 	{ 48035,  89000 },
394142ff76bdSMauro Carvalho Chehab 	{ 47593,  88000 },
394242ff76bdSMauro Carvalho Chehab 	{ 47282,  87000 },
394342ff76bdSMauro Carvalho Chehab 	{ 46953,  86000 },
394442ff76bdSMauro Carvalho Chehab 	{ 46698,  85000 },
394542ff76bdSMauro Carvalho Chehab 	{ 45617,  84000 },
394642ff76bdSMauro Carvalho Chehab 	{ 44773,  83000 },
394742ff76bdSMauro Carvalho Chehab 	{ 43845,  82000 },
394842ff76bdSMauro Carvalho Chehab 	{ 43020,  81000 },
394942ff76bdSMauro Carvalho Chehab 	{ 42010,  80000 },	/* -51 dBm */
395042ff76bdSMauro Carvalho Chehab 	{     0,      0 },
395142ff76bdSMauro Carvalho Chehab };
395242ff76bdSMauro Carvalho Chehab 
395342ff76bdSMauro Carvalho Chehab static u32 interpolate_value(u32 value, struct linear_segments *segments,
395442ff76bdSMauro Carvalho Chehab 			     unsigned len)
395542ff76bdSMauro Carvalho Chehab {
395642ff76bdSMauro Carvalho Chehab 	u64 tmp64;
395742ff76bdSMauro Carvalho Chehab 	u32 dx;
395842ff76bdSMauro Carvalho Chehab 	s32 dy;
395942ff76bdSMauro Carvalho Chehab 	int i, ret;
396042ff76bdSMauro Carvalho Chehab 
396142ff76bdSMauro Carvalho Chehab 	if (value >= segments[0].x)
396242ff76bdSMauro Carvalho Chehab 		return segments[0].y;
396342ff76bdSMauro Carvalho Chehab 	if (value < segments[len-1].x)
396442ff76bdSMauro Carvalho Chehab 		return segments[len-1].y;
396542ff76bdSMauro Carvalho Chehab 
396642ff76bdSMauro Carvalho Chehab 	for (i = 1; i < len - 1; i++) {
396742ff76bdSMauro Carvalho Chehab 		/* If value is identical, no need to interpolate */
396842ff76bdSMauro Carvalho Chehab 		if (value == segments[i].x)
396942ff76bdSMauro Carvalho Chehab 			return segments[i].y;
397042ff76bdSMauro Carvalho Chehab 		if (value > segments[i].x)
397142ff76bdSMauro Carvalho Chehab 			break;
397242ff76bdSMauro Carvalho Chehab 	}
397342ff76bdSMauro Carvalho Chehab 
397442ff76bdSMauro Carvalho Chehab 	/* Linear interpolation between the two (x,y) points */
397542ff76bdSMauro Carvalho Chehab 	dy = segments[i - 1].y - segments[i].y;
397642ff76bdSMauro Carvalho Chehab 	dx = segments[i - 1].x - segments[i].x;
397742ff76bdSMauro Carvalho Chehab 
397842ff76bdSMauro Carvalho Chehab 	tmp64 = value - segments[i].x;
397942ff76bdSMauro Carvalho Chehab 	tmp64 *= dy;
398042ff76bdSMauro Carvalho Chehab 	do_div(tmp64, dx);
398142ff76bdSMauro Carvalho Chehab 	ret = segments[i].y + tmp64;
398242ff76bdSMauro Carvalho Chehab 
398342ff76bdSMauro Carvalho Chehab 	return ret;
398442ff76bdSMauro Carvalho Chehab }
398542ff76bdSMauro Carvalho Chehab 
3986704f01bbSMauro Carvalho Chehab static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer)
3987704f01bbSMauro Carvalho Chehab {
3988704f01bbSMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
3989704f01bbSMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3990704f01bbSMauro Carvalho Chehab 	int ini_layer, end_layer, i;
39914bf48150SMauro Carvalho Chehab 	u64 time_us, tmp64;
3992704f01bbSMauro Carvalho Chehab 	u32 tmp, denom;
3993e4a3bc1cSMauro Carvalho Chehab 	int guard, rate_num, rate_denum = 1, bits_per_symbol, nsegs;
3994e4a3bc1cSMauro Carvalho Chehab 	int interleaving = 0, fft_div;
3995704f01bbSMauro Carvalho Chehab 
3996704f01bbSMauro Carvalho Chehab 	if (layer >= 0) {
3997704f01bbSMauro Carvalho Chehab 		ini_layer = layer;
3998704f01bbSMauro Carvalho Chehab 		end_layer = layer + 1;
3999704f01bbSMauro Carvalho Chehab 	} else {
4000704f01bbSMauro Carvalho Chehab 		ini_layer = 0;
4001704f01bbSMauro Carvalho Chehab 		end_layer = 3;
4002704f01bbSMauro Carvalho Chehab 	}
4003704f01bbSMauro Carvalho Chehab 
4004704f01bbSMauro Carvalho Chehab 	switch (c->guard_interval) {
4005704f01bbSMauro Carvalho Chehab 	case GUARD_INTERVAL_1_4:
4006704f01bbSMauro Carvalho Chehab 		guard = 4;
4007704f01bbSMauro Carvalho Chehab 		break;
4008704f01bbSMauro Carvalho Chehab 	case GUARD_INTERVAL_1_8:
4009704f01bbSMauro Carvalho Chehab 		guard = 8;
4010704f01bbSMauro Carvalho Chehab 		break;
4011704f01bbSMauro Carvalho Chehab 	case GUARD_INTERVAL_1_16:
4012704f01bbSMauro Carvalho Chehab 		guard = 16;
4013704f01bbSMauro Carvalho Chehab 		break;
4014704f01bbSMauro Carvalho Chehab 	default:
4015704f01bbSMauro Carvalho Chehab 	case GUARD_INTERVAL_1_32:
4016704f01bbSMauro Carvalho Chehab 		guard = 32;
4017704f01bbSMauro Carvalho Chehab 		break;
4018704f01bbSMauro Carvalho Chehab 	}
4019704f01bbSMauro Carvalho Chehab 
4020704f01bbSMauro Carvalho Chehab 	switch (c->transmission_mode) {
4021704f01bbSMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
4022704f01bbSMauro Carvalho Chehab 		fft_div = 4;
4023704f01bbSMauro Carvalho Chehab 		break;
4024704f01bbSMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
4025704f01bbSMauro Carvalho Chehab 		fft_div = 2;
4026704f01bbSMauro Carvalho Chehab 		break;
4027704f01bbSMauro Carvalho Chehab 	default:
4028704f01bbSMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
4029704f01bbSMauro Carvalho Chehab 		fft_div = 1;
4030704f01bbSMauro Carvalho Chehab 		break;
4031704f01bbSMauro Carvalho Chehab 	}
4032704f01bbSMauro Carvalho Chehab 
4033704f01bbSMauro Carvalho Chehab 	denom = 0;
4034704f01bbSMauro Carvalho Chehab 	for (i = ini_layer; i < end_layer; i++) {
4035704f01bbSMauro Carvalho Chehab 		nsegs = c->layer[i].segment_count;
4036704f01bbSMauro Carvalho Chehab 		if (nsegs == 0 || nsegs > 13)
4037704f01bbSMauro Carvalho Chehab 			continue;
4038704f01bbSMauro Carvalho Chehab 
4039704f01bbSMauro Carvalho Chehab 		switch (c->layer[i].modulation) {
4040704f01bbSMauro Carvalho Chehab 		case DQPSK:
4041704f01bbSMauro Carvalho Chehab 		case QPSK:
4042704f01bbSMauro Carvalho Chehab 			bits_per_symbol = 2;
4043704f01bbSMauro Carvalho Chehab 			break;
4044704f01bbSMauro Carvalho Chehab 		case QAM_16:
4045704f01bbSMauro Carvalho Chehab 			bits_per_symbol = 4;
4046704f01bbSMauro Carvalho Chehab 			break;
4047704f01bbSMauro Carvalho Chehab 		default:
4048704f01bbSMauro Carvalho Chehab 		case QAM_64:
4049704f01bbSMauro Carvalho Chehab 			bits_per_symbol = 6;
4050704f01bbSMauro Carvalho Chehab 			break;
4051704f01bbSMauro Carvalho Chehab 		}
4052704f01bbSMauro Carvalho Chehab 
4053704f01bbSMauro Carvalho Chehab 		switch (c->layer[i].fec) {
4054704f01bbSMauro Carvalho Chehab 		case FEC_1_2:
4055704f01bbSMauro Carvalho Chehab 			rate_num = 1;
4056704f01bbSMauro Carvalho Chehab 			rate_denum = 2;
4057704f01bbSMauro Carvalho Chehab 			break;
4058704f01bbSMauro Carvalho Chehab 		case FEC_2_3:
4059704f01bbSMauro Carvalho Chehab 			rate_num = 2;
4060704f01bbSMauro Carvalho Chehab 			rate_denum = 3;
4061704f01bbSMauro Carvalho Chehab 			break;
4062704f01bbSMauro Carvalho Chehab 		case FEC_3_4:
4063704f01bbSMauro Carvalho Chehab 			rate_num = 3;
4064704f01bbSMauro Carvalho Chehab 			rate_denum = 4;
4065704f01bbSMauro Carvalho Chehab 			break;
4066704f01bbSMauro Carvalho Chehab 		case FEC_5_6:
4067704f01bbSMauro Carvalho Chehab 			rate_num = 5;
4068704f01bbSMauro Carvalho Chehab 			rate_denum = 6;
4069704f01bbSMauro Carvalho Chehab 			break;
4070704f01bbSMauro Carvalho Chehab 		default:
4071704f01bbSMauro Carvalho Chehab 		case FEC_7_8:
4072704f01bbSMauro Carvalho Chehab 			rate_num = 7;
4073704f01bbSMauro Carvalho Chehab 			rate_denum = 8;
4074704f01bbSMauro Carvalho Chehab 			break;
4075704f01bbSMauro Carvalho Chehab 		}
4076704f01bbSMauro Carvalho Chehab 
4077704f01bbSMauro Carvalho Chehab 		interleaving = c->layer[i].interleaving;
4078704f01bbSMauro Carvalho Chehab 
4079704f01bbSMauro Carvalho Chehab 		denom += bits_per_symbol * rate_num * fft_div * nsegs * 384;
4080704f01bbSMauro Carvalho Chehab 	}
4081704f01bbSMauro Carvalho Chehab 
4082704f01bbSMauro Carvalho Chehab 	/* If all goes wrong, wait for 1s for the next stats */
4083704f01bbSMauro Carvalho Chehab 	if (!denom)
4084704f01bbSMauro Carvalho Chehab 		return 0;
4085704f01bbSMauro Carvalho Chehab 
4086704f01bbSMauro Carvalho Chehab 	/* Estimate the period for the total bit rate */
4087704f01bbSMauro Carvalho Chehab 	time_us = rate_denum * (1008 * 1562500L);
40884bf48150SMauro Carvalho Chehab 	tmp64 = time_us;
40894bf48150SMauro Carvalho Chehab 	do_div(tmp64, guard);
40904bf48150SMauro Carvalho Chehab 	time_us = time_us + tmp64;
4091704f01bbSMauro Carvalho Chehab 	time_us += denom / 2;
4092704f01bbSMauro Carvalho Chehab 	do_div(time_us, denom);
4093704f01bbSMauro Carvalho Chehab 
4094704f01bbSMauro Carvalho Chehab 	tmp = 1008 * 96 * interleaving;
4095704f01bbSMauro Carvalho Chehab 	time_us += tmp + tmp / guard;
4096704f01bbSMauro Carvalho Chehab 
4097704f01bbSMauro Carvalho Chehab 	return time_us;
4098704f01bbSMauro Carvalho Chehab }
4099704f01bbSMauro Carvalho Chehab 
41000df289a2SMauro Carvalho Chehab static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat)
41016ef06e78SMauro Carvalho Chehab {
41026ef06e78SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
41036ef06e78SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
4104704f01bbSMauro Carvalho Chehab 	int i;
41050400c535SMauro Carvalho Chehab 	int show_per_stats = 0;
41060400c535SMauro Carvalho Chehab 	u32 time_us = 0, snr, val;
41070400c535SMauro Carvalho Chehab 	u64 blocks;
410842ff76bdSMauro Carvalho Chehab 	s32 db;
41096ef06e78SMauro Carvalho Chehab 	u16 strength;
41106ef06e78SMauro Carvalho Chehab 
41116ef06e78SMauro Carvalho Chehab 	/* Get Signal strength */
41126ef06e78SMauro Carvalho Chehab 	dib8000_read_signal_strength(fe, &strength);
411342ff76bdSMauro Carvalho Chehab 	val = strength;
411442ff76bdSMauro Carvalho Chehab 	db = interpolate_value(val,
411542ff76bdSMauro Carvalho Chehab 			       strength_to_db_table,
411642ff76bdSMauro Carvalho Chehab 			       ARRAY_SIZE(strength_to_db_table)) - 131000;
411742ff76bdSMauro Carvalho Chehab 	c->strength.stat[0].svalue = db;
41186ef06e78SMauro Carvalho Chehab 
4119704f01bbSMauro Carvalho Chehab 	/* UCB/BER/CNR measures require lock */
4120704f01bbSMauro Carvalho Chehab 	if (!(stat & FE_HAS_LOCK)) {
4121704f01bbSMauro Carvalho Chehab 		c->cnr.len = 1;
41220400c535SMauro Carvalho Chehab 		c->block_count.len = 1;
4123704f01bbSMauro Carvalho Chehab 		c->block_error.len = 1;
4124704f01bbSMauro Carvalho Chehab 		c->post_bit_error.len = 1;
4125704f01bbSMauro Carvalho Chehab 		c->post_bit_count.len = 1;
4126704f01bbSMauro Carvalho Chehab 		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4127704f01bbSMauro Carvalho Chehab 		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4128704f01bbSMauro Carvalho Chehab 		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4129704f01bbSMauro Carvalho Chehab 		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
41300400c535SMauro Carvalho Chehab 		c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
41316ef06e78SMauro Carvalho Chehab 		return 0;
4132704f01bbSMauro Carvalho Chehab 	}
4133704f01bbSMauro Carvalho Chehab 
4134704f01bbSMauro Carvalho Chehab 	/* Check if time for stats was elapsed */
41350400c535SMauro Carvalho Chehab 	if (time_after(jiffies, state->per_jiffies_stats)) {
41360400c535SMauro Carvalho Chehab 		state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
41376ef06e78SMauro Carvalho Chehab 
41386ef06e78SMauro Carvalho Chehab 		/* Get SNR */
41396ef06e78SMauro Carvalho Chehab 		snr = dib8000_get_snr(fe);
41406ef06e78SMauro Carvalho Chehab 		for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) {
41416ef06e78SMauro Carvalho Chehab 			if (state->fe[i])
41426ef06e78SMauro Carvalho Chehab 				snr += dib8000_get_snr(state->fe[i]);
41436ef06e78SMauro Carvalho Chehab 		}
41446ef06e78SMauro Carvalho Chehab 		snr = snr >> 16;
41456ef06e78SMauro Carvalho Chehab 
41466ef06e78SMauro Carvalho Chehab 		if (snr) {
41476ef06e78SMauro Carvalho Chehab 			snr = 10 * intlog10(snr);
41486ef06e78SMauro Carvalho Chehab 			snr = (1000L * snr) >> 24;
41496ef06e78SMauro Carvalho Chehab 		} else {
41506ef06e78SMauro Carvalho Chehab 			snr = 0;
41516ef06e78SMauro Carvalho Chehab 		}
41526ef06e78SMauro Carvalho Chehab 		c->cnr.stat[0].svalue = snr;
41536ef06e78SMauro Carvalho Chehab 		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
41546ef06e78SMauro Carvalho Chehab 
41550400c535SMauro Carvalho Chehab 		/* Get UCB measures */
41560400c535SMauro Carvalho Chehab 		dib8000_read_unc_blocks(fe, &val);
41570400c535SMauro Carvalho Chehab 		if (val < state->init_ucb)
41585dc8526bSMauro Carvalho Chehab 			state->init_ucb += 0x100000000LL;
41590400c535SMauro Carvalho Chehab 
41600400c535SMauro Carvalho Chehab 		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
41610400c535SMauro Carvalho Chehab 		c->block_error.stat[0].uvalue = val + state->init_ucb;
41620400c535SMauro Carvalho Chehab 
41630400c535SMauro Carvalho Chehab 		/* Estimate the number of packets based on bitrate */
41640400c535SMauro Carvalho Chehab 		if (!time_us)
41650400c535SMauro Carvalho Chehab 			time_us = dib8000_get_time_us(fe, -1);
41660400c535SMauro Carvalho Chehab 
41670400c535SMauro Carvalho Chehab 		if (time_us) {
41685dc8526bSMauro Carvalho Chehab 			blocks = 1250000ULL * 1000000ULL;
41690400c535SMauro Carvalho Chehab 			do_div(blocks, time_us * 8 * 204);
41700400c535SMauro Carvalho Chehab 			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
41710400c535SMauro Carvalho Chehab 			c->block_count.stat[0].uvalue += blocks;
41720400c535SMauro Carvalho Chehab 		}
41730400c535SMauro Carvalho Chehab 
41740400c535SMauro Carvalho Chehab 		show_per_stats = 1;
41750400c535SMauro Carvalho Chehab 	}
41760400c535SMauro Carvalho Chehab 
41770400c535SMauro Carvalho Chehab 	/* Get post-BER measures */
41780400c535SMauro Carvalho Chehab 	if (time_after(jiffies, state->ber_jiffies_stats)) {
41790400c535SMauro Carvalho Chehab 		time_us = dib8000_get_time_us(fe, -1);
41800400c535SMauro Carvalho Chehab 		state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
41810400c535SMauro Carvalho Chehab 
41828af16adfSMauro Carvalho Chehab 		dprintk("Next all layers stats available in %u us.\n", time_us);
41836ef06e78SMauro Carvalho Chehab 
41846ef06e78SMauro Carvalho Chehab 		dib8000_read_ber(fe, &val);
41856ef06e78SMauro Carvalho Chehab 		c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
41866ef06e78SMauro Carvalho Chehab 		c->post_bit_error.stat[0].uvalue += val;
41876ef06e78SMauro Carvalho Chehab 
41886ef06e78SMauro Carvalho Chehab 		c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
41896ef06e78SMauro Carvalho Chehab 		c->post_bit_count.stat[0].uvalue += 100000000;
4190704f01bbSMauro Carvalho Chehab 	}
41916ef06e78SMauro Carvalho Chehab 
41926ef06e78SMauro Carvalho Chehab 	if (state->revision < 0x8002)
41936ef06e78SMauro Carvalho Chehab 		return 0;
41946ef06e78SMauro Carvalho Chehab 
41956ef06e78SMauro Carvalho Chehab 	c->block_error.len = 4;
41966ef06e78SMauro Carvalho Chehab 	c->post_bit_error.len = 4;
41976ef06e78SMauro Carvalho Chehab 	c->post_bit_count.len = 4;
41986ef06e78SMauro Carvalho Chehab 
41996ef06e78SMauro Carvalho Chehab 	for (i = 0; i < 3; i++) {
42000400c535SMauro Carvalho Chehab 		unsigned nsegs = c->layer[i].segment_count;
42010400c535SMauro Carvalho Chehab 
42020400c535SMauro Carvalho Chehab 		if (nsegs == 0 || nsegs > 13)
4203704f01bbSMauro Carvalho Chehab 			continue;
4204704f01bbSMauro Carvalho Chehab 
42050400c535SMauro Carvalho Chehab 		time_us = 0;
42060400c535SMauro Carvalho Chehab 
42070400c535SMauro Carvalho Chehab 		if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) {
42080400c535SMauro Carvalho Chehab 			time_us = dib8000_get_time_us(fe, i);
42090400c535SMauro Carvalho Chehab 
42100400c535SMauro Carvalho Chehab 			state->ber_jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
4211704f01bbSMauro Carvalho Chehab 			dprintk("Next layer %c  stats will be available in %u us\n",
4212704f01bbSMauro Carvalho Chehab 				'A' + i, time_us);
4213704f01bbSMauro Carvalho Chehab 
42146ef06e78SMauro Carvalho Chehab 			val = dib8000_read_word(state, per_layer_regs[i].ber);
42156ef06e78SMauro Carvalho Chehab 			c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
42166ef06e78SMauro Carvalho Chehab 			c->post_bit_error.stat[1 + i].uvalue += val;
42176ef06e78SMauro Carvalho Chehab 
42186ef06e78SMauro Carvalho Chehab 			c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
42196ef06e78SMauro Carvalho Chehab 			c->post_bit_count.stat[1 + i].uvalue += 100000000;
42200400c535SMauro Carvalho Chehab 		}
42216ef06e78SMauro Carvalho Chehab 
42220400c535SMauro Carvalho Chehab 		if (show_per_stats) {
42236ef06e78SMauro Carvalho Chehab 			val = dib8000_read_word(state, per_layer_regs[i].per);
42246ef06e78SMauro Carvalho Chehab 
42256ef06e78SMauro Carvalho Chehab 			c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
42266ef06e78SMauro Carvalho Chehab 			c->block_error.stat[1 + i].uvalue += val;
42270400c535SMauro Carvalho Chehab 
42280400c535SMauro Carvalho Chehab 			if (!time_us)
42290400c535SMauro Carvalho Chehab 				time_us = dib8000_get_time_us(fe, i);
42300400c535SMauro Carvalho Chehab 			if (time_us) {
42315dc8526bSMauro Carvalho Chehab 				blocks = 1250000ULL * 1000000ULL;
42320400c535SMauro Carvalho Chehab 				do_div(blocks, time_us * 8 * 204);
42330400c535SMauro Carvalho Chehab 				c->block_count.stat[0].scale = FE_SCALE_COUNTER;
42340400c535SMauro Carvalho Chehab 				c->block_count.stat[0].uvalue += blocks;
42350400c535SMauro Carvalho Chehab 			}
42360400c535SMauro Carvalho Chehab 		}
42376ef06e78SMauro Carvalho Chehab 	}
42386ef06e78SMauro Carvalho Chehab 	return 0;
42396ef06e78SMauro Carvalho Chehab }
42406ef06e78SMauro Carvalho Chehab 
4241d44913c1SMauro Carvalho Chehab static int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
42429a0bf528SMauro Carvalho Chehab {
42439a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
42449a0bf528SMauro Carvalho Chehab 	u8 index_frontend = 1;
42459a0bf528SMauro Carvalho Chehab 
42469a0bf528SMauro Carvalho Chehab 	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
42479a0bf528SMauro Carvalho Chehab 		index_frontend++;
42489a0bf528SMauro Carvalho Chehab 	if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
42498af16adfSMauro Carvalho Chehab 		dprintk("set slave fe %p to index %i\n", fe_slave, index_frontend);
42509a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend] = fe_slave;
42519a0bf528SMauro Carvalho Chehab 		return 0;
42529a0bf528SMauro Carvalho Chehab 	}
42539a0bf528SMauro Carvalho Chehab 
42548af16adfSMauro Carvalho Chehab 	dprintk("too many slave frontend\n");
42559a0bf528SMauro Carvalho Chehab 	return -ENOMEM;
42569a0bf528SMauro Carvalho Chehab }
42579a0bf528SMauro Carvalho Chehab 
4258d44913c1SMauro Carvalho Chehab static int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
42599a0bf528SMauro Carvalho Chehab {
42609a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
42619a0bf528SMauro Carvalho Chehab 	u8 index_frontend = 1;
42629a0bf528SMauro Carvalho Chehab 
42639a0bf528SMauro Carvalho Chehab 	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
42649a0bf528SMauro Carvalho Chehab 		index_frontend++;
42659a0bf528SMauro Carvalho Chehab 	if (index_frontend != 1) {
42668af16adfSMauro Carvalho Chehab 		dprintk("remove slave fe %p (index %i)\n", state->fe[index_frontend-1], index_frontend-1);
42679a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend] = NULL;
42689a0bf528SMauro Carvalho Chehab 		return 0;
42699a0bf528SMauro Carvalho Chehab 	}
42709a0bf528SMauro Carvalho Chehab 
42718af16adfSMauro Carvalho Chehab 	dprintk("no frontend to be removed\n");
42729a0bf528SMauro Carvalho Chehab 	return -ENODEV;
42739a0bf528SMauro Carvalho Chehab }
42749a0bf528SMauro Carvalho Chehab 
4275d44913c1SMauro Carvalho Chehab static struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
42769a0bf528SMauro Carvalho Chehab {
42779a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
42789a0bf528SMauro Carvalho Chehab 
42799a0bf528SMauro Carvalho Chehab 	if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
42809a0bf528SMauro Carvalho Chehab 		return NULL;
42819a0bf528SMauro Carvalho Chehab 	return state->fe[slave_index];
42829a0bf528SMauro Carvalho Chehab }
42839a0bf528SMauro Carvalho Chehab 
4284d44913c1SMauro Carvalho Chehab static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
42859a0bf528SMauro Carvalho Chehab 		u8 default_addr, u8 first_addr, u8 is_dib8096p)
42869a0bf528SMauro Carvalho Chehab {
42879a0bf528SMauro Carvalho Chehab 	int k = 0, ret = 0;
42889a0bf528SMauro Carvalho Chehab 	u8 new_addr = 0;
42899a0bf528SMauro Carvalho Chehab 	struct i2c_device client = {.adap = host };
42909a0bf528SMauro Carvalho Chehab 
42919a0bf528SMauro Carvalho Chehab 	client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
42929a0bf528SMauro Carvalho Chehab 	if (!client.i2c_write_buffer) {
42938af16adfSMauro Carvalho Chehab 		dprintk("%s: not enough memory\n", __func__);
42949a0bf528SMauro Carvalho Chehab 		return -ENOMEM;
42959a0bf528SMauro Carvalho Chehab 	}
42969a0bf528SMauro Carvalho Chehab 	client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
42979a0bf528SMauro Carvalho Chehab 	if (!client.i2c_read_buffer) {
42988af16adfSMauro Carvalho Chehab 		dprintk("%s: not enough memory\n", __func__);
42999a0bf528SMauro Carvalho Chehab 		ret = -ENOMEM;
43009a0bf528SMauro Carvalho Chehab 		goto error_memory_read;
43019a0bf528SMauro Carvalho Chehab 	}
43029a0bf528SMauro Carvalho Chehab 	client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
43039a0bf528SMauro Carvalho Chehab 	if (!client.i2c_buffer_lock) {
43048af16adfSMauro Carvalho Chehab 		dprintk("%s: not enough memory\n", __func__);
43059a0bf528SMauro Carvalho Chehab 		ret = -ENOMEM;
43069a0bf528SMauro Carvalho Chehab 		goto error_memory_lock;
43079a0bf528SMauro Carvalho Chehab 	}
43089a0bf528SMauro Carvalho Chehab 	mutex_init(client.i2c_buffer_lock);
43099a0bf528SMauro Carvalho Chehab 
43109a0bf528SMauro Carvalho Chehab 	for (k = no_of_demods - 1; k >= 0; k--) {
43119a0bf528SMauro Carvalho Chehab 		/* designated i2c address */
43129a0bf528SMauro Carvalho Chehab 		new_addr = first_addr + (k << 1);
43139a0bf528SMauro Carvalho Chehab 
43149a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
43159a0bf528SMauro Carvalho Chehab 		if (!is_dib8096p)
43169a0bf528SMauro Carvalho Chehab 			dib8000_i2c_write16(&client, 1287, 0x0003);	/* sram lead in, rdy */
43179a0bf528SMauro Carvalho Chehab 		if (dib8000_identify(&client) == 0) {
43189a0bf528SMauro Carvalho Chehab 			/* sram lead in, rdy */
43199a0bf528SMauro Carvalho Chehab 			if (!is_dib8096p)
43209a0bf528SMauro Carvalho Chehab 				dib8000_i2c_write16(&client, 1287, 0x0003);
43219a0bf528SMauro Carvalho Chehab 			client.addr = default_addr;
43229a0bf528SMauro Carvalho Chehab 			if (dib8000_identify(&client) == 0) {
43238af16adfSMauro Carvalho Chehab 				dprintk("#%d: not identified\n", k);
43249a0bf528SMauro Carvalho Chehab 				ret  = -EINVAL;
43259a0bf528SMauro Carvalho Chehab 				goto error;
43269a0bf528SMauro Carvalho Chehab 			}
43279a0bf528SMauro Carvalho Chehab 		}
43289a0bf528SMauro Carvalho Chehab 
43299a0bf528SMauro Carvalho Chehab 		/* start diversity to pull_down div_str - just for i2c-enumeration */
43309a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
43319a0bf528SMauro Carvalho Chehab 
43329a0bf528SMauro Carvalho Chehab 		/* set new i2c address and force divstart */
43339a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
43349a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
43359a0bf528SMauro Carvalho Chehab 		dib8000_identify(&client);
43369a0bf528SMauro Carvalho Chehab 
43378af16adfSMauro Carvalho Chehab 		dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
43389a0bf528SMauro Carvalho Chehab 	}
43399a0bf528SMauro Carvalho Chehab 
43409a0bf528SMauro Carvalho Chehab 	for (k = 0; k < no_of_demods; k++) {
43419a0bf528SMauro Carvalho Chehab 		new_addr = first_addr | (k << 1);
43429a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
43439a0bf528SMauro Carvalho Chehab 
43449a0bf528SMauro Carvalho Chehab 		// unforce divstr
43459a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1285, new_addr << 2);
43469a0bf528SMauro Carvalho Chehab 
43479a0bf528SMauro Carvalho Chehab 		/* deactivate div - it was just for i2c-enumeration */
43489a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1286, 0);
43499a0bf528SMauro Carvalho Chehab 	}
43509a0bf528SMauro Carvalho Chehab 
43519a0bf528SMauro Carvalho Chehab error:
43529a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_buffer_lock);
43539a0bf528SMauro Carvalho Chehab error_memory_lock:
43549a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_read_buffer);
43559a0bf528SMauro Carvalho Chehab error_memory_read:
43569a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_write_buffer);
43579a0bf528SMauro Carvalho Chehab 
43589a0bf528SMauro Carvalho Chehab 	return ret;
43599a0bf528SMauro Carvalho Chehab }
43609a0bf528SMauro Carvalho Chehab 
43619a0bf528SMauro Carvalho Chehab static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
43629a0bf528SMauro Carvalho Chehab {
43639a0bf528SMauro Carvalho Chehab 	tune->min_delay_ms = 1000;
43649a0bf528SMauro Carvalho Chehab 	tune->step_size = 0;
43659a0bf528SMauro Carvalho Chehab 	tune->max_drift = 0;
43669a0bf528SMauro Carvalho Chehab 	return 0;
43679a0bf528SMauro Carvalho Chehab }
43689a0bf528SMauro Carvalho Chehab 
43699a0bf528SMauro Carvalho Chehab static void dib8000_release(struct dvb_frontend *fe)
43709a0bf528SMauro Carvalho Chehab {
43719a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
43729a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
43739a0bf528SMauro Carvalho Chehab 
43749a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
43759a0bf528SMauro Carvalho Chehab 		dvb_frontend_detach(st->fe[index_frontend]);
43769a0bf528SMauro Carvalho Chehab 
43779a0bf528SMauro Carvalho Chehab 	dibx000_exit_i2c_master(&st->i2c_master);
43789a0bf528SMauro Carvalho Chehab 	i2c_del_adapter(&st->dib8096p_tuner_adap);
43799a0bf528SMauro Carvalho Chehab 	kfree(st->fe[0]);
43809a0bf528SMauro Carvalho Chehab 	kfree(st);
43819a0bf528SMauro Carvalho Chehab }
43829a0bf528SMauro Carvalho Chehab 
4383d44913c1SMauro Carvalho Chehab static struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
43849a0bf528SMauro Carvalho Chehab {
43859a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
43869a0bf528SMauro Carvalho Chehab 	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
43879a0bf528SMauro Carvalho Chehab }
43889a0bf528SMauro Carvalho Chehab 
4389d44913c1SMauro Carvalho Chehab static int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
43909a0bf528SMauro Carvalho Chehab {
43919a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
43929a0bf528SMauro Carvalho Chehab 	u16 val = dib8000_read_word(st, 299) & 0xffef;
43939a0bf528SMauro Carvalho Chehab 	val |= (onoff & 0x1) << 4;
43949a0bf528SMauro Carvalho Chehab 
43958af16adfSMauro Carvalho Chehab 	dprintk("pid filter enabled %d\n", onoff);
43969a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(st, 299, val);
43979a0bf528SMauro Carvalho Chehab }
43989a0bf528SMauro Carvalho Chehab 
4399d44913c1SMauro Carvalho Chehab static int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
44009a0bf528SMauro Carvalho Chehab {
44019a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
44028af16adfSMauro Carvalho Chehab 	dprintk("Index %x, PID %d, OnOff %d\n", id, pid, onoff);
44039a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
44049a0bf528SMauro Carvalho Chehab }
44059a0bf528SMauro Carvalho Chehab 
44069a0bf528SMauro Carvalho Chehab static const struct dvb_frontend_ops dib8000_ops = {
44079a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ISDBT },
44089a0bf528SMauro Carvalho Chehab 	.info = {
44099a0bf528SMauro Carvalho Chehab 		 .name = "DiBcom 8000 ISDB-T",
44109a0bf528SMauro Carvalho Chehab 		 .frequency_min = 44250000,
44119a0bf528SMauro Carvalho Chehab 		 .frequency_max = 867250000,
44129a0bf528SMauro Carvalho Chehab 		 .frequency_stepsize = 62500,
44139a0bf528SMauro Carvalho Chehab 		 .caps = FE_CAN_INVERSION_AUTO |
44149a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
44159a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
44169a0bf528SMauro Carvalho Chehab 		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
44179a0bf528SMauro Carvalho Chehab 		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
44189a0bf528SMauro Carvalho Chehab 		 },
44199a0bf528SMauro Carvalho Chehab 
44209a0bf528SMauro Carvalho Chehab 	.release = dib8000_release,
44219a0bf528SMauro Carvalho Chehab 
44229a0bf528SMauro Carvalho Chehab 	.init = dib8000_wakeup,
44239a0bf528SMauro Carvalho Chehab 	.sleep = dib8000_sleep,
44249a0bf528SMauro Carvalho Chehab 
44259a0bf528SMauro Carvalho Chehab 	.set_frontend = dib8000_set_frontend,
44269a0bf528SMauro Carvalho Chehab 	.get_tune_settings = dib8000_fe_get_tune_settings,
44279a0bf528SMauro Carvalho Chehab 	.get_frontend = dib8000_get_frontend,
44289a0bf528SMauro Carvalho Chehab 
44299a0bf528SMauro Carvalho Chehab 	.read_status = dib8000_read_status,
44309a0bf528SMauro Carvalho Chehab 	.read_ber = dib8000_read_ber,
44319a0bf528SMauro Carvalho Chehab 	.read_signal_strength = dib8000_read_signal_strength,
44329a0bf528SMauro Carvalho Chehab 	.read_snr = dib8000_read_snr,
44339a0bf528SMauro Carvalho Chehab 	.read_ucblocks = dib8000_read_unc_blocks,
44349a0bf528SMauro Carvalho Chehab };
44359a0bf528SMauro Carvalho Chehab 
4436d44913c1SMauro Carvalho Chehab static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
44379a0bf528SMauro Carvalho Chehab {
44389a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *fe;
44399a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state;
44409a0bf528SMauro Carvalho Chehab 
44418af16adfSMauro Carvalho Chehab 	dprintk("dib8000_init\n");
44429a0bf528SMauro Carvalho Chehab 
44439a0bf528SMauro Carvalho Chehab 	state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
44449a0bf528SMauro Carvalho Chehab 	if (state == NULL)
44459a0bf528SMauro Carvalho Chehab 		return NULL;
44469a0bf528SMauro Carvalho Chehab 	fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
44479a0bf528SMauro Carvalho Chehab 	if (fe == NULL)
44489a0bf528SMauro Carvalho Chehab 		goto error;
44499a0bf528SMauro Carvalho Chehab 
44509a0bf528SMauro Carvalho Chehab 	memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
44519a0bf528SMauro Carvalho Chehab 	state->i2c.adap = i2c_adap;
44529a0bf528SMauro Carvalho Chehab 	state->i2c.addr = i2c_addr;
44539a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_write_buffer = state->i2c_write_buffer;
44549a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_read_buffer = state->i2c_read_buffer;
44559a0bf528SMauro Carvalho Chehab 	mutex_init(&state->i2c_buffer_lock);
44569a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
44579a0bf528SMauro Carvalho Chehab 	state->gpio_val = cfg->gpio_val;
44589a0bf528SMauro Carvalho Chehab 	state->gpio_dir = cfg->gpio_dir;
44599a0bf528SMauro Carvalho Chehab 
44609a0bf528SMauro Carvalho Chehab 	/* Ensure the output mode remains at the previous default if it's
44619a0bf528SMauro Carvalho Chehab 	 * not specifically set by the caller.
44629a0bf528SMauro Carvalho Chehab 	 */
44639a0bf528SMauro Carvalho Chehab 	if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
44649a0bf528SMauro Carvalho Chehab 		state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
44659a0bf528SMauro Carvalho Chehab 
44669a0bf528SMauro Carvalho Chehab 	state->fe[0] = fe;
44679a0bf528SMauro Carvalho Chehab 	fe->demodulator_priv = state;
44689a0bf528SMauro Carvalho Chehab 	memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
44699a0bf528SMauro Carvalho Chehab 
44709a0bf528SMauro Carvalho Chehab 	state->timf_default = cfg->pll->timf;
44719a0bf528SMauro Carvalho Chehab 
44729a0bf528SMauro Carvalho Chehab 	if (dib8000_identify(&state->i2c) == 0)
44739a0bf528SMauro Carvalho Chehab 		goto error;
44749a0bf528SMauro Carvalho Chehab 
44759a0bf528SMauro Carvalho Chehab 	dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
44769a0bf528SMauro Carvalho Chehab 
44779a0bf528SMauro Carvalho Chehab 	/* init 8096p tuner adapter */
44789a0bf528SMauro Carvalho Chehab 	strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
44799a0bf528SMauro Carvalho Chehab 			sizeof(state->dib8096p_tuner_adap.name));
44809a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
44819a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.algo_data = NULL;
44829a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
44839a0bf528SMauro Carvalho Chehab 	i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
44849a0bf528SMauro Carvalho Chehab 	i2c_add_adapter(&state->dib8096p_tuner_adap);
44859a0bf528SMauro Carvalho Chehab 
44869a0bf528SMauro Carvalho Chehab 	dib8000_reset(fe);
44879a0bf528SMauro Carvalho Chehab 
44889a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));	/* ber_rs_len = 3 */
4489173a64cbSPatrick Boettcher 	state->current_demod_bw = 6000;
44909a0bf528SMauro Carvalho Chehab 
44919a0bf528SMauro Carvalho Chehab 	return fe;
44929a0bf528SMauro Carvalho Chehab 
44939a0bf528SMauro Carvalho Chehab error:
44949a0bf528SMauro Carvalho Chehab 	kfree(state);
44959a0bf528SMauro Carvalho Chehab 	return NULL;
44969a0bf528SMauro Carvalho Chehab }
44979a0bf528SMauro Carvalho Chehab 
4498d44913c1SMauro Carvalho Chehab void *dib8000_attach(struct dib8000_ops *ops)
4499d44913c1SMauro Carvalho Chehab {
4500d44913c1SMauro Carvalho Chehab 	if (!ops)
4501d44913c1SMauro Carvalho Chehab 		return NULL;
4502d44913c1SMauro Carvalho Chehab 
4503d44913c1SMauro Carvalho Chehab 	ops->pwm_agc_reset = dib8000_pwm_agc_reset;
4504d44913c1SMauro Carvalho Chehab 	ops->get_dc_power = dib8090p_get_dc_power;
4505d44913c1SMauro Carvalho Chehab 	ops->set_gpio = dib8000_set_gpio;
4506d44913c1SMauro Carvalho Chehab 	ops->get_slave_frontend = dib8000_get_slave_frontend;
4507d44913c1SMauro Carvalho Chehab 	ops->set_tune_state = dib8000_set_tune_state;
4508d44913c1SMauro Carvalho Chehab 	ops->pid_filter_ctrl = dib8000_pid_filter_ctrl;
4509d44913c1SMauro Carvalho Chehab 	ops->remove_slave_frontend = dib8000_remove_slave_frontend;
4510d44913c1SMauro Carvalho Chehab 	ops->get_adc_power = dib8000_get_adc_power;
4511d44913c1SMauro Carvalho Chehab 	ops->update_pll = dib8000_update_pll;
4512d44913c1SMauro Carvalho Chehab 	ops->tuner_sleep = dib8096p_tuner_sleep;
4513d44913c1SMauro Carvalho Chehab 	ops->get_tune_state = dib8000_get_tune_state;
4514d44913c1SMauro Carvalho Chehab 	ops->get_i2c_tuner = dib8096p_get_i2c_tuner;
4515d44913c1SMauro Carvalho Chehab 	ops->set_slave_frontend = dib8000_set_slave_frontend;
4516d44913c1SMauro Carvalho Chehab 	ops->pid_filter = dib8000_pid_filter;
4517d44913c1SMauro Carvalho Chehab 	ops->ctrl_timf = dib8000_ctrl_timf;
4518d44913c1SMauro Carvalho Chehab 	ops->init = dib8000_init;
4519d44913c1SMauro Carvalho Chehab 	ops->get_i2c_master = dib8000_get_i2c_master;
4520d44913c1SMauro Carvalho Chehab 	ops->i2c_enumeration = dib8000_i2c_enumeration;
4521d44913c1SMauro Carvalho Chehab 	ops->set_wbd_ref = dib8000_set_wbd_ref;
4522d44913c1SMauro Carvalho Chehab 
4523d44913c1SMauro Carvalho Chehab 	return ops;
4524d44913c1SMauro Carvalho Chehab }
4525d44913c1SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_attach);
45269a0bf528SMauro Carvalho Chehab 
452799e44da7SPatrick Boettcher MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@parrot.com, Patrick Boettcher <patrick.boettcher@posteo.de>");
45289a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
45299a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
4530