1a10e763bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
29a0bf528SMauro Carvalho Chehab /*
39a0bf528SMauro Carvalho Chehab  * Linux-DVB Driver for DiBcom's DiB8000 chip (ISDB-T).
49a0bf528SMauro Carvalho Chehab  *
59a0bf528SMauro Carvalho Chehab  * Copyright (C) 2009 DiBcom (http://www.dibcom.fr/)
69a0bf528SMauro Carvalho Chehab  */
78af16adfSMauro Carvalho Chehab 
88af16adfSMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
98af16adfSMauro Carvalho Chehab 
109a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
119a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
129a0bf528SMauro Carvalho Chehab #include <linux/i2c.h>
139a0bf528SMauro Carvalho Chehab #include <linux/mutex.h>
14b4600d70SMauro Carvalho Chehab #include <asm/div64.h>
159a0bf528SMauro Carvalho Chehab 
16f97fa3dcSAndy Shevchenko #include <linux/int_log.h>
179a0bf528SMauro Carvalho Chehab 
18fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
199a0bf528SMauro Carvalho Chehab 
209a0bf528SMauro Carvalho Chehab #include "dib8000.h"
219a0bf528SMauro Carvalho Chehab 
229a0bf528SMauro Carvalho Chehab #define LAYER_ALL -1
239a0bf528SMauro Carvalho Chehab #define LAYER_A   1
249a0bf528SMauro Carvalho Chehab #define LAYER_B   2
259a0bf528SMauro Carvalho Chehab #define LAYER_C   3
269a0bf528SMauro Carvalho Chehab 
279a0bf528SMauro Carvalho Chehab #define MAX_NUMBER_OF_FRONTENDS 6
28173a64cbSPatrick Boettcher /* #define DIB8000_AGC_FREEZE */
299a0bf528SMauro Carvalho Chehab 
309a0bf528SMauro Carvalho Chehab static int debug;
319a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
329a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
339a0bf528SMauro Carvalho Chehab 
348af16adfSMauro Carvalho Chehab #define dprintk(fmt, arg...) do {					\
358af16adfSMauro Carvalho Chehab 	if (debug)							\
368af16adfSMauro Carvalho Chehab 		printk(KERN_DEBUG pr_fmt("%s: " fmt),			\
378af16adfSMauro Carvalho Chehab 		       __func__, ##arg);				\
388af16adfSMauro Carvalho Chehab } while (0)
399a0bf528SMauro Carvalho Chehab 
409a0bf528SMauro Carvalho Chehab struct i2c_device {
419a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *adap;
429a0bf528SMauro Carvalho Chehab 	u8 addr;
439a0bf528SMauro Carvalho Chehab 	u8 *i2c_write_buffer;
449a0bf528SMauro Carvalho Chehab 	u8 *i2c_read_buffer;
459a0bf528SMauro Carvalho Chehab 	struct mutex *i2c_buffer_lock;
469a0bf528SMauro Carvalho Chehab };
479a0bf528SMauro Carvalho Chehab 
48173a64cbSPatrick Boettcher enum param_loop_step {
49173a64cbSPatrick Boettcher 	LOOP_TUNE_1,
50173a64cbSPatrick Boettcher 	LOOP_TUNE_2
51173a64cbSPatrick Boettcher };
52173a64cbSPatrick Boettcher 
53173a64cbSPatrick Boettcher enum dib8000_autosearch_step {
54173a64cbSPatrick Boettcher 	AS_START = 0,
55173a64cbSPatrick Boettcher 	AS_SEARCHING_FFT,
56173a64cbSPatrick Boettcher 	AS_SEARCHING_GUARD,
57173a64cbSPatrick Boettcher 	AS_DONE = 100,
58173a64cbSPatrick Boettcher };
59173a64cbSPatrick Boettcher 
60173a64cbSPatrick Boettcher enum timeout_mode {
61173a64cbSPatrick Boettcher 	SYMBOL_DEPENDENT_OFF = 0,
62173a64cbSPatrick Boettcher 	SYMBOL_DEPENDENT_ON,
63173a64cbSPatrick Boettcher };
64173a64cbSPatrick Boettcher 
659a0bf528SMauro Carvalho Chehab struct dib8000_state {
669a0bf528SMauro Carvalho Chehab 	struct dib8000_config cfg;
679a0bf528SMauro Carvalho Chehab 
689a0bf528SMauro Carvalho Chehab 	struct i2c_device i2c;
699a0bf528SMauro Carvalho Chehab 
709a0bf528SMauro Carvalho Chehab 	struct dibx000_i2c_master i2c_master;
719a0bf528SMauro Carvalho Chehab 
729a0bf528SMauro Carvalho Chehab 	u16 wbd_ref;
739a0bf528SMauro Carvalho Chehab 
749a0bf528SMauro Carvalho Chehab 	u8 current_band;
759a0bf528SMauro Carvalho Chehab 	u32 current_bandwidth;
769a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *current_agc;
779a0bf528SMauro Carvalho Chehab 	u32 timf;
789a0bf528SMauro Carvalho Chehab 	u32 timf_default;
799a0bf528SMauro Carvalho Chehab 
809a0bf528SMauro Carvalho Chehab 	u8 div_force_off:1;
819a0bf528SMauro Carvalho Chehab 	u8 div_state:1;
829a0bf528SMauro Carvalho Chehab 	u16 div_sync_wait;
839a0bf528SMauro Carvalho Chehab 
849a0bf528SMauro Carvalho Chehab 	u8 agc_state;
859a0bf528SMauro Carvalho Chehab 	u8 differential_constellation;
869a0bf528SMauro Carvalho Chehab 	u8 diversity_onoff;
879a0bf528SMauro Carvalho Chehab 
889a0bf528SMauro Carvalho Chehab 	s16 ber_monitored_layer;
899a0bf528SMauro Carvalho Chehab 	u16 gpio_dir;
909a0bf528SMauro Carvalho Chehab 	u16 gpio_val;
919a0bf528SMauro Carvalho Chehab 
929a0bf528SMauro Carvalho Chehab 	u16 revision;
939a0bf528SMauro Carvalho Chehab 	u8 isdbt_cfg_loaded;
949a0bf528SMauro Carvalho Chehab 	enum frontend_tune_state tune_state;
95173a64cbSPatrick Boettcher 	s32 status;
969a0bf528SMauro Carvalho Chehab 
979a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
989a0bf528SMauro Carvalho Chehab 
999a0bf528SMauro Carvalho Chehab 	/* for the I2C transfer */
1009a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2];
1019a0bf528SMauro Carvalho Chehab 	u8 i2c_write_buffer[4];
1029a0bf528SMauro Carvalho Chehab 	u8 i2c_read_buffer[2];
1039a0bf528SMauro Carvalho Chehab 	struct mutex i2c_buffer_lock;
1049a0bf528SMauro Carvalho Chehab 	u8 input_mode_mpeg;
1059a0bf528SMauro Carvalho Chehab 
1069a0bf528SMauro Carvalho Chehab 	u16 tuner_enable;
1079a0bf528SMauro Carvalho Chehab 	struct i2c_adapter dib8096p_tuner_adap;
108173a64cbSPatrick Boettcher 	u16 current_demod_bw;
109173a64cbSPatrick Boettcher 
110173a64cbSPatrick Boettcher 	u16 seg_mask;
111173a64cbSPatrick Boettcher 	u16 seg_diff_mask;
112173a64cbSPatrick Boettcher 	u16 mode;
113173a64cbSPatrick Boettcher 	u8 layer_b_nb_seg;
114173a64cbSPatrick Boettcher 	u8 layer_c_nb_seg;
115173a64cbSPatrick Boettcher 
116173a64cbSPatrick Boettcher 	u8 channel_parameters_set;
117173a64cbSPatrick Boettcher 	u16 autosearch_state;
118173a64cbSPatrick Boettcher 	u16 found_nfft;
119173a64cbSPatrick Boettcher 	u16 found_guard;
120173a64cbSPatrick Boettcher 	u8 subchannel;
121173a64cbSPatrick Boettcher 	u8 symbol_duration;
122d6c62b76SMauro Carvalho Chehab 	unsigned long timeout;
123173a64cbSPatrick Boettcher 	u8 longest_intlv_layer;
124173a64cbSPatrick Boettcher 	u16 output_mode;
125173a64cbSPatrick Boettcher 
126704f01bbSMauro Carvalho Chehab 	/* for DVBv5 stats */
1277a9d85d5SMauro Carvalho Chehab 	s64 init_ucb;
1280400c535SMauro Carvalho Chehab 	unsigned long per_jiffies_stats;
1290400c535SMauro Carvalho Chehab 	unsigned long ber_jiffies_stats;
1300400c535SMauro Carvalho Chehab 	unsigned long ber_jiffies_stats_layer[3];
131704f01bbSMauro Carvalho Chehab 
132173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
133173a64cbSPatrick Boettcher 	u16 agc1_max;
134173a64cbSPatrick Boettcher 	u16 agc1_min;
135173a64cbSPatrick Boettcher 	u16 agc2_max;
136173a64cbSPatrick Boettcher 	u16 agc2_min;
137173a64cbSPatrick Boettcher #endif
1389a0bf528SMauro Carvalho Chehab };
1399a0bf528SMauro Carvalho Chehab 
1409a0bf528SMauro Carvalho Chehab enum dib8000_power_mode {
1419a0bf528SMauro Carvalho Chehab 	DIB8000_POWER_ALL = 0,
1429a0bf528SMauro Carvalho Chehab 	DIB8000_POWER_INTERFACE_ONLY,
1439a0bf528SMauro Carvalho Chehab };
1449a0bf528SMauro Carvalho Chehab 
dib8000_i2c_read16(struct i2c_device * i2c,u16 reg)1459a0bf528SMauro Carvalho Chehab static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
1469a0bf528SMauro Carvalho Chehab {
1479a0bf528SMauro Carvalho Chehab 	u16 ret;
1489a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2] = {
1499a0bf528SMauro Carvalho Chehab 		{.addr = i2c->addr >> 1, .flags = 0, .len = 2},
1509a0bf528SMauro Carvalho Chehab 		{.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
1519a0bf528SMauro Carvalho Chehab 	};
1529a0bf528SMauro Carvalho Chehab 
1539a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
1548af16adfSMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
1559a0bf528SMauro Carvalho Chehab 		return 0;
1569a0bf528SMauro Carvalho Chehab 	}
1579a0bf528SMauro Carvalho Chehab 
1589a0bf528SMauro Carvalho Chehab 	msg[0].buf    = i2c->i2c_write_buffer;
1599a0bf528SMauro Carvalho Chehab 	msg[0].buf[0] = reg >> 8;
1609a0bf528SMauro Carvalho Chehab 	msg[0].buf[1] = reg & 0xff;
1619a0bf528SMauro Carvalho Chehab 	msg[1].buf    = i2c->i2c_read_buffer;
1629a0bf528SMauro Carvalho Chehab 
1639a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(i2c->adap, msg, 2) != 2)
1648af16adfSMauro Carvalho Chehab 		dprintk("i2c read error on %d\n", reg);
1659a0bf528SMauro Carvalho Chehab 
1669a0bf528SMauro Carvalho Chehab 	ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
1679a0bf528SMauro Carvalho Chehab 	mutex_unlock(i2c->i2c_buffer_lock);
1689a0bf528SMauro Carvalho Chehab 	return ret;
1699a0bf528SMauro Carvalho Chehab }
1709a0bf528SMauro Carvalho Chehab 
__dib8000_read_word(struct dib8000_state * state,u16 reg)1715ac64ba1SMauro Carvalho Chehab static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg)
1729a0bf528SMauro Carvalho Chehab {
1739a0bf528SMauro Carvalho Chehab 	u16 ret;
1749a0bf528SMauro Carvalho Chehab 
1759a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = reg >> 8;
1769a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
1779a0bf528SMauro Carvalho Chehab 
1789a0bf528SMauro Carvalho Chehab 	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
1799a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c.addr >> 1;
1809a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
1819a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
1829a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 2;
1839a0bf528SMauro Carvalho Chehab 	state->msg[1].addr = state->i2c.addr >> 1;
1849a0bf528SMauro Carvalho Chehab 	state->msg[1].flags = I2C_M_RD;
1859a0bf528SMauro Carvalho Chehab 	state->msg[1].buf = state->i2c_read_buffer;
1869a0bf528SMauro Carvalho Chehab 	state->msg[1].len = 2;
1879a0bf528SMauro Carvalho Chehab 
1889a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
1898af16adfSMauro Carvalho Chehab 		dprintk("i2c read error on %d\n", reg);
1909a0bf528SMauro Carvalho Chehab 
1919a0bf528SMauro Carvalho Chehab 	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
1925ac64ba1SMauro Carvalho Chehab 
1935ac64ba1SMauro Carvalho Chehab 	return ret;
1945ac64ba1SMauro Carvalho Chehab }
1955ac64ba1SMauro Carvalho Chehab 
dib8000_read_word(struct dib8000_state * state,u16 reg)1965ac64ba1SMauro Carvalho Chehab static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
1975ac64ba1SMauro Carvalho Chehab {
1985ac64ba1SMauro Carvalho Chehab 	u16 ret;
1995ac64ba1SMauro Carvalho Chehab 
2005ac64ba1SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2018af16adfSMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
2025ac64ba1SMauro Carvalho Chehab 		return 0;
2035ac64ba1SMauro Carvalho Chehab 	}
2045ac64ba1SMauro Carvalho Chehab 
2055ac64ba1SMauro Carvalho Chehab 	ret = __dib8000_read_word(state, reg);
2065ac64ba1SMauro Carvalho Chehab 
2079a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
2089a0bf528SMauro Carvalho Chehab 
2099a0bf528SMauro Carvalho Chehab 	return ret;
2109a0bf528SMauro Carvalho Chehab }
2119a0bf528SMauro Carvalho Chehab 
dib8000_read32(struct dib8000_state * state,u16 reg)2129a0bf528SMauro Carvalho Chehab static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
2139a0bf528SMauro Carvalho Chehab {
2149a0bf528SMauro Carvalho Chehab 	u16 rw[2];
2159a0bf528SMauro Carvalho Chehab 
2165ac64ba1SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2178af16adfSMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
2185ac64ba1SMauro Carvalho Chehab 		return 0;
2195ac64ba1SMauro Carvalho Chehab 	}
2205ac64ba1SMauro Carvalho Chehab 
2215ac64ba1SMauro Carvalho Chehab 	rw[0] = __dib8000_read_word(state, reg + 0);
2225ac64ba1SMauro Carvalho Chehab 	rw[1] = __dib8000_read_word(state, reg + 1);
2235ac64ba1SMauro Carvalho Chehab 
2245ac64ba1SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
2259a0bf528SMauro Carvalho Chehab 
2269a0bf528SMauro Carvalho Chehab 	return ((rw[0] << 16) | (rw[1]));
2279a0bf528SMauro Carvalho Chehab }
2289a0bf528SMauro Carvalho Chehab 
dib8000_i2c_write16(struct i2c_device * i2c,u16 reg,u16 val)2299a0bf528SMauro Carvalho Chehab static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
2309a0bf528SMauro Carvalho Chehab {
2319a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
2329a0bf528SMauro Carvalho Chehab 	int ret = 0;
2339a0bf528SMauro Carvalho Chehab 
2349a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
2358af16adfSMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
2369a0bf528SMauro Carvalho Chehab 		return -EINVAL;
2379a0bf528SMauro Carvalho Chehab 	}
2389a0bf528SMauro Carvalho Chehab 
2399a0bf528SMauro Carvalho Chehab 	msg.buf    = i2c->i2c_write_buffer;
2409a0bf528SMauro Carvalho Chehab 	msg.buf[0] = (reg >> 8) & 0xff;
2419a0bf528SMauro Carvalho Chehab 	msg.buf[1] = reg & 0xff;
2429a0bf528SMauro Carvalho Chehab 	msg.buf[2] = (val >> 8) & 0xff;
2439a0bf528SMauro Carvalho Chehab 	msg.buf[3] = val & 0xff;
2449a0bf528SMauro Carvalho Chehab 
2459a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
2469a0bf528SMauro Carvalho Chehab 	mutex_unlock(i2c->i2c_buffer_lock);
2479a0bf528SMauro Carvalho Chehab 
2489a0bf528SMauro Carvalho Chehab 	return ret;
2499a0bf528SMauro Carvalho Chehab }
2509a0bf528SMauro Carvalho Chehab 
dib8000_write_word(struct dib8000_state * state,u16 reg,u16 val)2519a0bf528SMauro Carvalho Chehab static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
2529a0bf528SMauro Carvalho Chehab {
2539a0bf528SMauro Carvalho Chehab 	int ret;
2549a0bf528SMauro Carvalho Chehab 
2559a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2568af16adfSMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
2579a0bf528SMauro Carvalho Chehab 		return -EINVAL;
2589a0bf528SMauro Carvalho Chehab 	}
2599a0bf528SMauro Carvalho Chehab 
2609a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
2619a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
2629a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
2639a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[3] = val & 0xff;
2649a0bf528SMauro Carvalho Chehab 
2659a0bf528SMauro Carvalho Chehab 	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
2669a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c.addr >> 1;
2679a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
2689a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
2699a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 4;
2709a0bf528SMauro Carvalho Chehab 
2719a0bf528SMauro Carvalho Chehab 	ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
2729a0bf528SMauro Carvalho Chehab 			-EREMOTEIO : 0);
2739a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
2749a0bf528SMauro Carvalho Chehab 
2759a0bf528SMauro Carvalho Chehab 	return ret;
2769a0bf528SMauro Carvalho Chehab }
2779a0bf528SMauro Carvalho Chehab 
2789a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
2799a0bf528SMauro Carvalho Chehab 	(769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c,
2809a0bf528SMauro Carvalho Chehab 		(920 << 5) | 0x09
2819a0bf528SMauro Carvalho Chehab };
2829a0bf528SMauro Carvalho Chehab 
2839a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg[8] = {
2849a0bf528SMauro Carvalho Chehab 	(692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
2859a0bf528SMauro Carvalho Chehab };
2869a0bf528SMauro Carvalho Chehab 
2879a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
2889a0bf528SMauro Carvalho Chehab 	(832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11,
2899a0bf528SMauro Carvalho Chehab 		(-931 << 5) | 0x0f
2909a0bf528SMauro Carvalho Chehab };
2919a0bf528SMauro Carvalho Chehab 
2929a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
2939a0bf528SMauro Carvalho Chehab 	(622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e,
2949a0bf528SMauro Carvalho Chehab 		(982 << 5) | 0x0c
2959a0bf528SMauro Carvalho Chehab };
2969a0bf528SMauro Carvalho Chehab 
2979a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
2989a0bf528SMauro Carvalho Chehab 	(699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12,
2999a0bf528SMauro Carvalho Chehab 		(-720 << 5) | 0x0d
3009a0bf528SMauro Carvalho Chehab };
3019a0bf528SMauro Carvalho Chehab 
3029a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg[8] = {
3039a0bf528SMauro Carvalho Chehab 	(664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e,
3049a0bf528SMauro Carvalho Chehab 		(-610 << 5) | 0x0a
3059a0bf528SMauro Carvalho Chehab };
3069a0bf528SMauro Carvalho Chehab 
3079a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
3089a0bf528SMauro Carvalho Chehab 	(-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f,
3099a0bf528SMauro Carvalho Chehab 		(-922 << 5) | 0x0d
3109a0bf528SMauro Carvalho Chehab };
3119a0bf528SMauro Carvalho Chehab 
3129a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg[8] = {
3139a0bf528SMauro Carvalho Chehab 	(638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d,
3149a0bf528SMauro Carvalho Chehab 		(-655 << 5) | 0x0a
3159a0bf528SMauro Carvalho Chehab };
3169a0bf528SMauro Carvalho Chehab 
3179a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
3189a0bf528SMauro Carvalho Chehab 	(-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14,
3199a0bf528SMauro Carvalho Chehab 		(-958 << 5) | 0x13
3209a0bf528SMauro Carvalho Chehab };
3219a0bf528SMauro Carvalho Chehab 
3229a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
3239a0bf528SMauro Carvalho Chehab 	(-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12,
3249a0bf528SMauro Carvalho Chehab 		(-568 << 5) | 0x0f
3259a0bf528SMauro Carvalho Chehab };
3269a0bf528SMauro Carvalho Chehab 
3279a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
3289a0bf528SMauro Carvalho Chehab 	(-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14,
3299a0bf528SMauro Carvalho Chehab 		(-848 << 5) | 0x13
3309a0bf528SMauro Carvalho Chehab };
3319a0bf528SMauro Carvalho Chehab 
3329a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg[8] = {
3339a0bf528SMauro Carvalho Chehab 	(612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12,
3349a0bf528SMauro Carvalho Chehab 		(-869 << 5) | 0x13
3359a0bf528SMauro Carvalho Chehab };
3369a0bf528SMauro Carvalho Chehab 
3379a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
3389a0bf528SMauro Carvalho Chehab 	(-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13,
3399a0bf528SMauro Carvalho Chehab 		(-598 << 5) | 0x10
3409a0bf528SMauro Carvalho Chehab };
3419a0bf528SMauro Carvalho Chehab 
3429a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg[8] = {
3439a0bf528SMauro Carvalho Chehab 	(673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f,
3449a0bf528SMauro Carvalho Chehab 		(585 << 5) | 0x0f
3459a0bf528SMauro Carvalho Chehab };
3469a0bf528SMauro Carvalho Chehab 
3479a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
3489a0bf528SMauro Carvalho Chehab 	(863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18,
3499a0bf528SMauro Carvalho Chehab 		(0 << 5) | 0x14
3509a0bf528SMauro Carvalho Chehab };
3519a0bf528SMauro Carvalho Chehab 
3529a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
3539a0bf528SMauro Carvalho Chehab 	(-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15,
3549a0bf528SMauro Carvalho Chehab 		(-877 << 5) | 0x15
3559a0bf528SMauro Carvalho Chehab };
3569a0bf528SMauro Carvalho Chehab 
3579a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
3589a0bf528SMauro Carvalho Chehab 	(-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18,
3599a0bf528SMauro Carvalho Chehab 		(-921 << 5) | 0x14
3609a0bf528SMauro Carvalho Chehab };
3619a0bf528SMauro Carvalho Chehab 
3629a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg[8] = {
3639a0bf528SMauro Carvalho Chehab 	(514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15,
3649a0bf528SMauro Carvalho Chehab 		(690 << 5) | 0x14
3659a0bf528SMauro Carvalho Chehab };
3669a0bf528SMauro Carvalho Chehab 
3679a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_3seg[24] = {
3689a0bf528SMauro 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
3699a0bf528SMauro Carvalho Chehab };
3709a0bf528SMauro Carvalho Chehab 
3719a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_1seg[24] = {
3729a0bf528SMauro 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
3739a0bf528SMauro Carvalho Chehab };
3749a0bf528SMauro Carvalho Chehab 
3759a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_13seg[24] = {
3769a0bf528SMauro 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
3779a0bf528SMauro Carvalho Chehab };
3789a0bf528SMauro Carvalho Chehab 
fft_to_mode(struct dib8000_state * state)3799a0bf528SMauro Carvalho Chehab static u16 fft_to_mode(struct dib8000_state *state)
3809a0bf528SMauro Carvalho Chehab {
3819a0bf528SMauro Carvalho Chehab 	u16 mode;
3829a0bf528SMauro Carvalho Chehab 	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
3839a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
3849a0bf528SMauro Carvalho Chehab 		mode = 1;
3859a0bf528SMauro Carvalho Chehab 		break;
3869a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
3879a0bf528SMauro Carvalho Chehab 		mode = 2;
3889a0bf528SMauro Carvalho Chehab 		break;
3899a0bf528SMauro Carvalho Chehab 	default:
3909a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_AUTO:
3919a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
3929a0bf528SMauro Carvalho Chehab 		mode = 3;
3939a0bf528SMauro Carvalho Chehab 		break;
3949a0bf528SMauro Carvalho Chehab 	}
3959a0bf528SMauro Carvalho Chehab 	return mode;
3969a0bf528SMauro Carvalho Chehab }
3979a0bf528SMauro Carvalho Chehab 
dib8000_set_acquisition_mode(struct dib8000_state * state)3989a0bf528SMauro Carvalho Chehab static void dib8000_set_acquisition_mode(struct dib8000_state *state)
3999a0bf528SMauro Carvalho Chehab {
4009a0bf528SMauro Carvalho Chehab 	u16 nud = dib8000_read_word(state, 298);
4019a0bf528SMauro Carvalho Chehab 	nud |= (1 << 3) | (1 << 0);
4028af16adfSMauro Carvalho Chehab 	dprintk("acquisition mode activated\n");
4039a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 298, nud);
4049a0bf528SMauro Carvalho Chehab }
dib8000_set_output_mode(struct dvb_frontend * fe,int mode)4059a0bf528SMauro Carvalho Chehab static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
4069a0bf528SMauro Carvalho Chehab {
4079a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
4089a0bf528SMauro Carvalho Chehab 	u16 outreg, fifo_threshold, smo_mode, sram = 0x0205;	/* by default SDRAM deintlv is enabled */
4099a0bf528SMauro Carvalho Chehab 
410173a64cbSPatrick Boettcher 	state->output_mode = mode;
4119a0bf528SMauro Carvalho Chehab 	outreg = 0;
4129a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
4139a0bf528SMauro Carvalho Chehab 	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
4149a0bf528SMauro Carvalho Chehab 
4158af16adfSMauro Carvalho Chehab 	dprintk("-I-	Setting output mode for demod %p to %d\n",
4169a0bf528SMauro Carvalho Chehab 			&state->fe[0], mode);
4179a0bf528SMauro Carvalho Chehab 
4189a0bf528SMauro Carvalho Chehab 	switch (mode) {
4199a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:	// STBs with parallel gated clock
4209a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10);	/* 0x0400 */
4219a0bf528SMauro Carvalho Chehab 		break;
4229a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK:	// STBs with parallel continues clock
4239a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (1 << 6);	/* 0x0440 */
4249a0bf528SMauro Carvalho Chehab 		break;
4259a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:	// STBs with serial input
4269a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (2 << 6) | (0 << 1);	/* 0x0482 */
4279a0bf528SMauro Carvalho Chehab 		break;
4289a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
4299a0bf528SMauro Carvalho Chehab 		if (state->cfg.hostbus_diversity) {
4309a0bf528SMauro Carvalho Chehab 			outreg = (1 << 10) | (4 << 6);	/* 0x0500 */
4319a0bf528SMauro Carvalho Chehab 			sram &= 0xfdff;
4329a0bf528SMauro Carvalho Chehab 		} else
4339a0bf528SMauro Carvalho Chehab 			sram |= 0x0c00;
4349a0bf528SMauro Carvalho Chehab 		break;
4359a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:	// e.g. USB feeding
4369a0bf528SMauro Carvalho Chehab 		smo_mode |= (3 << 1);
4379a0bf528SMauro Carvalho Chehab 		fifo_threshold = 512;
4389a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (5 << 6);
4399a0bf528SMauro Carvalho Chehab 		break;
4409a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:	// disable
4419a0bf528SMauro Carvalho Chehab 		outreg = 0;
4429a0bf528SMauro Carvalho Chehab 		break;
4439a0bf528SMauro Carvalho Chehab 
4449a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
4459a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (3 << 6);
4469a0bf528SMauro Carvalho Chehab 		dib8000_set_acquisition_mode(state);
4479a0bf528SMauro Carvalho Chehab 		break;
4489a0bf528SMauro Carvalho Chehab 
4499a0bf528SMauro Carvalho Chehab 	default:
4508af16adfSMauro Carvalho Chehab 		dprintk("Unhandled output_mode passed to be set for demod %p\n",
4519a0bf528SMauro Carvalho Chehab 				&state->fe[0]);
4529a0bf528SMauro Carvalho Chehab 		return -EINVAL;
4539a0bf528SMauro Carvalho Chehab 	}
4549a0bf528SMauro Carvalho Chehab 
4559a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
4569a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
4579a0bf528SMauro Carvalho Chehab 
4589a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 299, smo_mode);
4599a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 300, fifo_threshold);	/* synchronous fread */
4609a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1286, outreg);
4619a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1291, sram);
4629a0bf528SMauro Carvalho Chehab 
4639a0bf528SMauro Carvalho Chehab 	return 0;
4649a0bf528SMauro Carvalho Chehab }
4659a0bf528SMauro Carvalho Chehab 
dib8000_set_diversity_in(struct dvb_frontend * fe,int onoff)4669a0bf528SMauro Carvalho Chehab static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
4679a0bf528SMauro Carvalho Chehab {
4689a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
469173a64cbSPatrick Boettcher 	u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0;
4709a0bf528SMauro Carvalho Chehab 
4718af16adfSMauro Carvalho Chehab 	dprintk("set diversity input to %i\n", onoff);
4729a0bf528SMauro Carvalho Chehab 	if (!state->differential_constellation) {
4739a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 272, 1 << 9);	//dvsy_off_lmod4 = 1
4749a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2);	// sync_enable = 1; comb_mode = 2
4759a0bf528SMauro Carvalho Chehab 	} else {
4769a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 272, 0);	//dvsy_off_lmod4 = 0
4779a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 273, sync_wait);	// sync_enable = 0; comb_mode = 0
4789a0bf528SMauro Carvalho Chehab 	}
4799a0bf528SMauro Carvalho Chehab 	state->diversity_onoff = onoff;
4809a0bf528SMauro Carvalho Chehab 
4819a0bf528SMauro Carvalho Chehab 	switch (onoff) {
4829a0bf528SMauro Carvalho Chehab 	case 0:		/* only use the internal way - not the diversity input */
4839a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 270, 1);
4849a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 271, 0);
4859a0bf528SMauro Carvalho Chehab 		break;
4869a0bf528SMauro Carvalho Chehab 	case 1:		/* both ways */
4879a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 270, 6);
4889a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 271, 6);
4899a0bf528SMauro Carvalho Chehab 		break;
4909a0bf528SMauro Carvalho Chehab 	case 2:		/* only the diversity input */
4919a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 270, 0);
4929a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 271, 1);
4939a0bf528SMauro Carvalho Chehab 		break;
4949a0bf528SMauro Carvalho Chehab 	}
495173a64cbSPatrick Boettcher 
496173a64cbSPatrick Boettcher 	if (state->revision == 0x8002) {
497173a64cbSPatrick Boettcher 		tmp = dib8000_read_word(state, 903);
498173a64cbSPatrick Boettcher 		dib8000_write_word(state, 903, tmp & ~(1 << 3));
499173a64cbSPatrick Boettcher 		msleep(30);
500173a64cbSPatrick Boettcher 		dib8000_write_word(state, 903, tmp | (1 << 3));
501173a64cbSPatrick Boettcher 	}
5029a0bf528SMauro Carvalho Chehab 	return 0;
5039a0bf528SMauro Carvalho Chehab }
5049a0bf528SMauro Carvalho Chehab 
dib8000_set_power_mode(struct dib8000_state * state,enum dib8000_power_mode mode)5059a0bf528SMauro Carvalho Chehab static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
5069a0bf528SMauro Carvalho Chehab {
5079a0bf528SMauro Carvalho Chehab 	/* by default everything is going to be powered off */
5089a0bf528SMauro Carvalho Chehab 	u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
5099a0bf528SMauro Carvalho Chehab 		reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
5109a0bf528SMauro Carvalho Chehab 		reg_1280;
5119a0bf528SMauro Carvalho Chehab 
5129a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
5139a0bf528SMauro Carvalho Chehab 		reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
5149a0bf528SMauro Carvalho Chehab 	else
5159a0bf528SMauro Carvalho Chehab 		reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80;
5169a0bf528SMauro Carvalho Chehab 
5179a0bf528SMauro Carvalho Chehab 	/* now, depending on the requested mode, we power on */
5189a0bf528SMauro Carvalho Chehab 	switch (mode) {
5199a0bf528SMauro Carvalho Chehab 		/* power up everything in the demod */
5209a0bf528SMauro Carvalho Chehab 	case DIB8000_POWER_ALL:
5219a0bf528SMauro Carvalho Chehab 		reg_774 = 0x0000;
5229a0bf528SMauro Carvalho Chehab 		reg_775 = 0x0000;
5239a0bf528SMauro Carvalho Chehab 		reg_776 = 0x0000;
5249a0bf528SMauro Carvalho Chehab 		reg_900 &= 0xfffc;
5259a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090)
5269a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x00ff;
5279a0bf528SMauro Carvalho Chehab 		else
5289a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x707f;
5299a0bf528SMauro Carvalho Chehab 		break;
5309a0bf528SMauro Carvalho Chehab 	case DIB8000_POWER_INTERFACE_ONLY:
5319a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090)
5329a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x00ff;
5339a0bf528SMauro Carvalho Chehab 		else
5349a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0xfa7b;
5359a0bf528SMauro Carvalho Chehab 		break;
5369a0bf528SMauro Carvalho Chehab 	}
5379a0bf528SMauro Carvalho Chehab 
5388af16adfSMauro 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);
5399a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 774, reg_774);
5409a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 775, reg_775);
5419a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 776, reg_776);
5429a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 900, reg_900);
5439a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1280, reg_1280);
5449a0bf528SMauro Carvalho Chehab }
5459a0bf528SMauro Carvalho Chehab 
dib8000_set_adc_state(struct dib8000_state * state,enum dibx000_adc_states no)5469a0bf528SMauro Carvalho Chehab static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
5479a0bf528SMauro Carvalho Chehab {
5489a0bf528SMauro Carvalho Chehab 	int ret = 0;
5499a0bf528SMauro Carvalho Chehab 	u16 reg, reg_907 = dib8000_read_word(state, 907);
5509a0bf528SMauro Carvalho Chehab 	u16 reg_908 = dib8000_read_word(state, 908);
5519a0bf528SMauro Carvalho Chehab 
5529a0bf528SMauro Carvalho Chehab 	switch (no) {
5539a0bf528SMauro Carvalho Chehab 	case DIBX000_SLOW_ADC_ON:
5549a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090) {
5559a0bf528SMauro Carvalho Chehab 			reg_908 |= (1 << 1) | (1 << 0);
5569a0bf528SMauro Carvalho Chehab 			ret |= dib8000_write_word(state, 908, reg_908);
5579a0bf528SMauro Carvalho Chehab 			reg_908 &= ~(1 << 1);
5589a0bf528SMauro Carvalho Chehab 		} else {
5599a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1925);
5609a0bf528SMauro Carvalho Chehab 			/* en_slowAdc = 1 & reset_sladc = 1 */
5619a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1925, reg |
5629a0bf528SMauro Carvalho Chehab 					(1<<4) | (1<<2));
5639a0bf528SMauro Carvalho Chehab 
564868c9a17SMauro Carvalho Chehab 			/* read access to make it works... strange ... */
5659a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1925);
5669a0bf528SMauro Carvalho Chehab 			msleep(20);
5679a0bf528SMauro Carvalho Chehab 			/* en_slowAdc = 1 & reset_sladc = 0 */
5689a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1925, reg & ~(1<<4));
5699a0bf528SMauro Carvalho Chehab 
5709a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 921) & ~((0x3 << 14)
5719a0bf528SMauro Carvalho Chehab 					| (0x3 << 12));
5729a0bf528SMauro Carvalho Chehab 			/* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ;
5739a0bf528SMauro Carvalho Chehab 			   (Vin2 = Vcm) */
5749a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 921, reg | (1 << 14)
5759a0bf528SMauro Carvalho Chehab 					| (3 << 12));
5769a0bf528SMauro Carvalho Chehab 		}
5779a0bf528SMauro Carvalho Chehab 		break;
5789a0bf528SMauro Carvalho Chehab 
5799a0bf528SMauro Carvalho Chehab 	case DIBX000_SLOW_ADC_OFF:
5809a0bf528SMauro Carvalho Chehab 		if (state->revision == 0x8090) {
5819a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1925);
5829a0bf528SMauro Carvalho Chehab 			/* reset_sladc = 1 en_slowAdc = 0 */
5839a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1925,
5849a0bf528SMauro Carvalho Chehab 					(reg & ~(1<<2)) | (1<<4));
5859a0bf528SMauro Carvalho Chehab 		}
5869a0bf528SMauro Carvalho Chehab 		reg_908 |= (1 << 1) | (1 << 0);
5879a0bf528SMauro Carvalho Chehab 		break;
5889a0bf528SMauro Carvalho Chehab 
5899a0bf528SMauro Carvalho Chehab 	case DIBX000_ADC_ON:
5909a0bf528SMauro Carvalho Chehab 		reg_907 &= 0x0fff;
5919a0bf528SMauro Carvalho Chehab 		reg_908 &= 0x0003;
5929a0bf528SMauro Carvalho Chehab 		break;
5939a0bf528SMauro Carvalho Chehab 
5949a0bf528SMauro Carvalho Chehab 	case DIBX000_ADC_OFF:	// leave the VBG voltage on
595c063c7c6SMauro Carvalho Chehab 		reg_907 = (1 << 13) | (1 << 12);
596c063c7c6SMauro Carvalho Chehab 		reg_908 = (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 1);
5979a0bf528SMauro Carvalho Chehab 		break;
5989a0bf528SMauro Carvalho Chehab 
5999a0bf528SMauro Carvalho Chehab 	case DIBX000_VBG_ENABLE:
6009a0bf528SMauro Carvalho Chehab 		reg_907 &= ~(1 << 15);
6019a0bf528SMauro Carvalho Chehab 		break;
6029a0bf528SMauro Carvalho Chehab 
6039a0bf528SMauro Carvalho Chehab 	case DIBX000_VBG_DISABLE:
6049a0bf528SMauro Carvalho Chehab 		reg_907 |= (1 << 15);
6059a0bf528SMauro Carvalho Chehab 		break;
6069a0bf528SMauro Carvalho Chehab 
6079a0bf528SMauro Carvalho Chehab 	default:
6089a0bf528SMauro Carvalho Chehab 		break;
6099a0bf528SMauro Carvalho Chehab 	}
6109a0bf528SMauro Carvalho Chehab 
6119a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 907, reg_907);
6129a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 908, reg_908);
6139a0bf528SMauro Carvalho Chehab 
6149a0bf528SMauro Carvalho Chehab 	return ret;
6159a0bf528SMauro Carvalho Chehab }
6169a0bf528SMauro Carvalho Chehab 
dib8000_set_bandwidth(struct dvb_frontend * fe,u32 bw)6179a0bf528SMauro Carvalho Chehab static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
6189a0bf528SMauro Carvalho Chehab {
6199a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
6209a0bf528SMauro Carvalho Chehab 	u32 timf;
6219a0bf528SMauro Carvalho Chehab 
6229a0bf528SMauro Carvalho Chehab 	if (bw == 0)
6239a0bf528SMauro Carvalho Chehab 		bw = 6000;
6249a0bf528SMauro Carvalho Chehab 
6259a0bf528SMauro Carvalho Chehab 	if (state->timf == 0) {
6268af16adfSMauro Carvalho Chehab 		dprintk("using default timf\n");
6279a0bf528SMauro Carvalho Chehab 		timf = state->timf_default;
6289a0bf528SMauro Carvalho Chehab 	} else {
6298af16adfSMauro Carvalho Chehab 		dprintk("using updated timf\n");
6309a0bf528SMauro Carvalho Chehab 		timf = state->timf;
6319a0bf528SMauro Carvalho Chehab 	}
6329a0bf528SMauro Carvalho Chehab 
6339a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
6349a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
6359a0bf528SMauro Carvalho Chehab 
6369a0bf528SMauro Carvalho Chehab 	return 0;
6379a0bf528SMauro Carvalho Chehab }
6389a0bf528SMauro Carvalho Chehab 
dib8000_sad_calib(struct dib8000_state * state)6399a0bf528SMauro Carvalho Chehab static int dib8000_sad_calib(struct dib8000_state *state)
6409a0bf528SMauro Carvalho Chehab {
641173a64cbSPatrick Boettcher 	u8 sad_sel = 3;
642173a64cbSPatrick Boettcher 
6439a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090) {
644173a64cbSPatrick Boettcher 		dib8000_write_word(state, 922, (sad_sel << 2));
645173a64cbSPatrick Boettcher 		dib8000_write_word(state, 923, 2048);
646173a64cbSPatrick Boettcher 
647173a64cbSPatrick Boettcher 		dib8000_write_word(state, 922, (sad_sel << 2) | 0x1);
648173a64cbSPatrick Boettcher 		dib8000_write_word(state, 922, (sad_sel << 2));
649173a64cbSPatrick Boettcher 	} else {
6509a0bf528SMauro Carvalho Chehab 		/* internal */
6519a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
652173a64cbSPatrick Boettcher 		dib8000_write_word(state, 924, 776);
6539a0bf528SMauro Carvalho Chehab 
6549a0bf528SMauro Carvalho Chehab 		/* do the calibration */
6559a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923, (1 << 0));
6569a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923, (0 << 0));
657173a64cbSPatrick Boettcher 	}
6589a0bf528SMauro Carvalho Chehab 
6599a0bf528SMauro Carvalho Chehab 	msleep(1);
6609a0bf528SMauro Carvalho Chehab 	return 0;
6619a0bf528SMauro Carvalho Chehab }
6629a0bf528SMauro Carvalho Chehab 
dib8000_set_wbd_ref(struct dvb_frontend * fe,u16 value)663d44913c1SMauro Carvalho Chehab static int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
6649a0bf528SMauro Carvalho Chehab {
6659a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
6669a0bf528SMauro Carvalho Chehab 	if (value > 4095)
6679a0bf528SMauro Carvalho Chehab 		value = 4095;
6689a0bf528SMauro Carvalho Chehab 	state->wbd_ref = value;
6699a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(state, 106, value);
6709a0bf528SMauro Carvalho Chehab }
671173a64cbSPatrick Boettcher 
dib8000_reset_pll_common(struct dib8000_state * state,const struct dibx000_bandwidth_config * bw)6729a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
6739a0bf528SMauro Carvalho Chehab {
6748af16adfSMauro Carvalho Chehab 	dprintk("ifreq: %d %x, inversion: %d\n", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
6759a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
6769a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23,
6779a0bf528SMauro Carvalho Chehab 				(u16) (((bw->internal * 1000) >> 16) & 0xffff));
6789a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24,
6799a0bf528SMauro Carvalho Chehab 				(u16) ((bw->internal * 1000) & 0xffff));
6809a0bf528SMauro Carvalho Chehab 	} else {
6819a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff));
6829a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24,
6839a0bf528SMauro Carvalho Chehab 				(u16) ((bw->internal  / 2 * 1000) & 0xffff));
6849a0bf528SMauro Carvalho Chehab 	}
6859a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
6869a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
6879a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
6889a0bf528SMauro Carvalho Chehab 
6899a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
6909a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 922, bw->sad_cfg);
6919a0bf528SMauro Carvalho Chehab }
6929a0bf528SMauro Carvalho Chehab 
dib8000_reset_pll(struct dib8000_state * state)6939a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll(struct dib8000_state *state)
6949a0bf528SMauro Carvalho Chehab {
6959a0bf528SMauro Carvalho Chehab 	const struct dibx000_bandwidth_config *pll = state->cfg.pll;
6969a0bf528SMauro Carvalho Chehab 	u16 clk_cfg1, reg;
6979a0bf528SMauro Carvalho Chehab 
6989a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
6999a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 901,
7009a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv << 8) | (pll->pll_ratio << 0));
7019a0bf528SMauro Carvalho Chehab 
7029a0bf528SMauro Carvalho Chehab 		clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
7039a0bf528SMauro Carvalho Chehab 			(pll->bypclk_div << 5) | (pll->enable_refdiv << 4) |
7049a0bf528SMauro Carvalho Chehab 			(1 << 3) | (pll->pll_range << 1) |
7059a0bf528SMauro Carvalho Chehab 			(pll->pll_reset << 0);
7069a0bf528SMauro Carvalho Chehab 
7079a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 902, clk_cfg1);
7089a0bf528SMauro Carvalho Chehab 		clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
7099a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 902, clk_cfg1);
7109a0bf528SMauro Carvalho Chehab 
7118af16adfSMauro Carvalho Chehab 		dprintk("clk_cfg1: 0x%04x\n", clk_cfg1);
7129a0bf528SMauro Carvalho Chehab 
7139a0bf528SMauro Carvalho Chehab 		/* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
7149a0bf528SMauro Carvalho Chehab 		if (state->cfg.pll->ADClkSrc == 0)
7159a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904,
7169a0bf528SMauro Carvalho Chehab 					(0 << 15) | (0 << 12) | (0 << 10) |
7179a0bf528SMauro Carvalho Chehab 					(pll->modulo << 8) |
7189a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
7199a0bf528SMauro Carvalho Chehab 		else if (state->cfg.refclksel != 0)
7209a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
7219a0bf528SMauro Carvalho Chehab 					((state->cfg.refclksel & 0x3) << 10) |
7229a0bf528SMauro Carvalho Chehab 					(pll->modulo << 8) |
7239a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
7249a0bf528SMauro Carvalho Chehab 		else
7259a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
7269a0bf528SMauro Carvalho Chehab 					(3 << 10) | (pll->modulo << 8) |
7279a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
7289a0bf528SMauro Carvalho Chehab 	} else {
7299a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1856, (!pll->pll_reset<<13) |
7309a0bf528SMauro Carvalho Chehab 				(pll->pll_range<<12) | (pll->pll_ratio<<6) |
7319a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv));
7329a0bf528SMauro Carvalho Chehab 
7339a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 1857);
7349a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15));
7359a0bf528SMauro Carvalho Chehab 
7369a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */
7379a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1858, reg | 1);
7389a0bf528SMauro Carvalho Chehab 
7399a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 904, (pll->modulo << 8));
7409a0bf528SMauro Carvalho Chehab 	}
7419a0bf528SMauro Carvalho Chehab 
7429a0bf528SMauro Carvalho Chehab 	dib8000_reset_pll_common(state, pll);
7439a0bf528SMauro Carvalho Chehab }
7449a0bf528SMauro Carvalho Chehab 
dib8000_update_pll(struct dvb_frontend * fe,struct dibx000_bandwidth_config * pll,u32 bw,u8 ratio)745d44913c1SMauro Carvalho Chehab static int dib8000_update_pll(struct dvb_frontend *fe,
746173a64cbSPatrick Boettcher 		struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
7479a0bf528SMauro Carvalho Chehab {
7489a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
7499a0bf528SMauro Carvalho Chehab 	u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
750173a64cbSPatrick Boettcher 	u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ;
7519a0bf528SMauro Carvalho Chehab 	u32 internal, xtal;
7529a0bf528SMauro Carvalho Chehab 
7539a0bf528SMauro Carvalho Chehab 	/* get back old values */
7549a0bf528SMauro Carvalho Chehab 	prediv = reg_1856 & 0x3f;
7559a0bf528SMauro Carvalho Chehab 	loopdiv = (reg_1856 >> 6) & 0x3f;
7569a0bf528SMauro Carvalho Chehab 
757173a64cbSPatrick Boettcher 	if ((pll == NULL) || (pll->pll_prediv == prediv &&
758173a64cbSPatrick Boettcher 				pll->pll_ratio == loopdiv))
759173a64cbSPatrick Boettcher 		return -EINVAL;
760173a64cbSPatrick Boettcher 
7618af16adfSMauro Carvalho Chehab 	dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)\n", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
762173a64cbSPatrick Boettcher 	if (state->revision == 0x8090) {
7639a0bf528SMauro Carvalho Chehab 		reg_1856 &= 0xf000;
7649a0bf528SMauro Carvalho Chehab 		reg_1857 = dib8000_read_word(state, 1857);
7659a0bf528SMauro Carvalho Chehab 		/* disable PLL */
7669a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15));
7679a0bf528SMauro Carvalho Chehab 
7689a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1856, reg_1856 |
7699a0bf528SMauro Carvalho Chehab 				((pll->pll_ratio & 0x3f) << 6) |
7709a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv & 0x3f));
7719a0bf528SMauro Carvalho Chehab 
7729a0bf528SMauro Carvalho Chehab 		/* write new system clk into P_sec_len */
7739a0bf528SMauro Carvalho Chehab 		internal = dib8000_read32(state, 23) / 1000;
7748af16adfSMauro Carvalho Chehab 		dprintk("Old Internal = %d\n", internal);
7759a0bf528SMauro Carvalho Chehab 		xtal = 2 * (internal / loopdiv) * prediv;
7769a0bf528SMauro Carvalho Chehab 		internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio;
7778af16adfSMauro Carvalho Chehab 		dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d\n", xtal, internal/1000, internal/2000, internal/8000);
7788af16adfSMauro Carvalho Chehab 		dprintk("New Internal = %d\n", internal);
7799a0bf528SMauro Carvalho Chehab 
7809a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23,
7819a0bf528SMauro Carvalho Chehab 				(u16) (((internal / 2) >> 16) & 0xffff));
7829a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff));
7839a0bf528SMauro Carvalho Chehab 		/* enable PLL */
7849a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg_1857 | (1 << 15));
7859a0bf528SMauro Carvalho Chehab 
7869a0bf528SMauro Carvalho Chehab 		while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1)
7878af16adfSMauro Carvalho Chehab 			dprintk("Waiting for PLL to lock\n");
7889a0bf528SMauro Carvalho Chehab 
7899a0bf528SMauro Carvalho Chehab 		/* verify */
7909a0bf528SMauro Carvalho Chehab 		reg_1856 = dib8000_read_word(state, 1856);
7918af16adfSMauro Carvalho Chehab 		dprintk("PLL Updated with prediv = %d and loopdiv = %d\n",
7929a0bf528SMauro Carvalho Chehab 				reg_1856&0x3f, (reg_1856>>6)&0x3f);
793173a64cbSPatrick Boettcher 	} else {
794173a64cbSPatrick Boettcher 		if (bw != state->current_demod_bw) {
795173a64cbSPatrick Boettcher 			/** Bandwidth change => force PLL update **/
7968af16adfSMauro 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);
797173a64cbSPatrick Boettcher 
798173a64cbSPatrick Boettcher 			if (state->cfg.pll->pll_prediv != oldprediv) {
799173a64cbSPatrick Boettcher 				/** Full PLL change only if prediv is changed **/
800173a64cbSPatrick Boettcher 
801173a64cbSPatrick Boettcher 				/** full update => bypass and reconfigure **/
8028af16adfSMauro 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);
803173a64cbSPatrick Boettcher 				dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */
804173a64cbSPatrick Boettcher 				dib8000_reset_pll(state);
805173a64cbSPatrick Boettcher 				dib8000_write_word(state, 898, 0x0004); /* sad */
806173a64cbSPatrick Boettcher 			} else
807173a64cbSPatrick Boettcher 				ratio = state->cfg.pll->pll_ratio;
808173a64cbSPatrick Boettcher 
809173a64cbSPatrick Boettcher 			state->current_demod_bw = bw;
810173a64cbSPatrick Boettcher 		}
811173a64cbSPatrick Boettcher 
812173a64cbSPatrick Boettcher 		if (ratio != 0) {
813173a64cbSPatrick Boettcher 			/** ratio update => only change ratio **/
8148af16adfSMauro Carvalho Chehab 			dprintk("PLL: Update ratio (prediv: %d, ratio: %d)\n", state->cfg.pll->pll_prediv, ratio);
815173a64cbSPatrick Boettcher 			dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
816173a64cbSPatrick Boettcher 		}
817173a64cbSPatrick Boettcher 	}
8189a0bf528SMauro Carvalho Chehab 
8199a0bf528SMauro Carvalho Chehab 	return 0;
8209a0bf528SMauro Carvalho Chehab }
8219a0bf528SMauro Carvalho Chehab 
dib8000_reset_gpio(struct dib8000_state * st)8229a0bf528SMauro Carvalho Chehab static int dib8000_reset_gpio(struct dib8000_state *st)
8239a0bf528SMauro Carvalho Chehab {
8249a0bf528SMauro Carvalho Chehab 	/* reset the GPIOs */
8259a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
8269a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1030, st->cfg.gpio_val);
8279a0bf528SMauro Carvalho Chehab 
8289a0bf528SMauro Carvalho Chehab 	/* TODO 782 is P_gpio_od */
8299a0bf528SMauro Carvalho Chehab 
8309a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
8319a0bf528SMauro Carvalho Chehab 
8329a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
8339a0bf528SMauro Carvalho Chehab 	return 0;
8349a0bf528SMauro Carvalho Chehab }
8359a0bf528SMauro Carvalho Chehab 
dib8000_cfg_gpio(struct dib8000_state * st,u8 num,u8 dir,u8 val)8369a0bf528SMauro Carvalho Chehab static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
8379a0bf528SMauro Carvalho Chehab {
8389a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir = dib8000_read_word(st, 1029);
8399a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir &= ~(1 << num);	/* reset the direction bit */
8409a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
8419a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
8429a0bf528SMauro Carvalho Chehab 
8439a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val = dib8000_read_word(st, 1030);
8449a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val &= ~(1 << num);	/* reset the direction bit */
8459a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val |= (val & 0x01) << num;	/* set the new value */
8469a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1030, st->cfg.gpio_val);
8479a0bf528SMauro Carvalho Chehab 
8488af16adfSMauro Carvalho Chehab 	dprintk("gpio dir: %x: gpio val: %x\n", st->cfg.gpio_dir, st->cfg.gpio_val);
8499a0bf528SMauro Carvalho Chehab 
8509a0bf528SMauro Carvalho Chehab 	return 0;
8519a0bf528SMauro Carvalho Chehab }
8529a0bf528SMauro Carvalho Chehab 
dib8000_set_gpio(struct dvb_frontend * fe,u8 num,u8 dir,u8 val)853d44913c1SMauro Carvalho Chehab static int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
8549a0bf528SMauro Carvalho Chehab {
8559a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
8569a0bf528SMauro Carvalho Chehab 	return dib8000_cfg_gpio(state, num, dir, val);
8579a0bf528SMauro Carvalho Chehab }
8589a0bf528SMauro Carvalho Chehab 
8599a0bf528SMauro Carvalho Chehab static const u16 dib8000_defaults[] = {
8609a0bf528SMauro Carvalho Chehab 	/* auto search configuration - lock0 by default waiting
8619a0bf528SMauro Carvalho Chehab 	 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
8629a0bf528SMauro Carvalho Chehab 	3, 7,
8639a0bf528SMauro Carvalho Chehab 	0x0004,
8649a0bf528SMauro Carvalho Chehab 	0x0400,
8659a0bf528SMauro Carvalho Chehab 	0x0814,
8669a0bf528SMauro Carvalho Chehab 
8679a0bf528SMauro Carvalho Chehab 	12, 11,
8689a0bf528SMauro Carvalho Chehab 	0x001b,
8699a0bf528SMauro Carvalho Chehab 	0x7740,
8709a0bf528SMauro Carvalho Chehab 	0x005b,
8719a0bf528SMauro Carvalho Chehab 	0x8d80,
8729a0bf528SMauro Carvalho Chehab 	0x01c9,
8739a0bf528SMauro Carvalho Chehab 	0xc380,
8749a0bf528SMauro Carvalho Chehab 	0x0000,
8759a0bf528SMauro Carvalho Chehab 	0x0080,
8769a0bf528SMauro Carvalho Chehab 	0x0000,
8779a0bf528SMauro Carvalho Chehab 	0x0090,
8789a0bf528SMauro Carvalho Chehab 	0x0001,
8799a0bf528SMauro Carvalho Chehab 	0xd4c0,
8809a0bf528SMauro Carvalho Chehab 
8819a0bf528SMauro Carvalho Chehab 	/*1, 32,
8829a0bf528SMauro Carvalho Chehab 		0x6680 // P_corm_thres Lock algorithms configuration */
8839a0bf528SMauro Carvalho Chehab 
8849a0bf528SMauro Carvalho Chehab 	11, 80,			/* set ADC level to -16 */
8859a0bf528SMauro Carvalho Chehab 	(1 << 13) - 825 - 117,
8869a0bf528SMauro Carvalho Chehab 	(1 << 13) - 837 - 117,
8879a0bf528SMauro Carvalho Chehab 	(1 << 13) - 811 - 117,
8889a0bf528SMauro Carvalho Chehab 	(1 << 13) - 766 - 117,
8899a0bf528SMauro Carvalho Chehab 	(1 << 13) - 737 - 117,
8909a0bf528SMauro Carvalho Chehab 	(1 << 13) - 693 - 117,
8919a0bf528SMauro Carvalho Chehab 	(1 << 13) - 648 - 117,
8929a0bf528SMauro Carvalho Chehab 	(1 << 13) - 619 - 117,
8939a0bf528SMauro Carvalho Chehab 	(1 << 13) - 575 - 117,
8949a0bf528SMauro Carvalho Chehab 	(1 << 13) - 531 - 117,
8959a0bf528SMauro Carvalho Chehab 	(1 << 13) - 501 - 117,
8969a0bf528SMauro Carvalho Chehab 
8979a0bf528SMauro Carvalho Chehab 	4, 108,
8989a0bf528SMauro Carvalho Chehab 	0,
8999a0bf528SMauro Carvalho Chehab 	0,
9009a0bf528SMauro Carvalho Chehab 	0,
9019a0bf528SMauro Carvalho Chehab 	0,
9029a0bf528SMauro Carvalho Chehab 
9039a0bf528SMauro Carvalho Chehab 	1, 175,
9049a0bf528SMauro Carvalho Chehab 	0x0410,
9059a0bf528SMauro Carvalho Chehab 	1, 179,
9069a0bf528SMauro Carvalho Chehab 	8192,			// P_fft_nb_to_cut
9079a0bf528SMauro Carvalho Chehab 
9089a0bf528SMauro Carvalho Chehab 	6, 181,
9099a0bf528SMauro Carvalho Chehab 	0x2800,			// P_coff_corthres_ ( 2k 4k 8k ) 0x2800
9109a0bf528SMauro Carvalho Chehab 	0x2800,
9119a0bf528SMauro Carvalho Chehab 	0x2800,
9129a0bf528SMauro Carvalho Chehab 	0x2800,			// P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
9139a0bf528SMauro Carvalho Chehab 	0x2800,
9149a0bf528SMauro Carvalho Chehab 	0x2800,
9159a0bf528SMauro Carvalho Chehab 
9169a0bf528SMauro Carvalho Chehab 	2, 193,
9179a0bf528SMauro Carvalho Chehab 	0x0666,			// P_pha3_thres
9189a0bf528SMauro Carvalho Chehab 	0x0000,			// P_cti_use_cpe, P_cti_use_prog
9199a0bf528SMauro Carvalho Chehab 
9209a0bf528SMauro Carvalho Chehab 	2, 205,
9219a0bf528SMauro Carvalho Chehab 	0x200f,			// P_cspu_regul, P_cspu_win_cut
9229a0bf528SMauro Carvalho Chehab 	0x000f,			// P_des_shift_work
9239a0bf528SMauro Carvalho Chehab 
9249a0bf528SMauro Carvalho Chehab 	5, 215,
9259a0bf528SMauro Carvalho Chehab 	0x023d,			// P_adp_regul_cnt
9269a0bf528SMauro Carvalho Chehab 	0x00a4,			// P_adp_noise_cnt
9279a0bf528SMauro Carvalho Chehab 	0x00a4,			// P_adp_regul_ext
9289a0bf528SMauro Carvalho Chehab 	0x7ff0,			// P_adp_noise_ext
9299a0bf528SMauro Carvalho Chehab 	0x3ccc,			// P_adp_fil
9309a0bf528SMauro Carvalho Chehab 
9319a0bf528SMauro Carvalho Chehab 	1, 230,
9329a0bf528SMauro Carvalho Chehab 	0x0000,			// P_2d_byp_ti_num
9339a0bf528SMauro Carvalho Chehab 
9349a0bf528SMauro Carvalho Chehab 	1, 263,
9359a0bf528SMauro Carvalho Chehab 	0x800,			//P_equal_thres_wgn
9369a0bf528SMauro Carvalho Chehab 
9379a0bf528SMauro Carvalho Chehab 	1, 268,
9389a0bf528SMauro Carvalho Chehab 	(2 << 9) | 39,		// P_equal_ctrl_synchro, P_equal_speedmode
9399a0bf528SMauro Carvalho Chehab 
9409a0bf528SMauro Carvalho Chehab 	1, 270,
9419a0bf528SMauro Carvalho Chehab 	0x0001,			// P_div_lock0_wait
9429a0bf528SMauro Carvalho Chehab 	1, 285,
9439a0bf528SMauro Carvalho Chehab 	0x0020,			//p_fec_
9449a0bf528SMauro Carvalho Chehab 	1, 299,
9459a0bf528SMauro Carvalho Chehab 	0x0062,			/* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */
9469a0bf528SMauro Carvalho Chehab 
9479a0bf528SMauro Carvalho Chehab 	1, 338,
9489a0bf528SMauro Carvalho Chehab 	(1 << 12) |		// P_ctrl_corm_thres4pre_freq_inh=1
9499a0bf528SMauro Carvalho Chehab 		(1 << 10) |
9509a0bf528SMauro Carvalho Chehab 		(0 << 9) |		/* P_ctrl_pre_freq_inh=0 */
9519a0bf528SMauro Carvalho Chehab 		(3 << 5) |		/* P_ctrl_pre_freq_step=3 */
9529a0bf528SMauro Carvalho Chehab 		(1 << 0),		/* P_pre_freq_win_len=1 */
9539a0bf528SMauro Carvalho Chehab 
9549a0bf528SMauro Carvalho Chehab 	0,
9559a0bf528SMauro Carvalho Chehab };
9569a0bf528SMauro Carvalho Chehab 
dib8000_identify(struct i2c_device * client)9579a0bf528SMauro Carvalho Chehab static u16 dib8000_identify(struct i2c_device *client)
9589a0bf528SMauro Carvalho Chehab {
9599a0bf528SMauro Carvalho Chehab 	u16 value;
9609a0bf528SMauro Carvalho Chehab 
9619a0bf528SMauro Carvalho Chehab 	//because of glitches sometimes
9629a0bf528SMauro Carvalho Chehab 	value = dib8000_i2c_read16(client, 896);
9639a0bf528SMauro Carvalho Chehab 
9649a0bf528SMauro Carvalho Chehab 	if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
9658af16adfSMauro Carvalho Chehab 		dprintk("wrong Vendor ID (read=0x%x)\n", value);
9669a0bf528SMauro Carvalho Chehab 		return 0;
9679a0bf528SMauro Carvalho Chehab 	}
9689a0bf528SMauro Carvalho Chehab 
9699a0bf528SMauro Carvalho Chehab 	value = dib8000_i2c_read16(client, 897);
9709a0bf528SMauro Carvalho Chehab 	if (value != 0x8000 && value != 0x8001 &&
9719a0bf528SMauro Carvalho Chehab 			value != 0x8002 && value != 0x8090) {
9728af16adfSMauro Carvalho Chehab 		dprintk("wrong Device ID (%x)\n", value);
9739a0bf528SMauro Carvalho Chehab 		return 0;
9749a0bf528SMauro Carvalho Chehab 	}
9759a0bf528SMauro Carvalho Chehab 
9769a0bf528SMauro Carvalho Chehab 	switch (value) {
9779a0bf528SMauro Carvalho Chehab 	case 0x8000:
9788af16adfSMauro Carvalho Chehab 		dprintk("found DiB8000A\n");
9799a0bf528SMauro Carvalho Chehab 		break;
9809a0bf528SMauro Carvalho Chehab 	case 0x8001:
9818af16adfSMauro Carvalho Chehab 		dprintk("found DiB8000B\n");
9829a0bf528SMauro Carvalho Chehab 		break;
9839a0bf528SMauro Carvalho Chehab 	case 0x8002:
9848af16adfSMauro Carvalho Chehab 		dprintk("found DiB8000C\n");
9859a0bf528SMauro Carvalho Chehab 		break;
9869a0bf528SMauro Carvalho Chehab 	case 0x8090:
9878af16adfSMauro Carvalho Chehab 		dprintk("found DiB8096P\n");
9889a0bf528SMauro Carvalho Chehab 		break;
9899a0bf528SMauro Carvalho Chehab 	}
9909a0bf528SMauro Carvalho Chehab 	return value;
9919a0bf528SMauro Carvalho Chehab }
9929a0bf528SMauro Carvalho Chehab 
9937a9d85d5SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 *unc);
9947a9d85d5SMauro Carvalho Chehab 
dib8000_reset_stats(struct dvb_frontend * fe)9956ef06e78SMauro Carvalho Chehab static void dib8000_reset_stats(struct dvb_frontend *fe)
9966ef06e78SMauro Carvalho Chehab {
9976ef06e78SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
9986ef06e78SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
9997a9d85d5SMauro Carvalho Chehab 	u32 ucb;
10006ef06e78SMauro Carvalho Chehab 
10016ef06e78SMauro Carvalho Chehab 	memset(&c->strength, 0, sizeof(c->strength));
10026ef06e78SMauro Carvalho Chehab 	memset(&c->cnr, 0, sizeof(c->cnr));
10036ef06e78SMauro Carvalho Chehab 	memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
10046ef06e78SMauro Carvalho Chehab 	memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
10056ef06e78SMauro Carvalho Chehab 	memset(&c->block_error, 0, sizeof(c->block_error));
10066ef06e78SMauro Carvalho Chehab 
10076ef06e78SMauro Carvalho Chehab 	c->strength.len = 1;
10086ef06e78SMauro Carvalho Chehab 	c->cnr.len = 1;
10096ef06e78SMauro Carvalho Chehab 	c->block_error.len = 1;
10100400c535SMauro Carvalho Chehab 	c->block_count.len = 1;
10116ef06e78SMauro Carvalho Chehab 	c->post_bit_error.len = 1;
10126ef06e78SMauro Carvalho Chehab 	c->post_bit_count.len = 1;
10136ef06e78SMauro Carvalho Chehab 
1014b4600d70SMauro Carvalho Chehab 	c->strength.stat[0].scale = FE_SCALE_DECIBEL;
10156ef06e78SMauro Carvalho Chehab 	c->strength.stat[0].uvalue = 0;
10166ef06e78SMauro Carvalho Chehab 
10176ef06e78SMauro Carvalho Chehab 	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10186ef06e78SMauro Carvalho Chehab 	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10190400c535SMauro Carvalho Chehab 	c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10206ef06e78SMauro Carvalho Chehab 	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10216ef06e78SMauro Carvalho Chehab 	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
10227a9d85d5SMauro Carvalho Chehab 
10237a9d85d5SMauro Carvalho Chehab 	dib8000_read_unc_blocks(fe, &ucb);
1024704f01bbSMauro Carvalho Chehab 
10257a9d85d5SMauro Carvalho Chehab 	state->init_ucb = -ucb;
10260400c535SMauro Carvalho Chehab 	state->ber_jiffies_stats = 0;
10270400c535SMauro Carvalho Chehab 	state->per_jiffies_stats = 0;
10280400c535SMauro Carvalho Chehab 	memset(&state->ber_jiffies_stats_layer, 0,
10290400c535SMauro Carvalho Chehab 	       sizeof(state->ber_jiffies_stats_layer));
10306ef06e78SMauro Carvalho Chehab }
10316ef06e78SMauro Carvalho Chehab 
dib8000_reset(struct dvb_frontend * fe)10329a0bf528SMauro Carvalho Chehab static int dib8000_reset(struct dvb_frontend *fe)
10339a0bf528SMauro Carvalho Chehab {
10349a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
10359a0bf528SMauro Carvalho Chehab 
10369a0bf528SMauro Carvalho Chehab 	if ((state->revision = dib8000_identify(&state->i2c)) == 0)
10379a0bf528SMauro Carvalho Chehab 		return -EINVAL;
10389a0bf528SMauro Carvalho Chehab 
10399a0bf528SMauro Carvalho Chehab 	/* sram lead in, rdy */
10409a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
10419a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1287, 0x0003);
10429a0bf528SMauro Carvalho Chehab 
10439a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8000)
10448af16adfSMauro Carvalho Chehab 		dprintk("error : dib8000 MA not supported\n");
10459a0bf528SMauro Carvalho Chehab 
10469a0bf528SMauro Carvalho Chehab 	dibx000_reset_i2c_master(&state->i2c_master);
10479a0bf528SMauro Carvalho Chehab 
10489a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
10499a0bf528SMauro Carvalho Chehab 
10509a0bf528SMauro Carvalho Chehab 	/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
1051173a64cbSPatrick Boettcher 	dib8000_set_adc_state(state, DIBX000_ADC_OFF);
10529a0bf528SMauro Carvalho Chehab 
10539a0bf528SMauro Carvalho Chehab 	/* restart all parts */
10549a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0xffff);
10559a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 771, 0xffff);
10569a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 772, 0xfffc);
10576d38454aSMauro Carvalho Chehab 	dib8000_write_word(state, 898, 0x000c);	/* restart sad */
10589a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
10599a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1280, 0x0045);
10609a0bf528SMauro Carvalho Chehab 	else
10619a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1280, 0x004d);
10629a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1281, 0x000c);
10639a0bf528SMauro Carvalho Chehab 
10649a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0000);
10659a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 771, 0x0000);
10669a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 772, 0x0000);
10679a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 898, 0x0004);	// sad
10689a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1280, 0x0000);
10699a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1281, 0x0000);
10709a0bf528SMauro Carvalho Chehab 
10719a0bf528SMauro Carvalho Chehab 	/* drives */
10729a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
10739a0bf528SMauro Carvalho Chehab 		if (state->cfg.drives)
10749a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 906, state->cfg.drives);
10759a0bf528SMauro Carvalho Chehab 		else {
10768af16adfSMauro Carvalho Chehab 			dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.\n");
10779a0bf528SMauro Carvalho Chehab 			/* min drive SDRAM - not optimal - adjust */
10789a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 906, 0x2d98);
10799a0bf528SMauro Carvalho Chehab 		}
10809a0bf528SMauro Carvalho Chehab 	}
10819a0bf528SMauro Carvalho Chehab 
10829a0bf528SMauro Carvalho Chehab 	dib8000_reset_pll(state);
10839a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
10849a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 898, 0x0004);
10859a0bf528SMauro Carvalho Chehab 
10869a0bf528SMauro Carvalho Chehab 	if (dib8000_reset_gpio(state) != 0)
10878af16adfSMauro Carvalho Chehab 		dprintk("GPIO reset was not successful.\n");
10889a0bf528SMauro Carvalho Chehab 
10899a0bf528SMauro Carvalho Chehab 	if ((state->revision != 0x8090) &&
10909a0bf528SMauro Carvalho Chehab 			(dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
1091868c9a17SMauro Carvalho Chehab 		dprintk("OUTPUT_MODE could not be reset.\n");
10929a0bf528SMauro Carvalho Chehab 
10939a0bf528SMauro Carvalho Chehab 	state->current_agc = NULL;
10949a0bf528SMauro Carvalho Chehab 
10959a0bf528SMauro Carvalho Chehab 	// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
10969a0bf528SMauro Carvalho Chehab 	/* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
10979a0bf528SMauro Carvalho Chehab 	if (state->cfg.pll->ifreq == 0)
10989a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 40, 0x0755);	/* P_iqc_corr_inh = 0 enable IQcorr block */
10999a0bf528SMauro Carvalho Chehab 	else
11009a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 40, 0x1f55);	/* P_iqc_corr_inh = 1 disable IQcorr block */
11019a0bf528SMauro Carvalho Chehab 
11029a0bf528SMauro Carvalho Chehab 	{
11039a0bf528SMauro Carvalho Chehab 		u16 l = 0, r;
11049a0bf528SMauro Carvalho Chehab 		const u16 *n;
11059a0bf528SMauro Carvalho Chehab 		n = dib8000_defaults;
11069a0bf528SMauro Carvalho Chehab 		l = *n++;
11079a0bf528SMauro Carvalho Chehab 		while (l) {
11089a0bf528SMauro Carvalho Chehab 			r = *n++;
11099a0bf528SMauro Carvalho Chehab 			do {
11109a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, r, *n++);
11119a0bf528SMauro Carvalho Chehab 				r++;
11129a0bf528SMauro Carvalho Chehab 			} while (--l);
11139a0bf528SMauro Carvalho Chehab 			l = *n++;
11149a0bf528SMauro Carvalho Chehab 		}
11159a0bf528SMauro Carvalho Chehab 	}
1116173a64cbSPatrick Boettcher 
11179a0bf528SMauro Carvalho Chehab 	state->isdbt_cfg_loaded = 0;
11189a0bf528SMauro Carvalho Chehab 
11199a0bf528SMauro Carvalho Chehab 	//div_cfg override for special configs
1120173a64cbSPatrick Boettcher 	if ((state->revision != 8090) && (state->cfg.div_cfg != 0))
11219a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 903, state->cfg.div_cfg);
11229a0bf528SMauro Carvalho Chehab 
11239a0bf528SMauro Carvalho Chehab 	/* unforce divstr regardless whether i2c enumeration was done or not */
11249a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
11259a0bf528SMauro Carvalho Chehab 
11269a0bf528SMauro Carvalho Chehab 	dib8000_set_bandwidth(fe, 6000);
11279a0bf528SMauro Carvalho Chehab 
11289a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
11299a0bf528SMauro Carvalho Chehab 	dib8000_sad_calib(state);
1130173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
11319a0bf528SMauro Carvalho Chehab 		dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
1132173a64cbSPatrick Boettcher 
1133173a64cbSPatrick Boettcher 	/* ber_rs_len = 3 */
1134173a64cbSPatrick Boettcher 	dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));
11359a0bf528SMauro Carvalho Chehab 
11369a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
11379a0bf528SMauro Carvalho Chehab 
11386ef06e78SMauro Carvalho Chehab 	dib8000_reset_stats(fe);
11396ef06e78SMauro Carvalho Chehab 
11409a0bf528SMauro Carvalho Chehab 	return 0;
11419a0bf528SMauro Carvalho Chehab }
11429a0bf528SMauro Carvalho Chehab 
dib8000_restart_agc(struct dib8000_state * state)11439a0bf528SMauro Carvalho Chehab static void dib8000_restart_agc(struct dib8000_state *state)
11449a0bf528SMauro Carvalho Chehab {
11459a0bf528SMauro Carvalho Chehab 	// P_restart_iqc & P_restart_agc
11469a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0a00);
11479a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0000);
11489a0bf528SMauro Carvalho Chehab }
11499a0bf528SMauro Carvalho Chehab 
dib8000_update_lna(struct dib8000_state * state)11509a0bf528SMauro Carvalho Chehab static int dib8000_update_lna(struct dib8000_state *state)
11519a0bf528SMauro Carvalho Chehab {
11529a0bf528SMauro Carvalho Chehab 	u16 dyn_gain;
11539a0bf528SMauro Carvalho Chehab 
11549a0bf528SMauro Carvalho Chehab 	if (state->cfg.update_lna) {
11559a0bf528SMauro Carvalho Chehab 		// read dyn_gain here (because it is demod-dependent and not tuner)
11569a0bf528SMauro Carvalho Chehab 		dyn_gain = dib8000_read_word(state, 390);
11579a0bf528SMauro Carvalho Chehab 
11589a0bf528SMauro Carvalho Chehab 		if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
11599a0bf528SMauro Carvalho Chehab 			dib8000_restart_agc(state);
11609a0bf528SMauro Carvalho Chehab 			return 1;
11619a0bf528SMauro Carvalho Chehab 		}
11629a0bf528SMauro Carvalho Chehab 	}
11639a0bf528SMauro Carvalho Chehab 	return 0;
11649a0bf528SMauro Carvalho Chehab }
11659a0bf528SMauro Carvalho Chehab 
dib8000_set_agc_config(struct dib8000_state * state,u8 band)11669a0bf528SMauro Carvalho Chehab static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
11679a0bf528SMauro Carvalho Chehab {
11689a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *agc = NULL;
11699a0bf528SMauro Carvalho Chehab 	int i;
11709a0bf528SMauro Carvalho Chehab 	u16 reg;
11719a0bf528SMauro Carvalho Chehab 
11729a0bf528SMauro Carvalho Chehab 	if (state->current_band == band && state->current_agc != NULL)
11739a0bf528SMauro Carvalho Chehab 		return 0;
11749a0bf528SMauro Carvalho Chehab 	state->current_band = band;
11759a0bf528SMauro Carvalho Chehab 
11769a0bf528SMauro Carvalho Chehab 	for (i = 0; i < state->cfg.agc_config_count; i++)
11779a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc[i].band_caps & band) {
11789a0bf528SMauro Carvalho Chehab 			agc = &state->cfg.agc[i];
11799a0bf528SMauro Carvalho Chehab 			break;
11809a0bf528SMauro Carvalho Chehab 		}
11819a0bf528SMauro Carvalho Chehab 
11829a0bf528SMauro Carvalho Chehab 	if (agc == NULL) {
11838af16adfSMauro Carvalho Chehab 		dprintk("no valid AGC configuration found for band 0x%02x\n", band);
11849a0bf528SMauro Carvalho Chehab 		return -EINVAL;
11859a0bf528SMauro Carvalho Chehab 	}
11869a0bf528SMauro Carvalho Chehab 
11879a0bf528SMauro Carvalho Chehab 	state->current_agc = agc;
11889a0bf528SMauro Carvalho Chehab 
11899a0bf528SMauro Carvalho Chehab 	/* AGC */
11909a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 76, agc->setup);
11919a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 77, agc->inv_gain);
11929a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 78, agc->time_stabiliz);
11939a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
11949a0bf528SMauro Carvalho Chehab 
11959a0bf528SMauro Carvalho Chehab 	// Demod AGC loop configuration
11969a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
11979a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
11989a0bf528SMauro Carvalho Chehab 
11998af16adfSMauro Carvalho Chehab 	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
12009a0bf528SMauro Carvalho Chehab 		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
12019a0bf528SMauro Carvalho Chehab 
12029a0bf528SMauro Carvalho Chehab 	/* AGC continued */
12039a0bf528SMauro Carvalho Chehab 	if (state->wbd_ref != 0)
12049a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 106, state->wbd_ref);
12059a0bf528SMauro Carvalho Chehab 	else			// use default
12069a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 106, agc->wbd_ref);
12079a0bf528SMauro Carvalho Chehab 
12089a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090) {
12099a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 922) & (0x3 << 2);
12109a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
12119a0bf528SMauro Carvalho Chehab 	}
12129a0bf528SMauro Carvalho Chehab 
12139a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
12149a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 108, agc->agc1_max);
12159a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 109, agc->agc1_min);
12169a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 110, agc->agc2_max);
12179a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 111, agc->agc2_min);
12189a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
12199a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
12209a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
12219a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
12229a0bf528SMauro Carvalho Chehab 
12239a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 75, agc->agc1_pt3);
12249a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
12259a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923,
12269a0bf528SMauro Carvalho Chehab 				(dib8000_read_word(state, 923) & 0xffe3) |
12279a0bf528SMauro Carvalho Chehab 				(agc->wbd_inv << 4) | (agc->wbd_sel << 2));
12289a0bf528SMauro Carvalho Chehab 
12299a0bf528SMauro Carvalho Chehab 	return 0;
12309a0bf528SMauro Carvalho Chehab }
12319a0bf528SMauro Carvalho Chehab 
dib8000_pwm_agc_reset(struct dvb_frontend * fe)1232d44913c1SMauro Carvalho Chehab static void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
12339a0bf528SMauro Carvalho Chehab {
12349a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
12359a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_ADC_ON);
12369a0bf528SMauro Carvalho Chehab 	dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
12379a0bf528SMauro Carvalho Chehab }
12389a0bf528SMauro Carvalho Chehab 
dib8000_agc_soft_split(struct dib8000_state * state)12399a0bf528SMauro Carvalho Chehab static int dib8000_agc_soft_split(struct dib8000_state *state)
12409a0bf528SMauro Carvalho Chehab {
12419a0bf528SMauro Carvalho Chehab 	u16 agc, split_offset;
12429a0bf528SMauro Carvalho Chehab 
12439a0bf528SMauro Carvalho Chehab 	if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
1244d6c62b76SMauro Carvalho Chehab 		return 0;
12459a0bf528SMauro Carvalho Chehab 
12469a0bf528SMauro Carvalho Chehab 	// n_agc_global
12479a0bf528SMauro Carvalho Chehab 	agc = dib8000_read_word(state, 390);
12489a0bf528SMauro Carvalho Chehab 
12499a0bf528SMauro Carvalho Chehab 	if (agc > state->current_agc->split.min_thres)
12509a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.min;
12519a0bf528SMauro Carvalho Chehab 	else if (agc < state->current_agc->split.max_thres)
12529a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.max;
12539a0bf528SMauro Carvalho Chehab 	else
12549a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.max *
12559a0bf528SMauro Carvalho Chehab 			(agc - state->current_agc->split.min_thres) /
12569a0bf528SMauro Carvalho Chehab 			(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
12579a0bf528SMauro Carvalho Chehab 
12588af16adfSMauro Carvalho Chehab 	dprintk("AGC split_offset: %d\n", split_offset);
12599a0bf528SMauro Carvalho Chehab 
12609a0bf528SMauro Carvalho Chehab 	// P_agc_force_split and P_agc_split_offset
12619a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
12629a0bf528SMauro Carvalho Chehab 	return 5000;
12639a0bf528SMauro Carvalho Chehab }
12649a0bf528SMauro Carvalho Chehab 
dib8000_agc_startup(struct dvb_frontend * fe)12659a0bf528SMauro Carvalho Chehab static int dib8000_agc_startup(struct dvb_frontend *fe)
12669a0bf528SMauro Carvalho Chehab {
12679a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
12689a0bf528SMauro Carvalho Chehab 	enum frontend_tune_state *tune_state = &state->tune_state;
12699a0bf528SMauro Carvalho Chehab 	int ret = 0;
1270901c4ad6SMauro Carvalho Chehab 	u16 reg;
1271901c4ad6SMauro Carvalho Chehab 	u32 upd_demod_gain_period = 0x8000;
12729a0bf528SMauro Carvalho Chehab 
12739a0bf528SMauro Carvalho Chehab 	switch (*tune_state) {
12749a0bf528SMauro Carvalho Chehab 	case CT_AGC_START:
12759a0bf528SMauro Carvalho Chehab 		// set power-up level: interf+analog+AGC
12769a0bf528SMauro Carvalho Chehab 
12779a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090)
12789a0bf528SMauro Carvalho Chehab 			dib8000_set_adc_state(state, DIBX000_ADC_ON);
12799a0bf528SMauro Carvalho Chehab 		else {
12809a0bf528SMauro Carvalho Chehab 			dib8000_set_power_mode(state, DIB8000_POWER_ALL);
12819a0bf528SMauro Carvalho Chehab 
12829a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1947)&0xff00;
12839a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1946,
12849a0bf528SMauro Carvalho Chehab 					upd_demod_gain_period & 0xFFFF);
12859a0bf528SMauro Carvalho Chehab 			/* bit 14 = enDemodGain */
12869a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1947, reg | (1<<14) |
12879a0bf528SMauro Carvalho Chehab 					((upd_demod_gain_period >> 16) & 0xFF));
12889a0bf528SMauro Carvalho Chehab 
12899a0bf528SMauro Carvalho Chehab 			/* enable adc i & q */
12909a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1920);
12919a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1920, (reg | 0x3) &
12929a0bf528SMauro Carvalho Chehab 					(~(1 << 7)));
12939a0bf528SMauro Carvalho Chehab 		}
12949a0bf528SMauro Carvalho Chehab 
12959a0bf528SMauro Carvalho Chehab 		if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
12969a0bf528SMauro Carvalho Chehab 			*tune_state = CT_AGC_STOP;
12979a0bf528SMauro Carvalho Chehab 			state->status = FE_STATUS_TUNE_FAILED;
12989a0bf528SMauro Carvalho Chehab 			break;
12999a0bf528SMauro Carvalho Chehab 		}
13009a0bf528SMauro Carvalho Chehab 
13019a0bf528SMauro Carvalho Chehab 		ret = 70;
13029a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STEP_0;
13039a0bf528SMauro Carvalho Chehab 		break;
13049a0bf528SMauro Carvalho Chehab 
13059a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_0:
13069a0bf528SMauro Carvalho Chehab 		//AGC initialization
13079a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
13089a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(fe, 1);
13099a0bf528SMauro Carvalho Chehab 
13109a0bf528SMauro Carvalho Chehab 		dib8000_restart_agc(state);
13119a0bf528SMauro Carvalho Chehab 
13129a0bf528SMauro Carvalho Chehab 		// wait AGC rough lock time
13139a0bf528SMauro Carvalho Chehab 		ret = 50;
13149a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STEP_1;
13159a0bf528SMauro Carvalho Chehab 		break;
13169a0bf528SMauro Carvalho Chehab 
13179a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_1:
13189a0bf528SMauro Carvalho Chehab 		// wait AGC accurate lock time
13199a0bf528SMauro Carvalho Chehab 		ret = 70;
13209a0bf528SMauro Carvalho Chehab 
13219a0bf528SMauro Carvalho Chehab 		if (dib8000_update_lna(state))
13229a0bf528SMauro Carvalho Chehab 			// wait only AGC rough lock time
13239a0bf528SMauro Carvalho Chehab 			ret = 50;
13249a0bf528SMauro Carvalho Chehab 		else
13259a0bf528SMauro Carvalho Chehab 			*tune_state = CT_AGC_STEP_2;
13269a0bf528SMauro Carvalho Chehab 		break;
13279a0bf528SMauro Carvalho Chehab 
13289a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_2:
13299a0bf528SMauro Carvalho Chehab 		dib8000_agc_soft_split(state);
13309a0bf528SMauro Carvalho Chehab 
13319a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
13329a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(fe, 0);
13339a0bf528SMauro Carvalho Chehab 
13349a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STOP;
13359a0bf528SMauro Carvalho Chehab 		break;
13369a0bf528SMauro Carvalho Chehab 	default:
13379a0bf528SMauro Carvalho Chehab 		ret = dib8000_agc_soft_split(state);
13389a0bf528SMauro Carvalho Chehab 		break;
13399a0bf528SMauro Carvalho Chehab 	}
13409a0bf528SMauro Carvalho Chehab 	return ret;
13419a0bf528SMauro Carvalho Chehab 
13429a0bf528SMauro Carvalho Chehab }
13439a0bf528SMauro Carvalho Chehab 
dib8096p_host_bus_drive(struct dib8000_state * state,u8 drive)13449a0bf528SMauro Carvalho Chehab static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
13459a0bf528SMauro Carvalho Chehab {
13469a0bf528SMauro Carvalho Chehab 	u16 reg;
13479a0bf528SMauro Carvalho Chehab 
13489a0bf528SMauro Carvalho Chehab 	drive &= 0x7;
13499a0bf528SMauro Carvalho Chehab 
13509a0bf528SMauro Carvalho Chehab 	/* drive host bus 2, 3, 4 */
13519a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1798) &
13529a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
13539a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
13549a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1798, reg);
13559a0bf528SMauro Carvalho Chehab 
13569a0bf528SMauro Carvalho Chehab 	/* drive host bus 5,6 */
13579a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
13589a0bf528SMauro Carvalho Chehab 	reg |= (drive<<8) | (drive<<2);
13599a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1799, reg);
13609a0bf528SMauro Carvalho Chehab 
13619a0bf528SMauro Carvalho Chehab 	/* drive host bus 7, 8, 9 */
13629a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1800) &
13639a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
13649a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
13659a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1800, reg);
13669a0bf528SMauro Carvalho Chehab 
13679a0bf528SMauro Carvalho Chehab 	/* drive host bus 10, 11 */
13689a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
13699a0bf528SMauro Carvalho Chehab 	reg |= (drive<<8) | (drive<<2);
13709a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1801, reg);
13719a0bf528SMauro Carvalho Chehab 
13729a0bf528SMauro Carvalho Chehab 	/* drive host bus 12, 13, 14 */
13739a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1802) &
13749a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
13759a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
13769a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1802, reg);
13779a0bf528SMauro Carvalho Chehab }
13789a0bf528SMauro Carvalho Chehab 
dib8096p_calcSyncFreq(u32 P_Kin,u32 P_Kout,u32 insertExtSynchro,u32 syncSize)13799a0bf528SMauro Carvalho Chehab static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
13809a0bf528SMauro Carvalho Chehab 		u32 insertExtSynchro, u32 syncSize)
13819a0bf528SMauro Carvalho Chehab {
13829a0bf528SMauro Carvalho Chehab 	u32 quantif = 3;
13839a0bf528SMauro Carvalho Chehab 	u32 nom = (insertExtSynchro * P_Kin+syncSize);
13849a0bf528SMauro Carvalho Chehab 	u32 denom = P_Kout;
13859a0bf528SMauro Carvalho Chehab 	u32 syncFreq = ((nom << quantif) / denom);
13869a0bf528SMauro Carvalho Chehab 
13879a0bf528SMauro Carvalho Chehab 	if ((syncFreq & ((1 << quantif) - 1)) != 0)
13889a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif) + 1;
13899a0bf528SMauro Carvalho Chehab 	else
13909a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif);
13919a0bf528SMauro Carvalho Chehab 
13929a0bf528SMauro Carvalho Chehab 	if (syncFreq != 0)
13939a0bf528SMauro Carvalho Chehab 		syncFreq = syncFreq - 1;
13949a0bf528SMauro Carvalho Chehab 
13959a0bf528SMauro Carvalho Chehab 	return syncFreq;
13969a0bf528SMauro Carvalho Chehab }
13979a0bf528SMauro Carvalho Chehab 
dib8096p_cfg_DibTx(struct dib8000_state * state,u32 P_Kin,u32 P_Kout,u32 insertExtSynchro,u32 synchroMode,u32 syncWord,u32 syncSize)13989a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
13999a0bf528SMauro Carvalho Chehab 		u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
14009a0bf528SMauro Carvalho Chehab 		u32 syncWord, u32 syncSize)
14019a0bf528SMauro Carvalho Chehab {
14028af16adfSMauro Carvalho Chehab 	dprintk("Configure DibStream Tx\n");
14039a0bf528SMauro Carvalho Chehab 
14049a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1615, 1);
14059a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1603, P_Kin);
14069a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1605, P_Kout);
14079a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1606, insertExtSynchro);
14089a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1608, synchroMode);
14099a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
14109a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1610, syncWord & 0xffff);
14119a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1612, syncSize);
14129a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1615, 0);
14139a0bf528SMauro Carvalho Chehab }
14149a0bf528SMauro Carvalho Chehab 
dib8096p_cfg_DibRx(struct dib8000_state * state,u32 P_Kin,u32 P_Kout,u32 synchroMode,u32 insertExtSynchro,u32 syncWord,u32 syncSize,u32 dataOutRate)14159a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
14169a0bf528SMauro Carvalho Chehab 		u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
14179a0bf528SMauro Carvalho Chehab 		u32 syncWord, u32 syncSize, u32 dataOutRate)
14189a0bf528SMauro Carvalho Chehab {
14199a0bf528SMauro Carvalho Chehab 	u32 syncFreq;
14209a0bf528SMauro Carvalho Chehab 
14218af16adfSMauro Carvalho Chehab 	dprintk("Configure DibStream Rx synchroMode = %d\n", synchroMode);
14229a0bf528SMauro Carvalho Chehab 
14239a0bf528SMauro Carvalho Chehab 	if ((P_Kin != 0) && (P_Kout != 0)) {
14249a0bf528SMauro Carvalho Chehab 		syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
14259a0bf528SMauro Carvalho Chehab 				insertExtSynchro, syncSize);
14269a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1542, syncFreq);
14279a0bf528SMauro Carvalho Chehab 	}
14289a0bf528SMauro Carvalho Chehab 
14299a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1554, 1);
14309a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1536, P_Kin);
14319a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1537, P_Kout);
14329a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1539, synchroMode);
14339a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
14349a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1541, syncWord & 0xffff);
14359a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1543, syncSize);
14369a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1544, dataOutRate);
14379a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1554, 0);
14389a0bf528SMauro Carvalho Chehab }
14399a0bf528SMauro Carvalho Chehab 
dib8096p_enMpegMux(struct dib8000_state * state,int onoff)14409a0bf528SMauro Carvalho Chehab static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
14419a0bf528SMauro Carvalho Chehab {
14429a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
14439a0bf528SMauro Carvalho Chehab 
14449a0bf528SMauro Carvalho Chehab 	reg_1287 = dib8000_read_word(state, 1287);
14459a0bf528SMauro Carvalho Chehab 
14469a0bf528SMauro Carvalho Chehab 	switch (onoff) {
14479a0bf528SMauro Carvalho Chehab 	case 1:
14489a0bf528SMauro Carvalho Chehab 			reg_1287 &= ~(1 << 8);
14499a0bf528SMauro Carvalho Chehab 			break;
14509a0bf528SMauro Carvalho Chehab 	case 0:
14519a0bf528SMauro Carvalho Chehab 			reg_1287 |= (1 << 8);
14529a0bf528SMauro Carvalho Chehab 			break;
14539a0bf528SMauro Carvalho Chehab 	}
14549a0bf528SMauro Carvalho Chehab 
14559a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1287, reg_1287);
14569a0bf528SMauro Carvalho Chehab }
14579a0bf528SMauro Carvalho Chehab 
dib8096p_configMpegMux(struct dib8000_state * state,u16 pulseWidth,u16 enSerialMode,u16 enSerialClkDiv2)14589a0bf528SMauro Carvalho Chehab static void dib8096p_configMpegMux(struct dib8000_state *state,
14599a0bf528SMauro Carvalho Chehab 		u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
14609a0bf528SMauro Carvalho Chehab {
14619a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
14629a0bf528SMauro Carvalho Chehab 
14638af16adfSMauro Carvalho Chehab 	dprintk("Enable Mpeg mux\n");
14649a0bf528SMauro Carvalho Chehab 
14659a0bf528SMauro Carvalho Chehab 	dib8096p_enMpegMux(state, 0);
14669a0bf528SMauro Carvalho Chehab 
14679a0bf528SMauro Carvalho Chehab 	/* If the input mode is MPEG do not divide the serial clock */
14689a0bf528SMauro Carvalho Chehab 	if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
14699a0bf528SMauro Carvalho Chehab 		enSerialClkDiv2 = 0;
14709a0bf528SMauro Carvalho Chehab 
14719a0bf528SMauro Carvalho Chehab 	reg_1287 = ((pulseWidth & 0x1f) << 3) |
14729a0bf528SMauro Carvalho Chehab 		((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
14739a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1287, reg_1287);
14749a0bf528SMauro Carvalho Chehab 
14759a0bf528SMauro Carvalho Chehab 	dib8096p_enMpegMux(state, 1);
14769a0bf528SMauro Carvalho Chehab }
14779a0bf528SMauro Carvalho Chehab 
dib8096p_setDibTxMux(struct dib8000_state * state,int mode)14789a0bf528SMauro Carvalho Chehab static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
14799a0bf528SMauro Carvalho Chehab {
14809a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
14819a0bf528SMauro Carvalho Chehab 
14829a0bf528SMauro Carvalho Chehab 	switch (mode) {
14839a0bf528SMauro Carvalho Chehab 	case MPEG_ON_DIBTX:
14848af16adfSMauro Carvalho Chehab 			dprintk("SET MPEG ON DIBSTREAM TX\n");
14859a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
14869a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 9); break;
14879a0bf528SMauro Carvalho Chehab 	case DIV_ON_DIBTX:
14888af16adfSMauro Carvalho Chehab 			dprintk("SET DIV_OUT ON DIBSTREAM TX\n");
14899a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
14909a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 8); break;
14919a0bf528SMauro Carvalho Chehab 	case ADC_ON_DIBTX:
14928af16adfSMauro Carvalho Chehab 			dprintk("SET ADC_OUT ON DIBSTREAM TX\n");
14939a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
14949a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 7); break;
14959a0bf528SMauro Carvalho Chehab 	default:
14969a0bf528SMauro Carvalho Chehab 			break;
14979a0bf528SMauro Carvalho Chehab 	}
14989a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1288, reg_1288);
14999a0bf528SMauro Carvalho Chehab }
15009a0bf528SMauro Carvalho Chehab 
dib8096p_setHostBusMux(struct dib8000_state * state,int mode)15019a0bf528SMauro Carvalho Chehab static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
15029a0bf528SMauro Carvalho Chehab {
15039a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
15049a0bf528SMauro Carvalho Chehab 
15059a0bf528SMauro Carvalho Chehab 	switch (mode) {
15069a0bf528SMauro Carvalho Chehab 	case DEMOUT_ON_HOSTBUS:
15078af16adfSMauro Carvalho Chehab 			dprintk("SET DEM OUT OLD INTERF ON HOST BUS\n");
15089a0bf528SMauro Carvalho Chehab 			dib8096p_enMpegMux(state, 0);
15099a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 6);
15109a0bf528SMauro Carvalho Chehab 			break;
15119a0bf528SMauro Carvalho Chehab 	case DIBTX_ON_HOSTBUS:
15128af16adfSMauro Carvalho Chehab 			dprintk("SET DIBSTREAM TX ON HOST BUS\n");
15139a0bf528SMauro Carvalho Chehab 			dib8096p_enMpegMux(state, 0);
15149a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 5);
15159a0bf528SMauro Carvalho Chehab 			break;
15169a0bf528SMauro Carvalho Chehab 	case MPEG_ON_HOSTBUS:
15178af16adfSMauro Carvalho Chehab 			dprintk("SET MPEG MUX ON HOST BUS\n");
15189a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 4);
15199a0bf528SMauro Carvalho Chehab 			break;
15209a0bf528SMauro Carvalho Chehab 	default:
15219a0bf528SMauro Carvalho Chehab 			break;
15229a0bf528SMauro Carvalho Chehab 	}
15239a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1288, reg_1288);
15249a0bf528SMauro Carvalho Chehab }
15259a0bf528SMauro Carvalho Chehab 
dib8096p_set_diversity_in(struct dvb_frontend * fe,int onoff)15269a0bf528SMauro Carvalho Chehab static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
15279a0bf528SMauro Carvalho Chehab {
15289a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
15299a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
15309a0bf528SMauro Carvalho Chehab 
15319a0bf528SMauro Carvalho Chehab 	switch (onoff) {
15329a0bf528SMauro Carvalho Chehab 	case 0: /* only use the internal way - not the diversity input */
15338af16adfSMauro Carvalho Chehab 			dprintk("%s mode OFF : by default Enable Mpeg INPUT\n",
15349a0bf528SMauro Carvalho Chehab 					__func__);
15359a0bf528SMauro Carvalho Chehab 			/* outputRate = 8 */
15369a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
15379a0bf528SMauro Carvalho Chehab 
15389a0bf528SMauro Carvalho Chehab 			/* Do not divide the serial clock of MPEG MUX in
15399a0bf528SMauro Carvalho Chehab 			   SERIAL MODE in case input mode MPEG is used */
15409a0bf528SMauro Carvalho Chehab 			reg_1287 = dib8000_read_word(state, 1287);
15419a0bf528SMauro Carvalho Chehab 			/* enSerialClkDiv2 == 1 ? */
15429a0bf528SMauro Carvalho Chehab 			if ((reg_1287 & 0x1) == 1) {
15439a0bf528SMauro Carvalho Chehab 				/* force enSerialClkDiv2 = 0 */
15449a0bf528SMauro Carvalho Chehab 				reg_1287 &= ~0x1;
15459a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, 1287, reg_1287);
15469a0bf528SMauro Carvalho Chehab 			}
15479a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 1;
15489a0bf528SMauro Carvalho Chehab 			break;
15499a0bf528SMauro Carvalho Chehab 	case 1: /* both ways */
15509a0bf528SMauro Carvalho Chehab 	case 2: /* only the diversity input */
15518af16adfSMauro Carvalho Chehab 			dprintk("%s ON : Enable diversity INPUT\n", __func__);
15529a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
15539a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 0;
15549a0bf528SMauro Carvalho Chehab 			break;
15559a0bf528SMauro Carvalho Chehab 	}
15569a0bf528SMauro Carvalho Chehab 
15579a0bf528SMauro Carvalho Chehab 	dib8000_set_diversity_in(state->fe[0], onoff);
15589a0bf528SMauro Carvalho Chehab 	return 0;
15599a0bf528SMauro Carvalho Chehab }
15609a0bf528SMauro Carvalho Chehab 
dib8096p_set_output_mode(struct dvb_frontend * fe,int mode)15619a0bf528SMauro Carvalho Chehab static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
15629a0bf528SMauro Carvalho Chehab {
15639a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
15649a0bf528SMauro Carvalho Chehab 	u16 outreg, smo_mode, fifo_threshold;
15659a0bf528SMauro Carvalho Chehab 	u8 prefer_mpeg_mux_use = 1;
15669a0bf528SMauro Carvalho Chehab 	int ret = 0;
15679a0bf528SMauro Carvalho Chehab 
1568173a64cbSPatrick Boettcher 	state->output_mode = mode;
15699a0bf528SMauro Carvalho Chehab 	dib8096p_host_bus_drive(state, 1);
15709a0bf528SMauro Carvalho Chehab 
15719a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
15729a0bf528SMauro Carvalho Chehab 	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
15739a0bf528SMauro Carvalho Chehab 	outreg   = dib8000_read_word(state, 1286) &
15749a0bf528SMauro Carvalho Chehab 		~((1 << 10) | (0x7 << 6) | (1 << 1));
15759a0bf528SMauro Carvalho Chehab 
15769a0bf528SMauro Carvalho Chehab 	switch (mode) {
15779a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:
15789a0bf528SMauro Carvalho Chehab 			outreg = 0;
15799a0bf528SMauro Carvalho Chehab 			break;
15809a0bf528SMauro Carvalho Chehab 
15819a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:
15829a0bf528SMauro Carvalho Chehab 			if (prefer_mpeg_mux_use) {
15838af16adfSMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux\n");
15849a0bf528SMauro Carvalho Chehab 				dib8096p_configMpegMux(state, 3, 1, 1);
15859a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
15869a0bf528SMauro Carvalho Chehab 			} else {/* Use Smooth block */
15878af16adfSMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc\n");
15889a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state,
15899a0bf528SMauro Carvalho Chehab 						DEMOUT_ON_HOSTBUS);
15909a0bf528SMauro Carvalho Chehab 				outreg |= (2 << 6) | (0 << 1);
15919a0bf528SMauro Carvalho Chehab 			}
15929a0bf528SMauro Carvalho Chehab 			break;
15939a0bf528SMauro Carvalho Chehab 
15949a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:
15959a0bf528SMauro Carvalho Chehab 			if (prefer_mpeg_mux_use) {
15968af16adfSMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux\n");
15979a0bf528SMauro Carvalho Chehab 				dib8096p_configMpegMux(state, 2, 0, 0);
15989a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
15999a0bf528SMauro Carvalho Chehab 			} else { /* Use Smooth block */
16008af16adfSMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block\n");
16019a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state,
16029a0bf528SMauro Carvalho Chehab 						DEMOUT_ON_HOSTBUS);
16039a0bf528SMauro Carvalho Chehab 				outreg |= (0 << 6);
16049a0bf528SMauro Carvalho Chehab 			}
16059a0bf528SMauro Carvalho Chehab 			break;
16069a0bf528SMauro Carvalho Chehab 
16079a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
16088af16adfSMauro Carvalho Chehab 			dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block\n");
16099a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
16109a0bf528SMauro Carvalho Chehab 			outreg |= (1 << 6);
16119a0bf528SMauro Carvalho Chehab 			break;
16129a0bf528SMauro Carvalho Chehab 
16139a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:
16149a0bf528SMauro Carvalho Chehab 			/* Using Smooth block because not supported
16159a0bf528SMauro Carvalho Chehab 			   by new Mpeg Mux bloc */
16168af16adfSMauro Carvalho Chehab 			dprintk("dib8096P setting output mode TS_FIFO using Smooth block\n");
16179a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
16189a0bf528SMauro Carvalho Chehab 			outreg |= (5 << 6);
16199a0bf528SMauro Carvalho Chehab 			smo_mode |= (3 << 1);
16209a0bf528SMauro Carvalho Chehab 			fifo_threshold = 512;
16219a0bf528SMauro Carvalho Chehab 			break;
16229a0bf528SMauro Carvalho Chehab 
16239a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
16248af16adfSMauro Carvalho Chehab 			dprintk("dib8096P setting output mode MODE_DIVERSITY\n");
16259a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
16269a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
16279a0bf528SMauro Carvalho Chehab 			break;
16289a0bf528SMauro Carvalho Chehab 
16299a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
16308af16adfSMauro Carvalho Chehab 			dprintk("dib8096P setting output mode MODE_ANALOG_ADC\n");
16319a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
16329a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
16339a0bf528SMauro Carvalho Chehab 			break;
16349a0bf528SMauro Carvalho Chehab 	}
16359a0bf528SMauro Carvalho Chehab 
16369a0bf528SMauro Carvalho Chehab 	if (mode != OUTMODE_HIGH_Z)
16379a0bf528SMauro Carvalho Chehab 		outreg |= (1<<10);
16389a0bf528SMauro Carvalho Chehab 
16398af16adfSMauro Carvalho Chehab 	dprintk("output_mpeg2_in_188_bytes = %d\n",
16409a0bf528SMauro Carvalho Chehab 			state->cfg.output_mpeg2_in_188_bytes);
16419a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
16429a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
16439a0bf528SMauro Carvalho Chehab 
16449a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 299, smo_mode);
16459a0bf528SMauro Carvalho Chehab 	/* synchronous fread */
16469a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
16479a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 1286, outreg);
16489a0bf528SMauro Carvalho Chehab 
16499a0bf528SMauro Carvalho Chehab 	return ret;
16509a0bf528SMauro Carvalho Chehab }
16519a0bf528SMauro Carvalho Chehab 
map_addr_to_serpar_number(struct i2c_msg * msg)16529a0bf528SMauro Carvalho Chehab static int map_addr_to_serpar_number(struct i2c_msg *msg)
16539a0bf528SMauro Carvalho Chehab {
16549a0bf528SMauro Carvalho Chehab 	if (msg->buf[0] <= 15)
16559a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 1;
16569a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 17)
16579a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 15;
16589a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 16)
16599a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 17;
16609a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 19)
16619a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 16;
16629a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
16639a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 3;
16649a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 28)
16659a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 23;
16669a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 99)
16679a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 99;
16689a0bf528SMauro Carvalho Chehab 	else
16699a0bf528SMauro Carvalho Chehab 		return -EINVAL;
16709a0bf528SMauro Carvalho Chehab 	return 0;
16719a0bf528SMauro Carvalho Chehab }
16729a0bf528SMauro Carvalho Chehab 
dib8096p_tuner_write_serpar(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num)16739a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
16749a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
16759a0bf528SMauro Carvalho Chehab {
16769a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
16779a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1;
16789a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
16799a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
16809a0bf528SMauro Carvalho Chehab 
16819a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
16829a0bf528SMauro Carvalho Chehab 		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
16839a0bf528SMauro Carvalho Chehab 		i--;
16849a0bf528SMauro Carvalho Chehab 		if (i == 0)
16858af16adfSMauro Carvalho Chehab 			dprintk("Tuner ITF: write busy (overflow)\n");
16869a0bf528SMauro Carvalho Chehab 	}
16879a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
16889a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
16899a0bf528SMauro Carvalho Chehab 
16909a0bf528SMauro Carvalho Chehab 	return num;
16919a0bf528SMauro Carvalho Chehab }
16929a0bf528SMauro Carvalho Chehab 
dib8096p_tuner_read_serpar(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num)16939a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
16949a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
16959a0bf528SMauro Carvalho Chehab {
16969a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
16979a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1, n_empty = 1;
16989a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
16999a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
17009a0bf528SMauro Carvalho Chehab 	u16 read_word;
17019a0bf528SMauro Carvalho Chehab 
17029a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
17039a0bf528SMauro Carvalho Chehab 		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
17049a0bf528SMauro Carvalho Chehab 		i--;
17059a0bf528SMauro Carvalho Chehab 		if (i == 0)
17068af16adfSMauro Carvalho Chehab 			dprintk("TunerITF: read busy (overflow)\n");
17079a0bf528SMauro Carvalho Chehab 	}
17089a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
17099a0bf528SMauro Carvalho Chehab 
17109a0bf528SMauro Carvalho Chehab 	i = 1000;
17119a0bf528SMauro Carvalho Chehab 	while (n_empty == 1 && i) {
17129a0bf528SMauro Carvalho Chehab 		n_empty = dib8000_read_word(state, 1984)&0x1;
17139a0bf528SMauro Carvalho Chehab 		i--;
17149a0bf528SMauro Carvalho Chehab 		if (i == 0)
17158af16adfSMauro Carvalho Chehab 			dprintk("TunerITF: read busy (empty)\n");
17169a0bf528SMauro Carvalho Chehab 	}
17179a0bf528SMauro Carvalho Chehab 
17189a0bf528SMauro Carvalho Chehab 	read_word = dib8000_read_word(state, 1987);
17199a0bf528SMauro Carvalho Chehab 	msg[1].buf[0] = (read_word >> 8) & 0xff;
17209a0bf528SMauro Carvalho Chehab 	msg[1].buf[1] = (read_word) & 0xff;
17219a0bf528SMauro Carvalho Chehab 
17229a0bf528SMauro Carvalho Chehab 	return num;
17239a0bf528SMauro Carvalho Chehab }
17249a0bf528SMauro Carvalho Chehab 
dib8096p_tuner_rw_serpar(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num)17259a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
17269a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
17279a0bf528SMauro Carvalho Chehab {
17289a0bf528SMauro Carvalho Chehab 	if (map_addr_to_serpar_number(&msg[0]) == 0) {
17299a0bf528SMauro Carvalho Chehab 		if (num == 1) /* write */
17309a0bf528SMauro Carvalho Chehab 			return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
17319a0bf528SMauro Carvalho Chehab 		else /* read */
17329a0bf528SMauro Carvalho Chehab 			return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
17339a0bf528SMauro Carvalho Chehab 	}
17349a0bf528SMauro Carvalho Chehab 	return num;
17359a0bf528SMauro Carvalho Chehab }
17369a0bf528SMauro Carvalho Chehab 
dib8096p_rw_on_apb(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num,u16 apb_address)17379a0bf528SMauro Carvalho Chehab static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
17389a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num, u16 apb_address)
17399a0bf528SMauro Carvalho Chehab {
17409a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
17419a0bf528SMauro Carvalho Chehab 	u16 word;
17429a0bf528SMauro Carvalho Chehab 
17439a0bf528SMauro Carvalho Chehab 	if (num == 1) {		/* write */
17449a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, apb_address,
17459a0bf528SMauro Carvalho Chehab 				((msg[0].buf[1] << 8) | (msg[0].buf[2])));
17469a0bf528SMauro Carvalho Chehab 	} else {
17479a0bf528SMauro Carvalho Chehab 		word = dib8000_read_word(state, apb_address);
17489a0bf528SMauro Carvalho Chehab 		msg[1].buf[0] = (word >> 8) & 0xff;
17499a0bf528SMauro Carvalho Chehab 		msg[1].buf[1] = (word) & 0xff;
17509a0bf528SMauro Carvalho Chehab 	}
17519a0bf528SMauro Carvalho Chehab 	return num;
17529a0bf528SMauro Carvalho Chehab }
17539a0bf528SMauro Carvalho Chehab 
dib8096p_tuner_xfer(struct i2c_adapter * i2c_adap,struct i2c_msg msg[],int num)17549a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
17559a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
17569a0bf528SMauro Carvalho Chehab {
17579a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
17589a0bf528SMauro Carvalho Chehab 	u16 apb_address = 0, word;
17599a0bf528SMauro Carvalho Chehab 	int i = 0;
17609a0bf528SMauro Carvalho Chehab 
17619a0bf528SMauro Carvalho Chehab 	switch (msg[0].buf[0]) {
17629a0bf528SMauro Carvalho Chehab 	case 0x12:
17639a0bf528SMauro Carvalho Chehab 			apb_address = 1920;
17649a0bf528SMauro Carvalho Chehab 			break;
17659a0bf528SMauro Carvalho Chehab 	case 0x14:
17669a0bf528SMauro Carvalho Chehab 			apb_address = 1921;
17679a0bf528SMauro Carvalho Chehab 			break;
17689a0bf528SMauro Carvalho Chehab 	case 0x24:
17699a0bf528SMauro Carvalho Chehab 			apb_address = 1922;
17709a0bf528SMauro Carvalho Chehab 			break;
17719a0bf528SMauro Carvalho Chehab 	case 0x1a:
17729a0bf528SMauro Carvalho Chehab 			apb_address = 1923;
17739a0bf528SMauro Carvalho Chehab 			break;
17749a0bf528SMauro Carvalho Chehab 	case 0x22:
17759a0bf528SMauro Carvalho Chehab 			apb_address = 1924;
17769a0bf528SMauro Carvalho Chehab 			break;
17779a0bf528SMauro Carvalho Chehab 	case 0x33:
17789a0bf528SMauro Carvalho Chehab 			apb_address = 1926;
17799a0bf528SMauro Carvalho Chehab 			break;
17809a0bf528SMauro Carvalho Chehab 	case 0x34:
17819a0bf528SMauro Carvalho Chehab 			apb_address = 1927;
17829a0bf528SMauro Carvalho Chehab 			break;
17839a0bf528SMauro Carvalho Chehab 	case 0x35:
17849a0bf528SMauro Carvalho Chehab 			apb_address = 1928;
17859a0bf528SMauro Carvalho Chehab 			break;
17869a0bf528SMauro Carvalho Chehab 	case 0x36:
17879a0bf528SMauro Carvalho Chehab 			apb_address = 1929;
17889a0bf528SMauro Carvalho Chehab 			break;
17899a0bf528SMauro Carvalho Chehab 	case 0x37:
17909a0bf528SMauro Carvalho Chehab 			apb_address = 1930;
17919a0bf528SMauro Carvalho Chehab 			break;
17929a0bf528SMauro Carvalho Chehab 	case 0x38:
17939a0bf528SMauro Carvalho Chehab 			apb_address = 1931;
17949a0bf528SMauro Carvalho Chehab 			break;
17959a0bf528SMauro Carvalho Chehab 	case 0x39:
17969a0bf528SMauro Carvalho Chehab 			apb_address = 1932;
17979a0bf528SMauro Carvalho Chehab 			break;
17989a0bf528SMauro Carvalho Chehab 	case 0x2a:
17999a0bf528SMauro Carvalho Chehab 			apb_address = 1935;
18009a0bf528SMauro Carvalho Chehab 			break;
18019a0bf528SMauro Carvalho Chehab 	case 0x2b:
18029a0bf528SMauro Carvalho Chehab 			apb_address = 1936;
18039a0bf528SMauro Carvalho Chehab 			break;
18049a0bf528SMauro Carvalho Chehab 	case 0x2c:
18059a0bf528SMauro Carvalho Chehab 			apb_address = 1937;
18069a0bf528SMauro Carvalho Chehab 			break;
18079a0bf528SMauro Carvalho Chehab 	case 0x2d:
18089a0bf528SMauro Carvalho Chehab 			apb_address = 1938;
18099a0bf528SMauro Carvalho Chehab 			break;
18109a0bf528SMauro Carvalho Chehab 	case 0x2e:
18119a0bf528SMauro Carvalho Chehab 			apb_address = 1939;
18129a0bf528SMauro Carvalho Chehab 			break;
18139a0bf528SMauro Carvalho Chehab 	case 0x2f:
18149a0bf528SMauro Carvalho Chehab 			apb_address = 1940;
18159a0bf528SMauro Carvalho Chehab 			break;
18169a0bf528SMauro Carvalho Chehab 	case 0x30:
18179a0bf528SMauro Carvalho Chehab 			apb_address = 1941;
18189a0bf528SMauro Carvalho Chehab 			break;
18199a0bf528SMauro Carvalho Chehab 	case 0x31:
18209a0bf528SMauro Carvalho Chehab 			apb_address = 1942;
18219a0bf528SMauro Carvalho Chehab 			break;
18229a0bf528SMauro Carvalho Chehab 	case 0x32:
18239a0bf528SMauro Carvalho Chehab 			apb_address = 1943;
18249a0bf528SMauro Carvalho Chehab 			break;
18259a0bf528SMauro Carvalho Chehab 	case 0x3e:
18269a0bf528SMauro Carvalho Chehab 			apb_address = 1944;
18279a0bf528SMauro Carvalho Chehab 			break;
18289a0bf528SMauro Carvalho Chehab 	case 0x3f:
18299a0bf528SMauro Carvalho Chehab 			apb_address = 1945;
18309a0bf528SMauro Carvalho Chehab 			break;
18319a0bf528SMauro Carvalho Chehab 	case 0x40:
18329a0bf528SMauro Carvalho Chehab 			apb_address = 1948;
18339a0bf528SMauro Carvalho Chehab 			break;
18349a0bf528SMauro Carvalho Chehab 	case 0x25:
18359a0bf528SMauro Carvalho Chehab 			apb_address = 936;
18369a0bf528SMauro Carvalho Chehab 			break;
18379a0bf528SMauro Carvalho Chehab 	case 0x26:
18389a0bf528SMauro Carvalho Chehab 			apb_address = 937;
18399a0bf528SMauro Carvalho Chehab 			break;
18409a0bf528SMauro Carvalho Chehab 	case 0x27:
18419a0bf528SMauro Carvalho Chehab 			apb_address = 938;
18429a0bf528SMauro Carvalho Chehab 			break;
18439a0bf528SMauro Carvalho Chehab 	case 0x28:
18449a0bf528SMauro Carvalho Chehab 			apb_address = 939;
18459a0bf528SMauro Carvalho Chehab 			break;
18469a0bf528SMauro Carvalho Chehab 	case 0x1d:
18479a0bf528SMauro Carvalho Chehab 			/* get sad sel request */
18489a0bf528SMauro Carvalho Chehab 			i = ((dib8000_read_word(state, 921) >> 12)&0x3);
18499a0bf528SMauro Carvalho Chehab 			word = dib8000_read_word(state, 924+i);
18509a0bf528SMauro Carvalho Chehab 			msg[1].buf[0] = (word >> 8) & 0xff;
18519a0bf528SMauro Carvalho Chehab 			msg[1].buf[1] = (word) & 0xff;
18529a0bf528SMauro Carvalho Chehab 			return num;
18539a0bf528SMauro Carvalho Chehab 	case 0x1f:
18549a0bf528SMauro Carvalho Chehab 			if (num == 1) {	/* write */
18559a0bf528SMauro Carvalho Chehab 				word = (u16) ((msg[0].buf[1] << 8) |
18569a0bf528SMauro Carvalho Chehab 						msg[0].buf[2]);
18579a0bf528SMauro Carvalho Chehab 				/* in the VGAMODE Sel are located on bit 0/1 */
18589a0bf528SMauro Carvalho Chehab 				word &= 0x3;
18599a0bf528SMauro Carvalho Chehab 				word = (dib8000_read_word(state, 921) &
18609a0bf528SMauro Carvalho Chehab 						~(3<<12)) | (word<<12);
18619a0bf528SMauro Carvalho Chehab 				/* Set the proper input */
18629a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, 921, word);
18639a0bf528SMauro Carvalho Chehab 				return num;
18649a0bf528SMauro Carvalho Chehab 			}
18659a0bf528SMauro Carvalho Chehab 	}
18669a0bf528SMauro Carvalho Chehab 
1867868c9a17SMauro Carvalho Chehab 	if (apb_address != 0) /* R/W access via APB */
18689a0bf528SMauro Carvalho Chehab 		return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
18699a0bf528SMauro Carvalho Chehab 	else  /* R/W access via SERPAR  */
18709a0bf528SMauro Carvalho Chehab 		return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
18719a0bf528SMauro Carvalho Chehab 
18729a0bf528SMauro Carvalho Chehab 	return 0;
18739a0bf528SMauro Carvalho Chehab }
18749a0bf528SMauro Carvalho Chehab 
dib8096p_i2c_func(struct i2c_adapter * adapter)18759a0bf528SMauro Carvalho Chehab static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
18769a0bf528SMauro Carvalho Chehab {
18779a0bf528SMauro Carvalho Chehab 	return I2C_FUNC_I2C;
18789a0bf528SMauro Carvalho Chehab }
18799a0bf528SMauro Carvalho Chehab 
188028e83542SGustavo A. R. Silva static const struct i2c_algorithm dib8096p_tuner_xfer_algo = {
18819a0bf528SMauro Carvalho Chehab 	.master_xfer = dib8096p_tuner_xfer,
18829a0bf528SMauro Carvalho Chehab 	.functionality = dib8096p_i2c_func,
18839a0bf528SMauro Carvalho Chehab };
18849a0bf528SMauro Carvalho Chehab 
dib8096p_get_i2c_tuner(struct dvb_frontend * fe)1885d44913c1SMauro Carvalho Chehab static struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
18869a0bf528SMauro Carvalho Chehab {
18879a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
18889a0bf528SMauro Carvalho Chehab 	return &st->dib8096p_tuner_adap;
18899a0bf528SMauro Carvalho Chehab }
18909a0bf528SMauro Carvalho Chehab 
dib8096p_tuner_sleep(struct dvb_frontend * fe,int onoff)1891d44913c1SMauro Carvalho Chehab static int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
18929a0bf528SMauro Carvalho Chehab {
18939a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
18949a0bf528SMauro Carvalho Chehab 	u16 en_cur_state;
18959a0bf528SMauro Carvalho Chehab 
18968af16adfSMauro Carvalho Chehab 	dprintk("sleep dib8096p: %d\n", onoff);
18979a0bf528SMauro Carvalho Chehab 
18989a0bf528SMauro Carvalho Chehab 	en_cur_state = dib8000_read_word(state, 1922);
18999a0bf528SMauro Carvalho Chehab 
19009a0bf528SMauro Carvalho Chehab 	/* LNAs and MIX are ON and therefore it is a valid configuration */
19019a0bf528SMauro Carvalho Chehab 	if (en_cur_state > 0xff)
19029a0bf528SMauro Carvalho Chehab 		state->tuner_enable = en_cur_state ;
19039a0bf528SMauro Carvalho Chehab 
19049a0bf528SMauro Carvalho Chehab 	if (onoff)
19059a0bf528SMauro Carvalho Chehab 		en_cur_state &= 0x00ff;
19069a0bf528SMauro Carvalho Chehab 	else {
19079a0bf528SMauro Carvalho Chehab 		if (state->tuner_enable != 0)
19089a0bf528SMauro Carvalho Chehab 			en_cur_state = state->tuner_enable;
19099a0bf528SMauro Carvalho Chehab 	}
19109a0bf528SMauro Carvalho Chehab 
19119a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1922, en_cur_state);
19129a0bf528SMauro Carvalho Chehab 
19139a0bf528SMauro Carvalho Chehab 	return 0;
19149a0bf528SMauro Carvalho Chehab }
19159a0bf528SMauro Carvalho Chehab 
19169a0bf528SMauro Carvalho Chehab static const s32 lut_1000ln_mant[] =
19179a0bf528SMauro Carvalho Chehab {
19189a0bf528SMauro Carvalho Chehab 	908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
19199a0bf528SMauro Carvalho Chehab };
19209a0bf528SMauro Carvalho Chehab 
dib8000_get_adc_power(struct dvb_frontend * fe,u8 mode)1921d44913c1SMauro Carvalho Chehab static s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
19229a0bf528SMauro Carvalho Chehab {
19239a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
19249a0bf528SMauro Carvalho Chehab 	u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
19259a0bf528SMauro Carvalho Chehab 	s32 val;
19269a0bf528SMauro Carvalho Chehab 
19279a0bf528SMauro Carvalho Chehab 	val = dib8000_read32(state, 384);
19289a0bf528SMauro Carvalho Chehab 	if (mode) {
19299a0bf528SMauro Carvalho Chehab 		tmp_val = val;
19309a0bf528SMauro Carvalho Chehab 		while (tmp_val >>= 1)
19319a0bf528SMauro Carvalho Chehab 			exp++;
19329a0bf528SMauro Carvalho Chehab 		mant = (val * 1000 / (1<<exp));
19339a0bf528SMauro Carvalho Chehab 		ix = (u8)((mant-1000)/100); /* index of the LUT */
19349a0bf528SMauro Carvalho Chehab 		val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
19359a0bf528SMauro Carvalho Chehab 		val = (val*256)/1000;
19369a0bf528SMauro Carvalho Chehab 	}
19379a0bf528SMauro Carvalho Chehab 	return val;
19389a0bf528SMauro Carvalho Chehab }
19399a0bf528SMauro Carvalho Chehab 
dib8090p_get_dc_power(struct dvb_frontend * fe,u8 IQ)1940d44913c1SMauro Carvalho Chehab static int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
19419a0bf528SMauro Carvalho Chehab {
19429a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
19439a0bf528SMauro Carvalho Chehab 	int val = 0;
19449a0bf528SMauro Carvalho Chehab 
19459a0bf528SMauro Carvalho Chehab 	switch (IQ) {
19469a0bf528SMauro Carvalho Chehab 	case 1:
19479a0bf528SMauro Carvalho Chehab 			val = dib8000_read_word(state, 403);
19489a0bf528SMauro Carvalho Chehab 			break;
19499a0bf528SMauro Carvalho Chehab 	case 0:
19509a0bf528SMauro Carvalho Chehab 			val = dib8000_read_word(state, 404);
19519a0bf528SMauro Carvalho Chehab 			break;
19529a0bf528SMauro Carvalho Chehab 	}
19539a0bf528SMauro Carvalho Chehab 	if (val  & 0x200)
19549a0bf528SMauro Carvalho Chehab 		val -= 1024;
19559a0bf528SMauro Carvalho Chehab 
19569a0bf528SMauro Carvalho Chehab 	return val;
19579a0bf528SMauro Carvalho Chehab }
19589a0bf528SMauro Carvalho Chehab 
dib8000_update_timf(struct dib8000_state * state)19599a0bf528SMauro Carvalho Chehab static void dib8000_update_timf(struct dib8000_state *state)
19609a0bf528SMauro Carvalho Chehab {
19619a0bf528SMauro Carvalho Chehab 	u32 timf = state->timf = dib8000_read32(state, 435);
19629a0bf528SMauro Carvalho Chehab 
19639a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 29, (u16) (timf >> 16));
19649a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 30, (u16) (timf & 0xffff));
19658af16adfSMauro Carvalho Chehab 	dprintk("Updated timing frequency: %d (default: %d)\n", state->timf, state->timf_default);
19669a0bf528SMauro Carvalho Chehab }
19679a0bf528SMauro Carvalho Chehab 
dib8000_ctrl_timf(struct dvb_frontend * fe,uint8_t op,uint32_t timf)1968d44913c1SMauro Carvalho Chehab static u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
19699a0bf528SMauro Carvalho Chehab {
19709a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
19719a0bf528SMauro Carvalho Chehab 
19729a0bf528SMauro Carvalho Chehab 	switch (op) {
19739a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_SET:
19749a0bf528SMauro Carvalho Chehab 			state->timf = timf;
19759a0bf528SMauro Carvalho Chehab 			break;
19769a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_UPDATE:
19779a0bf528SMauro Carvalho Chehab 			dib8000_update_timf(state);
19789a0bf528SMauro Carvalho Chehab 			break;
19799a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_GET:
19809a0bf528SMauro Carvalho Chehab 			break;
19819a0bf528SMauro Carvalho Chehab 	}
19829a0bf528SMauro Carvalho Chehab 	dib8000_set_bandwidth(state->fe[0], 6000);
19839a0bf528SMauro Carvalho Chehab 
19849a0bf528SMauro Carvalho Chehab 	return state->timf;
19859a0bf528SMauro Carvalho Chehab }
19869a0bf528SMauro Carvalho Chehab 
19879a0bf528SMauro Carvalho Chehab static const u16 adc_target_16dB[11] = {
1988a768f90eSMauro Carvalho Chehab 	7250, 7238, 7264, 7309, 7338, 7382, 7427, 7456, 7500, 7544, 7574
19899a0bf528SMauro Carvalho Chehab };
1990a768f90eSMauro Carvalho Chehab 
19919a0bf528SMauro Carvalho Chehab static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
19929a0bf528SMauro Carvalho Chehab 
dib8000_set_layer(struct dib8000_state * state,u8 layer_index,u16 max_constellation)1993173a64cbSPatrick Boettcher static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
19949a0bf528SMauro Carvalho Chehab {
1995173a64cbSPatrick Boettcher 	u8  cr, constellation, time_intlv;
1996c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
19979a0bf528SMauro Carvalho Chehab 
1998c82056d0SMauro Carvalho Chehab 	switch (c->layer[layer_index].modulation) {
19999a0bf528SMauro Carvalho Chehab 	case DQPSK:
20009a0bf528SMauro Carvalho Chehab 			constellation = 0;
20019a0bf528SMauro Carvalho Chehab 			break;
20029a0bf528SMauro Carvalho Chehab 	case  QPSK:
20039a0bf528SMauro Carvalho Chehab 			constellation = 1;
20049a0bf528SMauro Carvalho Chehab 			break;
20059a0bf528SMauro Carvalho Chehab 	case QAM_16:
20069a0bf528SMauro Carvalho Chehab 			constellation = 2;
20079a0bf528SMauro Carvalho Chehab 			break;
20089a0bf528SMauro Carvalho Chehab 	case QAM_64:
20099a0bf528SMauro Carvalho Chehab 	default:
20109a0bf528SMauro Carvalho Chehab 			constellation = 3;
20119a0bf528SMauro Carvalho Chehab 			break;
20129a0bf528SMauro Carvalho Chehab 	}
20139a0bf528SMauro Carvalho Chehab 
2014c82056d0SMauro Carvalho Chehab 	switch (c->layer[layer_index].fec) {
20159a0bf528SMauro Carvalho Chehab 	case FEC_1_2:
2016173a64cbSPatrick Boettcher 			cr = 1;
20179a0bf528SMauro Carvalho Chehab 			break;
20189a0bf528SMauro Carvalho Chehab 	case FEC_2_3:
2019173a64cbSPatrick Boettcher 			cr = 2;
20209a0bf528SMauro Carvalho Chehab 			break;
20219a0bf528SMauro Carvalho Chehab 	case FEC_3_4:
2022173a64cbSPatrick Boettcher 			cr = 3;
20239a0bf528SMauro Carvalho Chehab 			break;
20249a0bf528SMauro Carvalho Chehab 	case FEC_5_6:
2025173a64cbSPatrick Boettcher 			cr = 5;
20269a0bf528SMauro Carvalho Chehab 			break;
20279a0bf528SMauro Carvalho Chehab 	case FEC_7_8:
20289a0bf528SMauro Carvalho Chehab 	default:
2029173a64cbSPatrick Boettcher 			cr = 7;
20309a0bf528SMauro Carvalho Chehab 			break;
20319a0bf528SMauro Carvalho Chehab 	}
20329a0bf528SMauro Carvalho Chehab 
203334ba2e65SMauro Carvalho Chehab 	time_intlv = fls(c->layer[layer_index].interleaving);
203434ba2e65SMauro Carvalho Chehab 	if (time_intlv > 3 && !(time_intlv == 4 && c->isdbt_sb_mode == 1))
2035173a64cbSPatrick Boettcher 		time_intlv = 0;
2036173a64cbSPatrick Boettcher 
2037c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
2038c82056d0SMauro Carvalho Chehab 	if (c->layer[layer_index].segment_count > 0) {
20399a0bf528SMauro Carvalho Chehab 		switch (max_constellation) {
20409a0bf528SMauro Carvalho Chehab 		case DQPSK:
20419a0bf528SMauro Carvalho Chehab 		case QPSK:
2042c82056d0SMauro Carvalho Chehab 				if (c->layer[layer_index].modulation == QAM_16 || c->layer[layer_index].modulation == QAM_64)
2043c82056d0SMauro Carvalho Chehab 					max_constellation = c->layer[layer_index].modulation;
20449a0bf528SMauro Carvalho Chehab 				break;
20459a0bf528SMauro Carvalho Chehab 		case QAM_16:
2046c82056d0SMauro Carvalho Chehab 				if (c->layer[layer_index].modulation == QAM_64)
2047c82056d0SMauro Carvalho Chehab 					max_constellation = c->layer[layer_index].modulation;
20489a0bf528SMauro Carvalho Chehab 				break;
20499a0bf528SMauro Carvalho Chehab 		}
20509a0bf528SMauro Carvalho Chehab 	}
2051173a64cbSPatrick Boettcher 
2052173a64cbSPatrick Boettcher 	return  max_constellation;
20539a0bf528SMauro Carvalho Chehab }
20549a0bf528SMauro Carvalho Chehab 
2055173a64cbSPatrick 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 */
2056173a64cbSPatrick 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 */
2057173a64cbSPatrick 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 */
dib8000_adp_fine_tune(struct dib8000_state * state,u16 max_constellation)2058173a64cbSPatrick Boettcher static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation)
2059173a64cbSPatrick Boettcher {
2060173a64cbSPatrick Boettcher 	u16 i, ana_gain = 0;
2061173a64cbSPatrick Boettcher 	const u16 *adp;
20629a0bf528SMauro Carvalho Chehab 
2063173a64cbSPatrick Boettcher 	/* channel estimation fine configuration */
2064173a64cbSPatrick Boettcher 	switch (max_constellation) {
2065173a64cbSPatrick Boettcher 	case QAM_64:
2066173a64cbSPatrick Boettcher 			ana_gain = 0x7;
2067173a64cbSPatrick Boettcher 			adp = &adp_Q64[0];
2068173a64cbSPatrick Boettcher 			break;
2069173a64cbSPatrick Boettcher 	case QAM_16:
2070173a64cbSPatrick Boettcher 			ana_gain = 0x7;
2071173a64cbSPatrick Boettcher 			adp = &adp_Q16[0];
2072173a64cbSPatrick Boettcher 			break;
2073173a64cbSPatrick Boettcher 	default:
2074173a64cbSPatrick Boettcher 			ana_gain = 0;
2075173a64cbSPatrick Boettcher 			adp = &adp_Qdefault[0];
2076173a64cbSPatrick Boettcher 			break;
20779a0bf528SMauro Carvalho Chehab 	}
20789a0bf528SMauro Carvalho Chehab 
2079173a64cbSPatrick Boettcher 	for (i = 0; i < 4; i++)
2080173a64cbSPatrick Boettcher 		dib8000_write_word(state, 215 + i, adp[i]);
20819a0bf528SMauro Carvalho Chehab 
2082173a64cbSPatrick Boettcher 	return ana_gain;
2083173a64cbSPatrick Boettcher }
20849a0bf528SMauro Carvalho Chehab 
dib8000_update_ana_gain(struct dib8000_state * state,u16 ana_gain)2085173a64cbSPatrick Boettcher static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain)
2086173a64cbSPatrick Boettcher {
2087173a64cbSPatrick Boettcher 	u16 i;
20889a0bf528SMauro Carvalho Chehab 
2089173a64cbSPatrick Boettcher 	dib8000_write_word(state, 116, ana_gain);
20909a0bf528SMauro Carvalho Chehab 
2091173a64cbSPatrick Boettcher 	/* update ADC target depending on ana_gain */
2092173a64cbSPatrick Boettcher 	if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */
2093173a64cbSPatrick Boettcher 		for (i = 0; i < 10; i++)
2094173a64cbSPatrick Boettcher 			dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
2095173a64cbSPatrick Boettcher 	} else { /* set -22dB ADC target for ana_gain=0 */
2096173a64cbSPatrick Boettcher 		for (i = 0; i < 10; i++)
2097173a64cbSPatrick Boettcher 			dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
2098173a64cbSPatrick Boettcher 	}
2099173a64cbSPatrick Boettcher }
21009a0bf528SMauro Carvalho Chehab 
dib8000_load_ana_fe_coefs(struct dib8000_state * state,const s16 * ana_fe)2101173a64cbSPatrick Boettcher static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
2102173a64cbSPatrick Boettcher {
2103173a64cbSPatrick Boettcher 	u16 mode = 0;
21049a0bf528SMauro Carvalho Chehab 
2105173a64cbSPatrick Boettcher 	if (state->isdbt_cfg_loaded == 0)
2106173a64cbSPatrick Boettcher 		for (mode = 0; mode < 24; mode++)
2107173a64cbSPatrick Boettcher 			dib8000_write_word(state, 117 + mode, ana_fe[mode]);
2108173a64cbSPatrick Boettcher }
21099a0bf528SMauro Carvalho Chehab 
21108db11aebSMauro Carvalho Chehab static const u16 lut_prbs_2k[13] = {
21118db11aebSMauro Carvalho Chehab 	0x423, 0x009, 0x5C7,
21128db11aebSMauro Carvalho Chehab 	0x7A6, 0x3D8, 0x527,
21138db11aebSMauro Carvalho Chehab 	0x7FF, 0x79B, 0x3D6,
21148db11aebSMauro Carvalho Chehab 	0x3A2, 0x53B, 0x2F4,
21158db11aebSMauro Carvalho Chehab 	0x213
2116173a64cbSPatrick Boettcher };
21178db11aebSMauro Carvalho Chehab 
21188db11aebSMauro Carvalho Chehab static const u16 lut_prbs_4k[13] = {
21198db11aebSMauro Carvalho Chehab 	0x208, 0x0C3, 0x7B9,
21208db11aebSMauro Carvalho Chehab 	0x423, 0x5C7, 0x3D8,
21218db11aebSMauro Carvalho Chehab 	0x7FF, 0x3D6, 0x53B,
21228db11aebSMauro Carvalho Chehab 	0x213, 0x029, 0x0D0,
21238db11aebSMauro Carvalho Chehab 	0x48E
2124173a64cbSPatrick Boettcher };
21258db11aebSMauro Carvalho Chehab 
21268db11aebSMauro Carvalho Chehab static const u16 lut_prbs_8k[13] = {
21278db11aebSMauro Carvalho Chehab 	0x740, 0x069, 0x7DD,
21288db11aebSMauro Carvalho Chehab 	0x208, 0x7B9, 0x5C7,
21298db11aebSMauro Carvalho Chehab 	0x7FF, 0x53B, 0x029,
21308db11aebSMauro Carvalho Chehab 	0x48E, 0x4C4, 0x367,
21318db11aebSMauro Carvalho Chehab 	0x684
2132173a64cbSPatrick Boettcher };
2133173a64cbSPatrick Boettcher 
dib8000_get_init_prbs(struct dib8000_state * state,u16 subchannel)2134173a64cbSPatrick Boettcher static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
2135173a64cbSPatrick Boettcher {
2136173a64cbSPatrick Boettcher 	int sub_channel_prbs_group = 0;
21378db11aebSMauro Carvalho Chehab 	int prbs_group;
2138173a64cbSPatrick Boettcher 
21398db11aebSMauro Carvalho Chehab 	sub_channel_prbs_group = subchannel / 3;
21408db11aebSMauro Carvalho Chehab 	if (sub_channel_prbs_group >= ARRAY_SIZE(lut_prbs_2k))
21418db11aebSMauro Carvalho Chehab 		return 0;
2142173a64cbSPatrick Boettcher 
21439a0bf528SMauro Carvalho Chehab 	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
21449a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
21458db11aebSMauro Carvalho Chehab 		prbs_group = lut_prbs_2k[sub_channel_prbs_group];
21468db11aebSMauro Carvalho Chehab 		break;
21479a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
21488db11aebSMauro Carvalho Chehab 		prbs_group =  lut_prbs_4k[sub_channel_prbs_group];
21498db11aebSMauro Carvalho Chehab 		break;
21509a0bf528SMauro Carvalho Chehab 	default:
2151173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
21528db11aebSMauro Carvalho Chehab 		prbs_group = lut_prbs_8k[sub_channel_prbs_group];
21539a0bf528SMauro Carvalho Chehab 	}
21548db11aebSMauro Carvalho Chehab 
21558db11aebSMauro Carvalho Chehab 	dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x\n",
21568db11aebSMauro Carvalho Chehab 		sub_channel_prbs_group, subchannel, prbs_group);
21578db11aebSMauro Carvalho Chehab 
21588db11aebSMauro Carvalho Chehab 	return prbs_group;
21599a0bf528SMauro Carvalho Chehab }
21609a0bf528SMauro Carvalho Chehab 
dib8000_set_13seg_channel(struct dib8000_state * state)2161173a64cbSPatrick Boettcher static void dib8000_set_13seg_channel(struct dib8000_state *state)
2162173a64cbSPatrick Boettcher {
2163173a64cbSPatrick Boettcher 	u16 i;
2164173a64cbSPatrick Boettcher 	u16 coff_pow = 0x2800;
21659a0bf528SMauro Carvalho Chehab 
2166173a64cbSPatrick Boettcher 	state->seg_mask = 0x1fff; /* All 13 segments enabled */
21679a0bf528SMauro Carvalho Chehab 
2168173a64cbSPatrick Boettcher 	/* ---- COFF ---- Carloff, the most robust --- */
2169173a64cbSPatrick Boettcher 	if (state->isdbt_cfg_loaded == 0) {  /* if not Sound Broadcasting mode : put default values for 13 segments */
21709a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 180, (16 << 6) | 9);
21719a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
21729a0bf528SMauro Carvalho Chehab 		coff_pow = 0x2800;
21739a0bf528SMauro Carvalho Chehab 		for (i = 0; i < 6; i++)
21749a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 181+i, coff_pow);
21759a0bf528SMauro Carvalho Chehab 
2176173a64cbSPatrick Boettcher 		/* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */
2177173a64cbSPatrick 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 */
21789a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
21799a0bf528SMauro Carvalho Chehab 
2180173a64cbSPatrick Boettcher 		/* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */
21819a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
2182173a64cbSPatrick Boettcher 		/* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */
21839a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
21849a0bf528SMauro Carvalho Chehab 
2185173a64cbSPatrick Boettcher 		dib8000_write_word(state, 228, 0);  /* default value */
2186173a64cbSPatrick Boettcher 		dib8000_write_word(state, 265, 31); /* default value */
2187173a64cbSPatrick Boettcher 		dib8000_write_word(state, 205, 0x200f); /* init value */
2188173a64cbSPatrick Boettcher 	}
2189173a64cbSPatrick Boettcher 
2190173a64cbSPatrick Boettcher 	/*
2191173a64cbSPatrick Boettcher 	 * make the cpil_coff_lock more robust but slower p_coff_winlen
21929a0bf528SMauro Carvalho Chehab 	 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
21939a0bf528SMauro Carvalho Chehab 	 */
21949a0bf528SMauro Carvalho Chehab 
2195173a64cbSPatrick Boettcher 	if (state->cfg.pll->ifreq == 0)
2196173a64cbSPatrick Boettcher 		dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
21979a0bf528SMauro Carvalho Chehab 
2198173a64cbSPatrick Boettcher 	dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg);
2199173a64cbSPatrick Boettcher }
22009a0bf528SMauro Carvalho Chehab 
dib8000_set_subchannel_prbs(struct dib8000_state * state,u16 init_prbs)2201173a64cbSPatrick Boettcher static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs)
2202173a64cbSPatrick Boettcher {
2203173a64cbSPatrick Boettcher 	u16 reg_1;
22049a0bf528SMauro Carvalho Chehab 
2205173a64cbSPatrick Boettcher 	reg_1 = dib8000_read_word(state, 1);
2206173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */
2207173a64cbSPatrick Boettcher }
22089a0bf528SMauro Carvalho Chehab 
dib8000_small_fine_tune(struct dib8000_state * state)2209173a64cbSPatrick Boettcher static void dib8000_small_fine_tune(struct dib8000_state *state)
2210173a64cbSPatrick Boettcher {
2211173a64cbSPatrick Boettcher 	u16 i;
2212173a64cbSPatrick Boettcher 	const s16 *ncoeff;
2213c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
22149a0bf528SMauro Carvalho Chehab 
2215173a64cbSPatrick Boettcher 	dib8000_write_word(state, 352, state->seg_diff_mask);
2216173a64cbSPatrick Boettcher 	dib8000_write_word(state, 353, state->seg_mask);
22179a0bf528SMauro Carvalho Chehab 
2218173a64cbSPatrick 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 */
2219c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 351, (c->isdbt_sb_mode << 9) | (c->isdbt_sb_mode << 8) | (13 << 4) | 5);
2220173a64cbSPatrick Boettcher 
2221c82056d0SMauro Carvalho Chehab 	if (c->isdbt_sb_mode) {
2222173a64cbSPatrick Boettcher 		/* ---- SMALL ---- */
2223c82056d0SMauro Carvalho Chehab 		switch (c->transmission_mode) {
2224173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_2K:
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_2k_sb_1seg_dqpsk;
2228173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2229173a64cbSPatrick Boettcher 						ncoeff = coeff_2k_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_2k_sb_3seg_0dqpsk_1dqpsk;
2234173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2235173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_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_2k_sb_3seg_1dqpsk;
2239173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2240173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg;
2241173a64cbSPatrick Boettcher 					}
2242173a64cbSPatrick Boettcher 				}
22439a0bf528SMauro Carvalho Chehab 				break;
22449a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_4K:
2245c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2246c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2247173a64cbSPatrick Boettcher 						ncoeff = coeff_4k_sb_1seg_dqpsk;
2248173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2249173a64cbSPatrick Boettcher 						ncoeff = coeff_4k_sb_1seg;
2250173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2251c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2252c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2253173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
2254173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2255173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_0dqpsk;
2256173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2257c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2258173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_1dqpsk;
2259173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2260173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg;
2261173a64cbSPatrick Boettcher 					}
2262173a64cbSPatrick Boettcher 				}
22639a0bf528SMauro Carvalho Chehab 				break;
2264173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_AUTO:
2265173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_8K:
22669a0bf528SMauro Carvalho Chehab 		default:
2267c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) { /* 1-seg */
2268c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) /* DQPSK */
2269173a64cbSPatrick Boettcher 						ncoeff = coeff_8k_sb_1seg_dqpsk;
2270173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2271173a64cbSPatrick Boettcher 						ncoeff = coeff_8k_sb_1seg;
2272173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2273c82056d0SMauro Carvalho Chehab 					if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2274c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2275173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
2276173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2277173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_0dqpsk;
2278173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2279c82056d0SMauro Carvalho Chehab 						if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
2280173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_1dqpsk;
2281173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2282173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg;
2283173a64cbSPatrick Boettcher 					}
2284173a64cbSPatrick Boettcher 				}
22859a0bf528SMauro Carvalho Chehab 				break;
22869a0bf528SMauro Carvalho Chehab 		}
2287173a64cbSPatrick Boettcher 
2288173a64cbSPatrick Boettcher 		for (i = 0; i < 8; i++)
2289173a64cbSPatrick Boettcher 			dib8000_write_word(state, 343 + i, ncoeff[i]);
2290173a64cbSPatrick Boettcher 	}
2291173a64cbSPatrick Boettcher }
2292173a64cbSPatrick Boettcher 
2293173a64cbSPatrick Boettcher static const u16 coff_thres_1seg[3] = {300, 150, 80};
2294173a64cbSPatrick Boettcher static const u16 coff_thres_3seg[3] = {350, 300, 250};
dib8000_set_sb_channel(struct dib8000_state * state)2295173a64cbSPatrick Boettcher static void dib8000_set_sb_channel(struct dib8000_state *state)
2296173a64cbSPatrick Boettcher {
2297c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2298173a64cbSPatrick Boettcher 	const u16 *coff;
2299173a64cbSPatrick Boettcher 	u16 i;
2300173a64cbSPatrick Boettcher 
2301c82056d0SMauro Carvalho Chehab 	if (c->transmission_mode == TRANSMISSION_MODE_2K || c->transmission_mode == TRANSMISSION_MODE_4K) {
2302173a64cbSPatrick Boettcher 		dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */
2303173a64cbSPatrick Boettcher 		dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */
2304173a64cbSPatrick Boettcher 	} else {
2305173a64cbSPatrick Boettcher 		dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */
2306173a64cbSPatrick Boettcher 		dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */
2307173a64cbSPatrick Boettcher 	}
2308173a64cbSPatrick Boettcher 
2309c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 1) /* 3-segments */
2310173a64cbSPatrick Boettcher 		state->seg_mask = 0x00E0;
2311173a64cbSPatrick Boettcher 	else /* 1-segment */
2312173a64cbSPatrick Boettcher 		state->seg_mask = 0x0040;
2313173a64cbSPatrick Boettcher 
2314173a64cbSPatrick Boettcher 	dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2315173a64cbSPatrick Boettcher 
2316173a64cbSPatrick Boettcher 	/* ---- COFF ---- Carloff, the most robust --- */
2317173a64cbSPatrick 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 */
2318c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 187, (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~c->isdbt_partial_reception & 1) << 2) | 0x3);
2319173a64cbSPatrick Boettcher 
2320173a64cbSPatrick Boettcher 	dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */
2321173a64cbSPatrick 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 */
2322173a64cbSPatrick Boettcher 
2323173a64cbSPatrick Boettcher 	/* Sound Broadcasting mode 1 seg */
2324c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 0) {
2325173a64cbSPatrick 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) */
2326173a64cbSPatrick Boettcher 		if (state->mode == 3)
2327173a64cbSPatrick Boettcher 			dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14));
23289a0bf528SMauro Carvalho Chehab 		else
2329173a64cbSPatrick Boettcher 			dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14));
2330173a64cbSPatrick Boettcher 
2331173a64cbSPatrick 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 */
2332173a64cbSPatrick Boettcher 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
2333173a64cbSPatrick Boettcher 		coff = &coff_thres_1seg[0];
2334173a64cbSPatrick Boettcher 	} else {   /* Sound Broadcasting mode 3 seg */
2335173a64cbSPatrick Boettcher 		dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
2336173a64cbSPatrick 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 */
2337173a64cbSPatrick Boettcher 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
2338173a64cbSPatrick Boettcher 		coff = &coff_thres_3seg[0];
2339173a64cbSPatrick Boettcher 	}
2340173a64cbSPatrick Boettcher 
2341173a64cbSPatrick Boettcher 	dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */
2342173a64cbSPatrick Boettcher 	dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */
2343173a64cbSPatrick Boettcher 
2344c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 0 && c->transmission_mode == TRANSMISSION_MODE_2K)
2345173a64cbSPatrick Boettcher 		dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */
2346173a64cbSPatrick Boettcher 
2347173a64cbSPatrick Boettcher 	/* Write COFF thres */
2348173a64cbSPatrick Boettcher 	for (i = 0 ; i < 3; i++) {
2349173a64cbSPatrick Boettcher 		dib8000_write_word(state, 181+i, coff[i]);
2350173a64cbSPatrick Boettcher 		dib8000_write_word(state, 184+i, coff[i]);
2351173a64cbSPatrick Boettcher 	}
2352173a64cbSPatrick Boettcher 
2353173a64cbSPatrick Boettcher 	/*
2354173a64cbSPatrick Boettcher 	 * make the cpil_coff_lock more robust but slower p_coff_winlen
2355173a64cbSPatrick Boettcher 	 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2356173a64cbSPatrick Boettcher 	 */
2357173a64cbSPatrick Boettcher 
2358173a64cbSPatrick Boettcher 	dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */
2359173a64cbSPatrick Boettcher 
2360c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception == 0)
2361173a64cbSPatrick Boettcher 		dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */
2362173a64cbSPatrick Boettcher 	else
2363173a64cbSPatrick Boettcher 		dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2364173a64cbSPatrick Boettcher }
2365173a64cbSPatrick Boettcher 
dib8000_set_isdbt_common_channel(struct dib8000_state * state,u8 seq,u8 autosearching)2366173a64cbSPatrick Boettcher static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
2367173a64cbSPatrick Boettcher {
2368173a64cbSPatrick Boettcher 	u16 p_cfr_left_edge  = 0, p_cfr_right_edge = 0;
2369173a64cbSPatrick Boettcher 	u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ;
2370173a64cbSPatrick Boettcher 	u16 max_constellation = DQPSK;
2371173a64cbSPatrick Boettcher 	int init_prbs;
2372c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2373173a64cbSPatrick Boettcher 
2374dde8e115SMauro Carvalho Chehab 	if (autosearching)
2375dde8e115SMauro Carvalho Chehab 		c->isdbt_partial_reception = 1;
2376dde8e115SMauro Carvalho Chehab 
2377173a64cbSPatrick Boettcher 	/* P_mode */
2378173a64cbSPatrick Boettcher 	dib8000_write_word(state, 10, (seq << 4));
2379173a64cbSPatrick Boettcher 
2380173a64cbSPatrick Boettcher 	/* init mode */
2381173a64cbSPatrick Boettcher 	state->mode = fft_to_mode(state);
2382173a64cbSPatrick Boettcher 
2383173a64cbSPatrick Boettcher 	/* set guard */
2384173a64cbSPatrick Boettcher 	tmp = dib8000_read_word(state, 1);
2385c82056d0SMauro Carvalho Chehab 	dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3));
2386173a64cbSPatrick Boettcher 
2387c82056d0SMauro 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));
2388173a64cbSPatrick Boettcher 
2389173a64cbSPatrick Boettcher 	/* signal optimization parameter */
2390c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception) {
2391c82056d0SMauro Carvalho Chehab 		state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0];
2392173a64cbSPatrick Boettcher 		for (i = 1; i < 3; i++)
2393c82056d0SMauro Carvalho Chehab 			nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
2394173a64cbSPatrick Boettcher 		for (i = 0; i < nbseg_diff; i++)
2395173a64cbSPatrick Boettcher 			state->seg_diff_mask |= 1 << permu_seg[i+1];
2396173a64cbSPatrick Boettcher 	} else {
2397173a64cbSPatrick Boettcher 		for (i = 0; i < 3; i++)
2398c82056d0SMauro Carvalho Chehab 			nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
2399173a64cbSPatrick Boettcher 		for (i = 0; i < nbseg_diff; i++)
2400173a64cbSPatrick Boettcher 			state->seg_diff_mask |= 1 << permu_seg[i];
2401173a64cbSPatrick Boettcher 	}
2402173a64cbSPatrick Boettcher 
2403173a64cbSPatrick Boettcher 	if (state->seg_diff_mask)
2404173a64cbSPatrick Boettcher 		dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2405173a64cbSPatrick Boettcher 	else
2406173a64cbSPatrick Boettcher 		dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */
2407173a64cbSPatrick Boettcher 
2408173a64cbSPatrick Boettcher 	for (i = 0; i < 3; i++)
2409173a64cbSPatrick Boettcher 		max_constellation = dib8000_set_layer(state, i, max_constellation);
2410173a64cbSPatrick Boettcher 	if (autosearching == 0) {
2411c82056d0SMauro Carvalho Chehab 		state->layer_b_nb_seg = c->layer[1].segment_count;
2412c82056d0SMauro Carvalho Chehab 		state->layer_c_nb_seg = c->layer[2].segment_count;
2413173a64cbSPatrick Boettcher 	}
2414173a64cbSPatrick Boettcher 
2415173a64cbSPatrick Boettcher 	/* WRITE: Mode & Diff mask */
2416173a64cbSPatrick Boettcher 	dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask);
2417173a64cbSPatrick Boettcher 
2418173a64cbSPatrick Boettcher 	state->differential_constellation = (state->seg_diff_mask != 0);
24199a0bf528SMauro Carvalho Chehab 
24209a0bf528SMauro Carvalho Chehab 	/* channel estimation fine configuration */
2421173a64cbSPatrick Boettcher 	ana_gain = dib8000_adp_fine_tune(state, max_constellation);
24229a0bf528SMauro Carvalho Chehab 
2423173a64cbSPatrick Boettcher 	/* update ana_gain depending on max constellation */
2424173a64cbSPatrick Boettcher 	dib8000_update_ana_gain(state, ana_gain);
24259a0bf528SMauro Carvalho Chehab 
2426173a64cbSPatrick Boettcher 	/* ---- ANA_FE ---- */
2427c82056d0SMauro Carvalho Chehab 	if (c->isdbt_partial_reception) /* 3-segments */
2428173a64cbSPatrick Boettcher 		dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg);
2429173a64cbSPatrick Boettcher 	else
2430173a64cbSPatrick Boettcher 		dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */
2431173a64cbSPatrick Boettcher 
2432173a64cbSPatrick Boettcher 	/* TSB or ISDBT ? apply it now */
2433c82056d0SMauro Carvalho Chehab 	if (c->isdbt_sb_mode) {
2434173a64cbSPatrick Boettcher 		dib8000_set_sb_channel(state);
24358db11aebSMauro Carvalho Chehab 		init_prbs = dib8000_get_init_prbs(state,
24368db11aebSMauro Carvalho Chehab 						  c->isdbt_sb_subchannel);
2437173a64cbSPatrick Boettcher 	} else {
2438173a64cbSPatrick Boettcher 		dib8000_set_13seg_channel(state);
2439173a64cbSPatrick Boettcher 		init_prbs = 0xfff;
2440173a64cbSPatrick Boettcher 	}
24419a0bf528SMauro Carvalho Chehab 
2442173a64cbSPatrick Boettcher 	/* SMALL */
2443173a64cbSPatrick Boettcher 	dib8000_small_fine_tune(state);
24449a0bf528SMauro Carvalho Chehab 
2445173a64cbSPatrick Boettcher 	dib8000_set_subchannel_prbs(state, init_prbs);
2446173a64cbSPatrick Boettcher 
2447173a64cbSPatrick Boettcher 	/* ---- CHAN_BLK ---- */
24489a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 13; i++) {
2449173a64cbSPatrick Boettcher 		if ((((~state->seg_diff_mask) >> i) & 1) == 1) {
2450173a64cbSPatrick Boettcher 			p_cfr_left_edge  += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0));
2451173a64cbSPatrick Boettcher 			p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0));
24529a0bf528SMauro Carvalho Chehab 		}
24539a0bf528SMauro Carvalho Chehab 	}
2454173a64cbSPatrick Boettcher 	dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */
2455173a64cbSPatrick Boettcher 	dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */
2456173a64cbSPatrick Boettcher 	/* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */
24579a0bf528SMauro Carvalho Chehab 
2458173a64cbSPatrick Boettcher 	dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */
2459173a64cbSPatrick Boettcher 	dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */
2460173a64cbSPatrick Boettcher 	dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */
2461173a64cbSPatrick Boettcher 
2462173a64cbSPatrick Boettcher 	if (!autosearching)
2463173a64cbSPatrick Boettcher 		dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
2464173a64cbSPatrick Boettcher 	else
2465173a64cbSPatrick Boettcher 		dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */
2466173a64cbSPatrick Boettcher 
2467173a64cbSPatrick Boettcher 	dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */
2468173a64cbSPatrick Boettcher 	dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */
2469173a64cbSPatrick Boettcher 
2470173a64cbSPatrick Boettcher 	dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2471173a64cbSPatrick Boettcher 
2472173a64cbSPatrick Boettcher 	/* ---- TMCC ---- */
24739a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 3; i++)
2474c82056d0SMauro Carvalho Chehab 		tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ;
2475173a64cbSPatrick Boettcher 
2476173a64cbSPatrick Boettcher 	/* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */
2477173a64cbSPatrick Boettcher 	/* Threshold is set at 1/4 of max power. */
24789a0bf528SMauro Carvalho Chehab 	tmcc_pow *= (1 << (9-2));
2479173a64cbSPatrick Boettcher 	dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */
2480173a64cbSPatrick Boettcher 	dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */
2481173a64cbSPatrick Boettcher 	dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */
2482173a64cbSPatrick Boettcher 	/*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */
24839a0bf528SMauro Carvalho Chehab 
2484173a64cbSPatrick Boettcher 	/* ---- PHA3 ---- */
24859a0bf528SMauro Carvalho Chehab 	if (state->isdbt_cfg_loaded == 0)
24869a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */
24879a0bf528SMauro Carvalho Chehab 
24889a0bf528SMauro Carvalho Chehab 	state->isdbt_cfg_loaded = 0;
2489173a64cbSPatrick Boettcher }
24909a0bf528SMauro Carvalho Chehab 
dib8000_wait_lock(struct dib8000_state * state,u32 internal,u32 wait0_ms,u32 wait1_ms,u32 wait2_ms)24916f7ee06fSMauro Carvalho Chehab static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal,
24926f7ee06fSMauro Carvalho Chehab 			     u32 wait0_ms, u32 wait1_ms, u32 wait2_ms)
2493173a64cbSPatrick Boettcher {
249413122f98SMauro Carvalho Chehab 	u32 value = 0;	/* P_search_end0 wait time */
2495173a64cbSPatrick Boettcher 	u16 reg = 11;	/* P_search_end0 start addr */
2496173a64cbSPatrick Boettcher 
2497173a64cbSPatrick Boettcher 	for (reg = 11; reg < 16; reg += 2) {
2498173a64cbSPatrick Boettcher 		if (reg == 11) {
2499173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
250013122f98SMauro Carvalho Chehab 				value = internal * wait1_ms;
2501173a64cbSPatrick Boettcher 			else
250213122f98SMauro Carvalho Chehab 				value = internal * wait0_ms;
2503173a64cbSPatrick Boettcher 		} else if (reg == 13)
250413122f98SMauro Carvalho Chehab 			value = internal * wait1_ms;
2505173a64cbSPatrick Boettcher 		else if (reg == 15)
250613122f98SMauro Carvalho Chehab 			value = internal * wait2_ms;
2507173a64cbSPatrick Boettcher 		dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff));
2508173a64cbSPatrick Boettcher 		dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff));
2509173a64cbSPatrick Boettcher 	}
2510173a64cbSPatrick Boettcher 	return value;
25119a0bf528SMauro Carvalho Chehab }
25129a0bf528SMauro Carvalho Chehab 
dib8000_autosearch_start(struct dvb_frontend * fe)25139a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_start(struct dvb_frontend *fe)
25149a0bf528SMauro Carvalho Chehab {
25159a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
2516c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2517173a64cbSPatrick Boettcher 	u8 slist = 0;
2518173a64cbSPatrick Boettcher 	u32 value, internal = state->cfg.pll->internal;
25199a0bf528SMauro Carvalho Chehab 
2520173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
2521173a64cbSPatrick Boettcher 		internal = dib8000_read32(state, 23) / 1000;
25229a0bf528SMauro Carvalho Chehab 
2523d67350f8SOlivier Grenie 	if ((state->revision >= 0x8002) &&
2524d67350f8SOlivier Grenie 	    (state->autosearch_state == AS_SEARCHING_FFT)) {
2525173a64cbSPatrick Boettcher 		dib8000_write_word(state,  37, 0x0065); /* P_ctrl_pha_off_max default values */
2526173a64cbSPatrick Boettcher 		dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
2527173a64cbSPatrick Boettcher 
2528173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */
2529173a64cbSPatrick Boettcher 		dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */
2530173a64cbSPatrick Boettcher 		dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */
2531173a64cbSPatrick Boettcher 		dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */
2532173a64cbSPatrick Boettcher 		dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */
2533173a64cbSPatrick Boettcher 		dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */
2534173a64cbSPatrick Boettcher 
2535173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2536173a64cbSPatrick Boettcher 			value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2537173a64cbSPatrick Boettcher 		else
2538173a64cbSPatrick Boettcher 			value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2539173a64cbSPatrick Boettcher 
2540173a64cbSPatrick Boettcher 		dib8000_write_word(state, 17, 0);
2541173a64cbSPatrick Boettcher 		dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */
2542173a64cbSPatrick Boettcher 		dib8000_write_word(state, 19, 0);
2543173a64cbSPatrick Boettcher 		dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */
2544173a64cbSPatrick Boettcher 		dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */
2545173a64cbSPatrick Boettcher 		dib8000_write_word(state, 22, value & 0xffff);
2546173a64cbSPatrick Boettcher 
2547173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2548173a64cbSPatrick Boettcher 			dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */
2549173a64cbSPatrick Boettcher 		else
2550173a64cbSPatrick Boettcher 			dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */
2551173a64cbSPatrick Boettcher 		dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */
2552173a64cbSPatrick Boettcher 
2553173a64cbSPatrick Boettcher 		/* P_search_param_select = (1 | 1<<4 | 1 << 8) */
2554173a64cbSPatrick Boettcher 		dib8000_write_word(state, 356, 0);
2555173a64cbSPatrick Boettcher 		dib8000_write_word(state, 357, 0x111);
2556173a64cbSPatrick Boettcher 
2557173a64cbSPatrick Boettcher 		dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
2558173a64cbSPatrick Boettcher 		dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
2559173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */
2560d67350f8SOlivier Grenie 	} else if ((state->revision >= 0x8002) &&
2561d67350f8SOlivier Grenie 		   (state->autosearch_state == AS_SEARCHING_GUARD)) {
2562c82056d0SMauro Carvalho Chehab 		c->transmission_mode = TRANSMISSION_MODE_8K;
2563c82056d0SMauro Carvalho Chehab 		c->guard_interval = GUARD_INTERVAL_1_8;
2564c82056d0SMauro Carvalho Chehab 		c->inversion = 0;
2565c82056d0SMauro Carvalho Chehab 		c->layer[0].modulation = QAM_64;
2566c82056d0SMauro Carvalho Chehab 		c->layer[0].fec = FEC_2_3;
2567c82056d0SMauro Carvalho Chehab 		c->layer[0].interleaving = 0;
2568c82056d0SMauro Carvalho Chehab 		c->layer[0].segment_count = 13;
25699a0bf528SMauro Carvalho Chehab 
2570173a64cbSPatrick Boettcher 		slist = 16;
2571c82056d0SMauro Carvalho Chehab 		c->transmission_mode = state->found_nfft;
2572173a64cbSPatrick Boettcher 
2573173a64cbSPatrick Boettcher 		dib8000_set_isdbt_common_channel(state, slist, 1);
2574173a64cbSPatrick Boettcher 
2575173a64cbSPatrick Boettcher 		/* set lock_mask values */
2576173a64cbSPatrick Boettcher 		dib8000_write_word(state, 6, 0x4);
2577173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2578173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */
2579173a64cbSPatrick Boettcher 		else
2580173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, 0x8);
2581173a64cbSPatrick Boettcher 		dib8000_write_word(state, 8, 0x1000);
2582173a64cbSPatrick Boettcher 
2583173a64cbSPatrick Boettcher 		/* set lock_mask wait time values */
2584173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2585173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2586173a64cbSPatrick Boettcher 		else
2587173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2588173a64cbSPatrick Boettcher 
2589173a64cbSPatrick Boettcher 		dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */
2590173a64cbSPatrick Boettcher 
2591173a64cbSPatrick Boettcher 		/* P_search_param_select = 0xf; look for the 4 different guard intervals */
2592173a64cbSPatrick Boettcher 		dib8000_write_word(state, 356, 0);
2593173a64cbSPatrick Boettcher 		dib8000_write_word(state, 357, 0xf);
2594173a64cbSPatrick Boettcher 
2595173a64cbSPatrick Boettcher 		value = dib8000_read_word(state, 0);
2596173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2597173a64cbSPatrick Boettcher 		dib8000_read_word(state, 1284);  /* reset the INT. n_irq_pending */
2598173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (u16)value);
2599173a64cbSPatrick Boettcher 	} else {
2600c82056d0SMauro Carvalho Chehab 		c->inversion = 0;
2601c82056d0SMauro Carvalho Chehab 		c->layer[0].modulation = QAM_64;
2602c82056d0SMauro Carvalho Chehab 		c->layer[0].fec = FEC_2_3;
2603c82056d0SMauro Carvalho Chehab 		c->layer[0].interleaving = 0;
2604c82056d0SMauro Carvalho Chehab 		c->layer[0].segment_count = 13;
2605c82056d0SMauro Carvalho Chehab 		if (!c->isdbt_sb_mode)
2606c82056d0SMauro Carvalho Chehab 			c->layer[0].segment_count = 13;
2607173a64cbSPatrick Boettcher 
2608173a64cbSPatrick Boettcher 		/* choose the right list, in sb, always do everything */
2609c82056d0SMauro Carvalho Chehab 		if (c->isdbt_sb_mode) {
26109a0bf528SMauro Carvalho Chehab 			slist = 7;
26119a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
26129a0bf528SMauro Carvalho Chehab 		} else {
2613c82056d0SMauro Carvalho Chehab 			if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2614c82056d0SMauro Carvalho Chehab 				if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2615c82056d0SMauro Carvalho Chehab 					c->transmission_mode = TRANSMISSION_MODE_8K;
2616c82056d0SMauro Carvalho Chehab 					c->guard_interval = GUARD_INTERVAL_1_8;
26179a0bf528SMauro Carvalho Chehab 					slist = 7;
2618173a64cbSPatrick Boettcher 					dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));  /* P_mode = 1 to have autosearch start ok with mode2 */
2619173a64cbSPatrick Boettcher 				} else {
2620c82056d0SMauro Carvalho Chehab 					c->guard_interval = GUARD_INTERVAL_1_8;
26219a0bf528SMauro Carvalho Chehab 					slist = 3;
2622173a64cbSPatrick Boettcher 				}
26239a0bf528SMauro Carvalho Chehab 			} else {
2624c82056d0SMauro Carvalho Chehab 				if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2625c82056d0SMauro Carvalho Chehab 					c->transmission_mode = TRANSMISSION_MODE_8K;
26269a0bf528SMauro Carvalho Chehab 					slist = 2;
2627173a64cbSPatrick Boettcher 					dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));  /* P_mode = 1 */
26289a0bf528SMauro Carvalho Chehab 				} else
26299a0bf528SMauro Carvalho Chehab 					slist = 0;
26309a0bf528SMauro Carvalho Chehab 			}
2631173a64cbSPatrick Boettcher 		}
26328af16adfSMauro Carvalho Chehab 		dprintk("Using list for autosearch : %d\n", slist);
26339a0bf528SMauro Carvalho Chehab 
2634173a64cbSPatrick Boettcher 		dib8000_set_isdbt_common_channel(state, slist, 1);
26359a0bf528SMauro Carvalho Chehab 
2636173a64cbSPatrick Boettcher 		/* set lock_mask values */
26379a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 6, 0x4);
2638173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2639173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10));
2640173a64cbSPatrick Boettcher 		else
26419a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 7, 0x8);
26429a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 8, 0x1000);
26439a0bf528SMauro Carvalho Chehab 
2644173a64cbSPatrick Boettcher 		/* set lock_mask wait time values */
2645173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2646173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2647173a64cbSPatrick Boettcher 		else
2648173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
26499a0bf528SMauro Carvalho Chehab 
26509a0bf528SMauro Carvalho Chehab 		value = dib8000_read_word(state, 0);
26519a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2652173a64cbSPatrick Boettcher 		dib8000_read_word(state, 1284);  /* reset the INT. n_irq_pending */
26539a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 0, (u16)value);
26549a0bf528SMauro Carvalho Chehab 	}
26559a0bf528SMauro Carvalho Chehab 	return 0;
26569a0bf528SMauro Carvalho Chehab }
26579a0bf528SMauro Carvalho Chehab 
dib8000_autosearch_irq(struct dvb_frontend * fe)26589a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_irq(struct dvb_frontend *fe)
26599a0bf528SMauro Carvalho Chehab {
26609a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
26619a0bf528SMauro Carvalho Chehab 	u16 irq_pending = dib8000_read_word(state, 1284);
26629a0bf528SMauro Carvalho Chehab 
2663d67350f8SOlivier Grenie 	if ((state->revision >= 0x8002) &&
2664d67350f8SOlivier Grenie 	    (state->autosearch_state == AS_SEARCHING_FFT)) {
2665173a64cbSPatrick Boettcher 		if (irq_pending & 0x1) {
26668af16adfSMauro Carvalho Chehab 			dprintk("dib8000_autosearch_irq: max correlation result available\n");
2667173a64cbSPatrick Boettcher 			return 3;
2668173a64cbSPatrick Boettcher 		}
2669173a64cbSPatrick Boettcher 	} else {
2670173a64cbSPatrick Boettcher 		if (irq_pending & 0x1) {	/* failed */
26718af16adfSMauro Carvalho Chehab 			dprintk("dib8000_autosearch_irq failed\n");
26729a0bf528SMauro Carvalho Chehab 			return 1;
26739a0bf528SMauro Carvalho Chehab 		}
26749a0bf528SMauro Carvalho Chehab 
2675173a64cbSPatrick Boettcher 		if (irq_pending & 0x2) {	/* succeeded */
26768af16adfSMauro Carvalho Chehab 			dprintk("dib8000_autosearch_irq succeeded\n");
26779a0bf528SMauro Carvalho Chehab 			return 2;
26789a0bf528SMauro Carvalho Chehab 		}
2679173a64cbSPatrick Boettcher 	}
26809a0bf528SMauro Carvalho Chehab 
26819a0bf528SMauro Carvalho Chehab 	return 0;		// still pending
26829a0bf528SMauro Carvalho Chehab }
26839a0bf528SMauro Carvalho Chehab 
dib8000_viterbi_state(struct dib8000_state * state,u8 onoff)2684173a64cbSPatrick Boettcher static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
2685173a64cbSPatrick Boettcher {
2686173a64cbSPatrick Boettcher 	u16 tmp;
2687173a64cbSPatrick Boettcher 
2688173a64cbSPatrick Boettcher 	tmp = dib8000_read_word(state, 771);
2689173a64cbSPatrick Boettcher 	if (onoff) /* start P_restart_chd : channel_decoder */
2690173a64cbSPatrick Boettcher 		dib8000_write_word(state, 771, tmp & 0xfffd);
2691173a64cbSPatrick Boettcher 	else /* stop P_restart_chd : channel_decoder */
2692173a64cbSPatrick Boettcher 		dib8000_write_word(state, 771, tmp | (1<<1));
2693173a64cbSPatrick Boettcher }
2694173a64cbSPatrick Boettcher 
dib8000_set_dds(struct dib8000_state * state,s32 offset_khz)2695173a64cbSPatrick Boettcher static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
2696173a64cbSPatrick Boettcher {
2697173a64cbSPatrick Boettcher 	s16 unit_khz_dds_val;
26987aa92c42SDan Gopstein 	u32 abs_offset_khz = abs(offset_khz);
2699173a64cbSPatrick Boettcher 	u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
2700173a64cbSPatrick Boettcher 	u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
2701173a64cbSPatrick Boettcher 	u8 ratio;
2702173a64cbSPatrick Boettcher 
2703173a64cbSPatrick Boettcher 	if (state->revision == 0x8090) {
2704173a64cbSPatrick Boettcher 		ratio = 4;
2705173a64cbSPatrick Boettcher 		unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000);
2706173a64cbSPatrick Boettcher 		if (offset_khz < 0)
2707173a64cbSPatrick Boettcher 			dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
2708173a64cbSPatrick Boettcher 		else
2709173a64cbSPatrick Boettcher 			dds = (abs_offset_khz * unit_khz_dds_val);
2710173a64cbSPatrick Boettcher 
2711173a64cbSPatrick Boettcher 		if (invert)
2712173a64cbSPatrick Boettcher 			dds = (1<<26) - dds;
2713173a64cbSPatrick Boettcher 	} else {
2714173a64cbSPatrick Boettcher 		ratio = 2;
2715173a64cbSPatrick Boettcher 		unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
2716173a64cbSPatrick Boettcher 
2717173a64cbSPatrick Boettcher 		if (offset_khz < 0)
2718173a64cbSPatrick Boettcher 			unit_khz_dds_val *= -1;
2719173a64cbSPatrick Boettcher 
2720173a64cbSPatrick Boettcher 		/* IF tuner */
2721173a64cbSPatrick Boettcher 		if (invert)
2722173a64cbSPatrick Boettcher 			dds -= abs_offset_khz * unit_khz_dds_val;
2723173a64cbSPatrick Boettcher 		else
2724173a64cbSPatrick Boettcher 			dds += abs_offset_khz * unit_khz_dds_val;
2725173a64cbSPatrick Boettcher 	}
2726173a64cbSPatrick Boettcher 
27278af16adfSMauro Carvalho Chehab 	dprintk("setting a DDS frequency offset of %c%dkHz\n", invert ? '-' : ' ', dds / unit_khz_dds_val);
2728173a64cbSPatrick Boettcher 
2729173a64cbSPatrick Boettcher 	if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) {
2730173a64cbSPatrick Boettcher 		/* Max dds offset is the half of the demod freq */
2731173a64cbSPatrick Boettcher 		dib8000_write_word(state, 26, invert);
2732173a64cbSPatrick Boettcher 		dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff);
2733173a64cbSPatrick Boettcher 		dib8000_write_word(state, 28, (u16)(dds & 0xffff));
2734173a64cbSPatrick Boettcher 	}
2735173a64cbSPatrick Boettcher }
2736173a64cbSPatrick Boettcher 
dib8000_set_frequency_offset(struct dib8000_state * state)2737173a64cbSPatrick Boettcher static void dib8000_set_frequency_offset(struct dib8000_state *state)
2738173a64cbSPatrick Boettcher {
2739c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2740173a64cbSPatrick Boettcher 	int i;
2741173a64cbSPatrick Boettcher 	u32 current_rf;
2742173a64cbSPatrick Boettcher 	int total_dds_offset_khz;
2743173a64cbSPatrick Boettcher 
2744173a64cbSPatrick Boettcher 	if (state->fe[0]->ops.tuner_ops.get_frequency)
2745173a64cbSPatrick Boettcher 		state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], &current_rf);
2746173a64cbSPatrick Boettcher 	else
2747c82056d0SMauro Carvalho Chehab 		current_rf = c->frequency;
2748173a64cbSPatrick Boettcher 	current_rf /= 1000;
2749c82056d0SMauro Carvalho Chehab 	total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000;
2750173a64cbSPatrick Boettcher 
2751c82056d0SMauro Carvalho Chehab 	if (c->isdbt_sb_mode) {
2752c82056d0SMauro Carvalho Chehab 		state->subchannel = c->isdbt_sb_subchannel;
2753173a64cbSPatrick Boettcher 
2754173a64cbSPatrick Boettcher 		i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */
2755c82056d0SMauro Carvalho Chehab 		dib8000_write_word(state, 26, c->inversion ^ i);
2756173a64cbSPatrick Boettcher 
2757173a64cbSPatrick Boettcher 		if (state->cfg.pll->ifreq == 0) { /* low if tuner */
2758c82056d0SMauro Carvalho Chehab 			if ((c->inversion ^ i) == 0)
2759173a64cbSPatrick Boettcher 				dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
2760173a64cbSPatrick Boettcher 		} else {
2761c82056d0SMauro Carvalho Chehab 			if ((c->inversion ^ i) == 0)
2762173a64cbSPatrick Boettcher 				total_dds_offset_khz *= -1;
2763173a64cbSPatrick Boettcher 		}
2764173a64cbSPatrick Boettcher 	}
2765173a64cbSPatrick Boettcher 
27668af16adfSMauro 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);
2767173a64cbSPatrick Boettcher 
2768173a64cbSPatrick Boettcher 	/* apply dds offset now */
2769173a64cbSPatrick Boettcher 	dib8000_set_dds(state, total_dds_offset_khz);
2770173a64cbSPatrick Boettcher }
2771173a64cbSPatrick Boettcher 
2772173a64cbSPatrick Boettcher static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 };
27736f7ee06fSMauro Carvalho Chehab 
dib8000_get_symbol_duration(struct dib8000_state * state)27746f7ee06fSMauro Carvalho Chehab static u32 dib8000_get_symbol_duration(struct dib8000_state *state)
2775173a64cbSPatrick Boettcher {
2776c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2777173a64cbSPatrick Boettcher 	u16 i;
2778173a64cbSPatrick Boettcher 
2779c82056d0SMauro Carvalho Chehab 	switch (c->transmission_mode) {
2780173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_2K:
2781173a64cbSPatrick Boettcher 			i = 0;
2782173a64cbSPatrick Boettcher 			break;
2783173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_4K:
2784173a64cbSPatrick Boettcher 			i = 2;
2785173a64cbSPatrick Boettcher 			break;
2786173a64cbSPatrick Boettcher 	default:
2787173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_AUTO:
2788173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2789173a64cbSPatrick Boettcher 			i = 1;
2790173a64cbSPatrick Boettcher 			break;
2791173a64cbSPatrick Boettcher 	}
2792173a64cbSPatrick Boettcher 
2793c82056d0SMauro Carvalho Chehab 	return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1;
2794173a64cbSPatrick Boettcher }
2795173a64cbSPatrick Boettcher 
dib8000_set_isdbt_loop_params(struct dib8000_state * state,enum param_loop_step loop_step)2796173a64cbSPatrick Boettcher static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step)
2797173a64cbSPatrick Boettcher {
2798c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2799173a64cbSPatrick Boettcher 	u16 reg_32 = 0, reg_37 = 0;
2800173a64cbSPatrick Boettcher 
2801173a64cbSPatrick Boettcher 	switch (loop_step) {
2802173a64cbSPatrick Boettcher 	case LOOP_TUNE_1:
2803c82056d0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode)  {
2804c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) {
2805173a64cbSPatrick Boettcher 					reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */
2806173a64cbSPatrick 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)  */
2807173a64cbSPatrick Boettcher 				} else { /* Sound Broadcasting mode 3 seg */
2808173a64cbSPatrick Boettcher 					reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */
2809173a64cbSPatrick 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)  */
2810173a64cbSPatrick Boettcher 				}
2811173a64cbSPatrick Boettcher 			} else { /* 13-seg start conf offset loop parameters */
2812173a64cbSPatrick Boettcher 				reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
2813173a64cbSPatrick 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  */
2814173a64cbSPatrick Boettcher 			}
2815173a64cbSPatrick Boettcher 			break;
2816173a64cbSPatrick Boettcher 	case LOOP_TUNE_2:
2817c82056d0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode)  {
2818c82056d0SMauro Carvalho Chehab 				if (c->isdbt_partial_reception == 0) {  /* Sound Broadcasting mode 1 seg */
2819173a64cbSPatrick Boettcher 					reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/
2820173a64cbSPatrick Boettcher 					reg_37 = (12-state->mode) | ((5 + state->mode) << 5);
2821173a64cbSPatrick Boettcher 				} else {  /* Sound Broadcasting mode 3 seg */
2822173a64cbSPatrick Boettcher 					reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */
2823173a64cbSPatrick Boettcher 					reg_37 = (11-state->mode) | ((5 + state->mode) << 5);
2824173a64cbSPatrick Boettcher 				}
2825173a64cbSPatrick Boettcher 			} else {  /* 13 seg */
2826173a64cbSPatrick Boettcher 				reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */
2827173a64cbSPatrick Boettcher 				reg_37 = ((5+state->mode) << 5) | (10 - state->mode);
2828173a64cbSPatrick Boettcher 			}
2829173a64cbSPatrick Boettcher 			break;
2830173a64cbSPatrick Boettcher 	}
2831173a64cbSPatrick Boettcher 	dib8000_write_word(state, 32, reg_32);
2832173a64cbSPatrick Boettcher 	dib8000_write_word(state, 37, reg_37);
2833173a64cbSPatrick Boettcher }
2834173a64cbSPatrick Boettcher 
dib8000_demod_restart(struct dib8000_state * state)2835173a64cbSPatrick Boettcher static void dib8000_demod_restart(struct dib8000_state *state)
2836173a64cbSPatrick Boettcher {
2837173a64cbSPatrick Boettcher 	dib8000_write_word(state, 770, 0x4000);
2838173a64cbSPatrick Boettcher 	dib8000_write_word(state, 770, 0x0000);
2839173a64cbSPatrick Boettcher 	return;
2840173a64cbSPatrick Boettcher }
2841173a64cbSPatrick Boettcher 
dib8000_set_sync_wait(struct dib8000_state * state)2842173a64cbSPatrick Boettcher static void dib8000_set_sync_wait(struct dib8000_state *state)
2843173a64cbSPatrick Boettcher {
2844c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
2845173a64cbSPatrick Boettcher 	u16 sync_wait = 64;
2846173a64cbSPatrick Boettcher 
2847173a64cbSPatrick Boettcher 	/* P_dvsy_sync_wait - reuse mode */
2848c82056d0SMauro Carvalho Chehab 	switch (c->transmission_mode) {
2849173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2850173a64cbSPatrick Boettcher 			sync_wait = 256;
2851173a64cbSPatrick Boettcher 			break;
2852173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_4K:
2853173a64cbSPatrick Boettcher 			sync_wait = 128;
2854173a64cbSPatrick Boettcher 			break;
2855173a64cbSPatrick Boettcher 	default:
2856173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_2K:
2857173a64cbSPatrick Boettcher 			sync_wait =  64;
2858173a64cbSPatrick Boettcher 			break;
2859173a64cbSPatrick Boettcher 	}
2860173a64cbSPatrick Boettcher 
2861173a64cbSPatrick Boettcher 	if (state->cfg.diversity_delay == 0)
2862c82056d0SMauro Carvalho Chehab 		sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */
2863173a64cbSPatrick Boettcher 	else
2864c82056d0SMauro Carvalho Chehab 		sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */
2865173a64cbSPatrick Boettcher 
2866173a64cbSPatrick Boettcher 	dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
2867173a64cbSPatrick Boettcher }
2868173a64cbSPatrick Boettcher 
dib8000_get_timeout(struct dib8000_state * state,u32 delay,enum timeout_mode mode)2869d6c62b76SMauro Carvalho Chehab static unsigned long dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
2870173a64cbSPatrick Boettcher {
2871173a64cbSPatrick Boettcher 	if (mode == SYMBOL_DEPENDENT_ON)
2872d6c62b76SMauro Carvalho Chehab 		delay *= state->symbol_duration;
2873d6c62b76SMauro Carvalho Chehab 
2874d6c62b76SMauro Carvalho Chehab 	return jiffies + usecs_to_jiffies(delay * 100);
2875173a64cbSPatrick Boettcher }
2876173a64cbSPatrick Boettcher 
dib8000_get_status(struct dvb_frontend * fe)2877173a64cbSPatrick Boettcher static s32 dib8000_get_status(struct dvb_frontend *fe)
2878173a64cbSPatrick Boettcher {
2879173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2880173a64cbSPatrick Boettcher 	return state->status;
2881173a64cbSPatrick Boettcher }
2882173a64cbSPatrick Boettcher 
dib8000_get_tune_state(struct dvb_frontend * fe)2883d44913c1SMauro Carvalho Chehab static enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
2884173a64cbSPatrick Boettcher {
2885173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2886173a64cbSPatrick Boettcher 	return state->tune_state;
2887173a64cbSPatrick Boettcher }
2888173a64cbSPatrick Boettcher 
dib8000_set_tune_state(struct dvb_frontend * fe,enum frontend_tune_state tune_state)2889d44913c1SMauro Carvalho Chehab static int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2890173a64cbSPatrick Boettcher {
2891173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2892173a64cbSPatrick Boettcher 
2893173a64cbSPatrick Boettcher 	state->tune_state = tune_state;
2894173a64cbSPatrick Boettcher 	return 0;
2895173a64cbSPatrick Boettcher }
2896173a64cbSPatrick Boettcher 
dib8000_tune_restart_from_demod(struct dvb_frontend * fe)2897173a64cbSPatrick Boettcher static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
2898173a64cbSPatrick Boettcher {
2899173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2900173a64cbSPatrick Boettcher 
2901173a64cbSPatrick Boettcher 	state->status = FE_STATUS_TUNE_PENDING;
2902173a64cbSPatrick Boettcher 	state->tune_state = CT_DEMOD_START;
2903173a64cbSPatrick Boettcher 	return 0;
2904173a64cbSPatrick Boettcher }
2905173a64cbSPatrick Boettcher 
dib8000_read_lock(struct dvb_frontend * fe)2906173a64cbSPatrick Boettcher static u16 dib8000_read_lock(struct dvb_frontend *fe)
2907173a64cbSPatrick Boettcher {
2908173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2909173a64cbSPatrick Boettcher 
2910173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
2911173a64cbSPatrick Boettcher 		return dib8000_read_word(state, 570);
2912173a64cbSPatrick Boettcher 	return dib8000_read_word(state, 568);
2913173a64cbSPatrick Boettcher }
2914173a64cbSPatrick Boettcher 
dib8090p_init_sdram(struct dib8000_state * state)2915173a64cbSPatrick Boettcher static int dib8090p_init_sdram(struct dib8000_state *state)
2916173a64cbSPatrick Boettcher {
2917173a64cbSPatrick Boettcher 	u16 reg = 0;
29188af16adfSMauro Carvalho Chehab 	dprintk("init sdram\n");
2919173a64cbSPatrick Boettcher 
2920173a64cbSPatrick Boettcher 	reg = dib8000_read_word(state, 274) & 0xfff0;
2921173a64cbSPatrick Boettcher 	dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */
2922173a64cbSPatrick Boettcher 
2923173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1803, (7 << 2));
2924173a64cbSPatrick Boettcher 
2925173a64cbSPatrick Boettcher 	reg = dib8000_read_word(state, 1280);
2926173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1280,  reg | (1 << 2)); /* force restart P_restart_sdram */
2927173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1280,  reg); /* release restart P_restart_sdram */
2928173a64cbSPatrick Boettcher 
2929173a64cbSPatrick Boettcher 	return 0;
2930173a64cbSPatrick Boettcher }
2931173a64cbSPatrick Boettcher 
2932ad976187SMauro Carvalho Chehab /**
2933ad976187SMauro Carvalho Chehab  * is_manual_mode - Check if TMCC should be used for parameters settings
2934ad976187SMauro Carvalho Chehab  * @c:	struct dvb_frontend_properties
2935ad976187SMauro Carvalho Chehab  *
2936ad976187SMauro Carvalho Chehab  * By default, TMCC table should be used for parameter settings on most
2937ad976187SMauro Carvalho Chehab  * usercases. However, sometimes it is desirable to lock the demod to
2938ad976187SMauro Carvalho Chehab  * use the manual parameters.
2939ad976187SMauro Carvalho Chehab  *
2940ad976187SMauro Carvalho Chehab  * On manual mode, the current dib8000_tune state machine is very restrict:
2941ad976187SMauro Carvalho Chehab  * It requires that both per-layer and per-transponder parameters to be
2942ad976187SMauro Carvalho Chehab  * properly specified, otherwise the device won't lock.
2943ad976187SMauro Carvalho Chehab  *
2944ad976187SMauro Carvalho Chehab  * Check if all those conditions are properly satisfied before allowing
2945ad976187SMauro Carvalho Chehab  * the device to use the manual frequency lock mode.
2946ad976187SMauro Carvalho Chehab  */
is_manual_mode(struct dtv_frontend_properties * c)2947ad976187SMauro Carvalho Chehab static int is_manual_mode(struct dtv_frontend_properties *c)
2948ad976187SMauro Carvalho Chehab {
2949ad976187SMauro Carvalho Chehab 	int i, n_segs = 0;
2950ad976187SMauro Carvalho Chehab 
2951ad976187SMauro Carvalho Chehab 	/* Use auto mode on DVB-T compat mode */
2952ad976187SMauro Carvalho Chehab 	if (c->delivery_system != SYS_ISDBT)
2953ad976187SMauro Carvalho Chehab 		return 0;
2954ad976187SMauro Carvalho Chehab 
2955ad976187SMauro Carvalho Chehab 	/*
2956ad976187SMauro Carvalho Chehab 	 * Transmission mode is only detected on auto mode, currently
2957ad976187SMauro Carvalho Chehab 	 */
2958ad976187SMauro Carvalho Chehab 	if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
29598af16adfSMauro Carvalho Chehab 		dprintk("transmission mode auto\n");
2960ad976187SMauro Carvalho Chehab 		return 0;
2961ad976187SMauro Carvalho Chehab 	}
2962ad976187SMauro Carvalho Chehab 
2963ad976187SMauro Carvalho Chehab 	/*
2964ad976187SMauro Carvalho Chehab 	 * Guard interval is only detected on auto mode, currently
2965ad976187SMauro Carvalho Chehab 	 */
2966ad976187SMauro Carvalho Chehab 	if (c->guard_interval == GUARD_INTERVAL_AUTO) {
29678af16adfSMauro Carvalho Chehab 		dprintk("guard interval auto\n");
2968ad976187SMauro Carvalho Chehab 		return 0;
2969ad976187SMauro Carvalho Chehab 	}
2970ad976187SMauro Carvalho Chehab 
2971ad976187SMauro Carvalho Chehab 	/*
2972ad976187SMauro Carvalho Chehab 	 * If no layer is enabled, assume auto mode, as at least one
2973ad976187SMauro Carvalho Chehab 	 * layer should be enabled
2974ad976187SMauro Carvalho Chehab 	 */
2975ad976187SMauro Carvalho Chehab 	if (!c->isdbt_layer_enabled) {
29768af16adfSMauro Carvalho Chehab 		dprintk("no layer modulation specified\n");
2977ad976187SMauro Carvalho Chehab 		return 0;
2978ad976187SMauro Carvalho Chehab 	}
2979ad976187SMauro Carvalho Chehab 
2980ad976187SMauro Carvalho Chehab 	/*
2981ad976187SMauro Carvalho Chehab 	 * Check if the per-layer parameters aren't auto and
2982ad976187SMauro Carvalho Chehab 	 * disable a layer if segment count is 0 or invalid.
2983ad976187SMauro Carvalho Chehab 	 */
2984ad976187SMauro Carvalho Chehab 	for (i = 0; i < 3; i++) {
2985ad976187SMauro Carvalho Chehab 		if (!(c->isdbt_layer_enabled & 1 << i))
2986ad976187SMauro Carvalho Chehab 			continue;
2987ad976187SMauro Carvalho Chehab 
2988ad976187SMauro Carvalho Chehab 		if ((c->layer[i].segment_count > 13) ||
2989ad976187SMauro Carvalho Chehab 		    (c->layer[i].segment_count == 0)) {
2990ad976187SMauro Carvalho Chehab 			c->isdbt_layer_enabled &= ~(1 << i);
2991ad976187SMauro Carvalho Chehab 			continue;
2992ad976187SMauro Carvalho Chehab 		}
2993ad976187SMauro Carvalho Chehab 
2994ad976187SMauro Carvalho Chehab 		n_segs += c->layer[i].segment_count;
2995ad976187SMauro Carvalho Chehab 
2996ad976187SMauro Carvalho Chehab 		if ((c->layer[i].modulation == QAM_AUTO) ||
2997ad976187SMauro Carvalho Chehab 		    (c->layer[i].fec == FEC_AUTO)) {
29988af16adfSMauro Carvalho Chehab 			dprintk("layer %c has either modulation or FEC auto\n",
2999ad976187SMauro Carvalho Chehab 				'A' + i);
3000ad976187SMauro Carvalho Chehab 			return 0;
3001ad976187SMauro Carvalho Chehab 		}
3002ad976187SMauro Carvalho Chehab 	}
3003ad976187SMauro Carvalho Chehab 
3004ad976187SMauro Carvalho Chehab 	/*
3005ad976187SMauro Carvalho Chehab 	 * Userspace specified a wrong number of segments.
3006ad976187SMauro Carvalho Chehab 	 *	fallback to auto mode.
3007ad976187SMauro Carvalho Chehab 	 */
3008ad976187SMauro Carvalho Chehab 	if (n_segs == 0 || n_segs > 13) {
30098af16adfSMauro Carvalho Chehab 		dprintk("number of segments is invalid\n");
3010ad976187SMauro Carvalho Chehab 		return 0;
3011ad976187SMauro Carvalho Chehab 	}
3012ad976187SMauro Carvalho Chehab 
3013ad976187SMauro Carvalho Chehab 	/* Everything looks ok for manual mode */
3014ad976187SMauro Carvalho Chehab 	return 1;
3015ad976187SMauro Carvalho Chehab }
3016ad976187SMauro Carvalho Chehab 
dib8000_tune(struct dvb_frontend * fe)30179a0bf528SMauro Carvalho Chehab static int dib8000_tune(struct dvb_frontend *fe)
30189a0bf528SMauro Carvalho Chehab {
30199a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
3020c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3021173a64cbSPatrick Boettcher 	enum frontend_tune_state *tune_state = &state->tune_state;
30229a0bf528SMauro Carvalho Chehab 
3023173a64cbSPatrick Boettcher 	u16 locks, deeper_interleaver = 0, i;
3024173a64cbSPatrick Boettcher 	int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
30259a0bf528SMauro Carvalho Chehab 
3026d6c62b76SMauro Carvalho Chehab 	unsigned long *timeout = &state->timeout;
3027d6c62b76SMauro Carvalho Chehab 	unsigned long now = jiffies;
30288db11aebSMauro Carvalho Chehab 	u16 init_prbs;
3029173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3030173a64cbSPatrick Boettcher 	u16 agc1, agc2;
3031173a64cbSPatrick Boettcher #endif
30329a0bf528SMauro Carvalho Chehab 
3033173a64cbSPatrick Boettcher 	u32 corm[4] = {0, 0, 0, 0};
3034173a64cbSPatrick Boettcher 	u8 find_index, max_value;
30359a0bf528SMauro Carvalho Chehab 
3036173a64cbSPatrick Boettcher #if 0
3037173a64cbSPatrick Boettcher 	if (*tune_state < CT_DEMOD_STOP)
30388af16adfSMauro Carvalho Chehab 		dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u jiffies = %lu\n",
3039d6c62b76SMauro Carvalho Chehab 			state->channel_parameters_set, *tune_state, state->autosearch_state, now);
3040173a64cbSPatrick Boettcher #endif
30419a0bf528SMauro Carvalho Chehab 
3042173a64cbSPatrick Boettcher 	switch (*tune_state) {
3043173a64cbSPatrick Boettcher 	case CT_DEMOD_START: /* 30 */
30446ef06e78SMauro Carvalho Chehab 		dib8000_reset_stats(fe);
30456ef06e78SMauro Carvalho Chehab 
3046173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
3047173a64cbSPatrick Boettcher 			dib8090p_init_sdram(state);
3048173a64cbSPatrick Boettcher 		state->status = FE_STATUS_TUNE_PENDING;
3049ad976187SMauro Carvalho Chehab 		state->channel_parameters_set = is_manual_mode(c);
3050ad976187SMauro Carvalho Chehab 
30518af16adfSMauro Carvalho Chehab 		dprintk("Tuning channel on %s search mode\n",
3052ad976187SMauro Carvalho Chehab 			state->channel_parameters_set ? "manual" : "auto");
30539a0bf528SMauro Carvalho Chehab 
3054173a64cbSPatrick Boettcher 		dib8000_viterbi_state(state, 0); /* force chan dec in restart */
30559a0bf528SMauro Carvalho Chehab 
3056ad976187SMauro Carvalho Chehab 		/* Layer monitor */
3057173a64cbSPatrick Boettcher 		dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
3058173a64cbSPatrick Boettcher 
3059173a64cbSPatrick Boettcher 		dib8000_set_frequency_offset(state);
3060c82056d0SMauro Carvalho Chehab 		dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
3061173a64cbSPatrick Boettcher 
3062173a64cbSPatrick Boettcher 		if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
3063173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3064173a64cbSPatrick Boettcher 			if (state->revision != 0x8090) {
3065173a64cbSPatrick Boettcher 				state->agc1_max = dib8000_read_word(state, 108);
3066173a64cbSPatrick Boettcher 				state->agc1_min = dib8000_read_word(state, 109);
3067173a64cbSPatrick Boettcher 				state->agc2_max = dib8000_read_word(state, 110);
3068173a64cbSPatrick Boettcher 				state->agc2_min = dib8000_read_word(state, 111);
3069173a64cbSPatrick Boettcher 				agc1 = dib8000_read_word(state, 388);
3070173a64cbSPatrick Boettcher 				agc2 = dib8000_read_word(state, 389);
3071173a64cbSPatrick Boettcher 				dib8000_write_word(state, 108, agc1);
3072173a64cbSPatrick Boettcher 				dib8000_write_word(state, 109, agc1);
3073173a64cbSPatrick Boettcher 				dib8000_write_word(state, 110, agc2);
3074173a64cbSPatrick Boettcher 				dib8000_write_word(state, 111, agc2);
3075173a64cbSPatrick Boettcher 			}
3076173a64cbSPatrick Boettcher #endif
3077173a64cbSPatrick Boettcher 			state->autosearch_state = AS_SEARCHING_FFT;
3078173a64cbSPatrick Boettcher 			state->found_nfft = TRANSMISSION_MODE_AUTO;
3079173a64cbSPatrick Boettcher 			state->found_guard = GUARD_INTERVAL_AUTO;
3080173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_SEARCH_NEXT;
3081173a64cbSPatrick Boettcher 		} else { /* we already know the channel struct so TUNE only ! */
3082173a64cbSPatrick Boettcher 			state->autosearch_state = AS_DONE;
3083173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_3;
3084173a64cbSPatrick Boettcher 		}
3085173a64cbSPatrick Boettcher 		state->symbol_duration = dib8000_get_symbol_duration(state);
3086173a64cbSPatrick Boettcher 		break;
3087173a64cbSPatrick Boettcher 
3088173a64cbSPatrick Boettcher 	case CT_DEMOD_SEARCH_NEXT: /* 51 */
3089173a64cbSPatrick Boettcher 		dib8000_autosearch_start(fe);
3090173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
3091173a64cbSPatrick Boettcher 			ret = 50;
3092173a64cbSPatrick Boettcher 		else
3093173a64cbSPatrick Boettcher 			ret = 15;
3094173a64cbSPatrick Boettcher 		*tune_state = CT_DEMOD_STEP_1;
3095173a64cbSPatrick Boettcher 		break;
3096173a64cbSPatrick Boettcher 
3097173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_1: /* 31 */
3098173a64cbSPatrick Boettcher 		switch (dib8000_autosearch_irq(fe)) {
3099173a64cbSPatrick Boettcher 		case 1: /* fail */
3100173a64cbSPatrick Boettcher 			state->status = FE_STATUS_TUNE_FAILED;
3101173a64cbSPatrick Boettcher 			state->autosearch_state = AS_DONE;
3102173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STOP; /* else we are done here */
3103173a64cbSPatrick Boettcher 			break;
3104868c9a17SMauro Carvalho Chehab 		case 2: /* Success */
3105173a64cbSPatrick Boettcher 			state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
3106173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_3;
3107173a64cbSPatrick Boettcher 			if (state->autosearch_state == AS_SEARCHING_GUARD)
3108173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_2;
3109173a64cbSPatrick Boettcher 			else
3110173a64cbSPatrick Boettcher 				state->autosearch_state = AS_DONE;
3111173a64cbSPatrick Boettcher 			break;
3112173a64cbSPatrick Boettcher 		case 3: /* Autosearch FFT max correlation endded */
3113173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_2;
3114173a64cbSPatrick Boettcher 			break;
3115173a64cbSPatrick Boettcher 		}
3116173a64cbSPatrick Boettcher 		break;
3117173a64cbSPatrick Boettcher 
3118173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_2:
3119173a64cbSPatrick Boettcher 		switch (state->autosearch_state) {
3120173a64cbSPatrick Boettcher 		case AS_SEARCHING_FFT:
3121173a64cbSPatrick Boettcher 			/* searching for the correct FFT */
3122173a64cbSPatrick Boettcher 			if (state->revision == 0x8090) {
3123173a64cbSPatrick Boettcher 				corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3124173a64cbSPatrick Boettcher 				corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3125173a64cbSPatrick Boettcher 				corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
3126173a64cbSPatrick Boettcher 			} else {
3127173a64cbSPatrick Boettcher 				corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
3128173a64cbSPatrick Boettcher 				corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3129173a64cbSPatrick Boettcher 				corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3130173a64cbSPatrick Boettcher 			}
31318af16adfSMauro Carvalho Chehab 			/* dprintk("corm fft: %u %u %u\n", corm[0], corm[1], corm[2]); */
3132173a64cbSPatrick Boettcher 
3133173a64cbSPatrick Boettcher 			max_value = 0;
3134173a64cbSPatrick Boettcher 			for (find_index = 1 ; find_index < 3 ; find_index++) {
3135173a64cbSPatrick Boettcher 				if (corm[max_value] < corm[find_index])
3136173a64cbSPatrick Boettcher 					max_value = find_index ;
31379a0bf528SMauro Carvalho Chehab 			}
31389a0bf528SMauro Carvalho Chehab 
3139173a64cbSPatrick Boettcher 			switch (max_value) {
3140173a64cbSPatrick Boettcher 			case 0:
3141173a64cbSPatrick Boettcher 				state->found_nfft = TRANSMISSION_MODE_2K;
3142173a64cbSPatrick Boettcher 				break;
3143173a64cbSPatrick Boettcher 			case 1:
3144173a64cbSPatrick Boettcher 				state->found_nfft = TRANSMISSION_MODE_4K;
3145173a64cbSPatrick Boettcher 				break;
3146173a64cbSPatrick Boettcher 			case 2:
3147173a64cbSPatrick Boettcher 			default:
3148173a64cbSPatrick Boettcher 				state->found_nfft = TRANSMISSION_MODE_8K;
3149173a64cbSPatrick Boettcher 				break;
3150173a64cbSPatrick Boettcher 			}
31518af16adfSMauro Carvalho Chehab 			/* dprintk("Autosearch FFT has found Mode %d\n", max_value + 1); */
3152173a64cbSPatrick Boettcher 
3153173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_SEARCH_NEXT;
3154173a64cbSPatrick Boettcher 			state->autosearch_state = AS_SEARCHING_GUARD;
3155173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
3156173a64cbSPatrick Boettcher 				ret = 50;
3157173a64cbSPatrick Boettcher 			else
3158173a64cbSPatrick Boettcher 				ret = 10;
3159173a64cbSPatrick Boettcher 			break;
3160173a64cbSPatrick Boettcher 		case AS_SEARCHING_GUARD:
3161173a64cbSPatrick Boettcher 			/* searching for the correct guard interval */
3162173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
3163173a64cbSPatrick Boettcher 				state->found_guard = dib8000_read_word(state, 572) & 0x3;
3164173a64cbSPatrick Boettcher 			else
3165173a64cbSPatrick Boettcher 				state->found_guard = dib8000_read_word(state, 570) & 0x3;
31668af16adfSMauro Carvalho Chehab 			/* dprintk("guard interval found=%i\n", state->found_guard); */
3167173a64cbSPatrick Boettcher 
3168173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_3;
3169173a64cbSPatrick Boettcher 			break;
3170173a64cbSPatrick Boettcher 		default:
3171173a64cbSPatrick Boettcher 			/* the demod should never be in this state */
3172173a64cbSPatrick Boettcher 			state->status = FE_STATUS_TUNE_FAILED;
3173173a64cbSPatrick Boettcher 			state->autosearch_state = AS_DONE;
3174173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STOP; /* else we are done here */
3175173a64cbSPatrick Boettcher 			break;
3176173a64cbSPatrick Boettcher 		}
3177173a64cbSPatrick Boettcher 		break;
3178173a64cbSPatrick Boettcher 
3179173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_3: /* 33 */
3180173a64cbSPatrick Boettcher 		dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
3181173a64cbSPatrick Boettcher 		dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
3182173a64cbSPatrick Boettcher 		*tune_state = CT_DEMOD_STEP_4;
3183173a64cbSPatrick Boettcher 		break;
3184173a64cbSPatrick Boettcher 
3185173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_4: /* (34) */
3186173a64cbSPatrick Boettcher 		dib8000_demod_restart(state);
3187173a64cbSPatrick Boettcher 
3188173a64cbSPatrick Boettcher 		dib8000_set_sync_wait(state);
3189173a64cbSPatrick Boettcher 		dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
3190173a64cbSPatrick Boettcher 
3191173a64cbSPatrick Boettcher 		locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
319239c1cb2bSJonathan McCrohan 		/* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */
3193173a64cbSPatrick Boettcher 		*timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
3194173a64cbSPatrick Boettcher 		*tune_state = CT_DEMOD_STEP_5;
3195173a64cbSPatrick Boettcher 		break;
3196173a64cbSPatrick Boettcher 
3197173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_5: /* (35) */
3198173a64cbSPatrick Boettcher 		locks = dib8000_read_lock(fe);
3199173a64cbSPatrick Boettcher 		if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
3200173a64cbSPatrick Boettcher 			dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
3201173a64cbSPatrick Boettcher 			if (!state->differential_constellation) {
3202173a64cbSPatrick Boettcher 				/* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
3203173a64cbSPatrick Boettcher 				*timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
3204173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_7;
3205173a64cbSPatrick Boettcher 			} else {
3206173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_8;
3207173a64cbSPatrick Boettcher 			}
3208d6c62b76SMauro Carvalho Chehab 		} else if (time_after(now, *timeout)) {
3209173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3210173a64cbSPatrick Boettcher 		}
3211173a64cbSPatrick Boettcher 		break;
3212173a64cbSPatrick Boettcher 
3213173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_6: /* (36)  if there is an input (diversity) */
3214173a64cbSPatrick Boettcher 		if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
3215d063ddfbSJason Wang 			/* if there is a diversity fe in input and this fe is has not already failed : wait here until this fe has succeeded or failed */
3216173a64cbSPatrick Boettcher 			if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
3217173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
3218868c9a17SMauro Carvalho Chehab 			else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failed also, break the current one */
3219173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3220173a64cbSPatrick Boettcher 				dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3221173a64cbSPatrick Boettcher 				dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3222173a64cbSPatrick Boettcher 				state->status = FE_STATUS_TUNE_FAILED;
3223173a64cbSPatrick Boettcher 			}
3224173a64cbSPatrick Boettcher 		} else {
3225173a64cbSPatrick Boettcher 			dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3226173a64cbSPatrick Boettcher 			dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3227173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3228173a64cbSPatrick Boettcher 			state->status = FE_STATUS_TUNE_FAILED;
3229173a64cbSPatrick Boettcher 		}
3230173a64cbSPatrick Boettcher 		break;
3231173a64cbSPatrick Boettcher 
3232173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_7: /* 37 */
3233173a64cbSPatrick Boettcher 		locks = dib8000_read_lock(fe);
3234173a64cbSPatrick Boettcher 		if (locks & (1<<10)) { /* lmod4_lock */
3235173a64cbSPatrick Boettcher 			ret = 14; /* wait for 14 symbols */
3236173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_8;
3237d6c62b76SMauro Carvalho Chehab 		} else if (time_after(now, *timeout))
3238173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3239173a64cbSPatrick Boettcher 		break;
3240173a64cbSPatrick Boettcher 
3241173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_8: /* 38 */
3242173a64cbSPatrick Boettcher 		dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3243173a64cbSPatrick Boettcher 		dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3244173a64cbSPatrick Boettcher 
3245173a64cbSPatrick Boettcher 		/* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
3246746f7ae0SMauro Carvalho Chehab 		if (c->isdbt_sb_mode
3247746f7ae0SMauro Carvalho Chehab 		    && c->isdbt_sb_subchannel < 14
3248746f7ae0SMauro Carvalho Chehab 		    && !state->differential_constellation) {
3249173a64cbSPatrick Boettcher 			state->subchannel = 0;
3250173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_11;
3251173a64cbSPatrick Boettcher 		} else {
3252173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_9;
3253173a64cbSPatrick Boettcher 			state->status = FE_STATUS_LOCKED;
3254173a64cbSPatrick Boettcher 		}
3255173a64cbSPatrick Boettcher 		break;
3256173a64cbSPatrick Boettcher 
3257173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_9: /* 39 */
3258173a64cbSPatrick Boettcher 		if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
325939c1cb2bSJonathan McCrohan 			/* defines timeout for mpeg lock depending on interleaver length of longest layer */
3260173a64cbSPatrick Boettcher 			for (i = 0; i < 3; i++) {
3261c82056d0SMauro Carvalho Chehab 				if (c->layer[i].interleaving >= deeper_interleaver) {
32628af16adfSMauro Carvalho Chehab 					dprintk("layer%i: time interleaver = %d\n", i, c->layer[i].interleaving);
3263c82056d0SMauro Carvalho Chehab 					if (c->layer[i].segment_count > 0) { /* valid layer */
3264c82056d0SMauro Carvalho Chehab 						deeper_interleaver = c->layer[0].interleaving;
3265173a64cbSPatrick Boettcher 						state->longest_intlv_layer = i;
3266173a64cbSPatrick Boettcher 					}
3267173a64cbSPatrick Boettcher 				}
3268173a64cbSPatrick Boettcher 			}
3269173a64cbSPatrick Boettcher 
3270173a64cbSPatrick Boettcher 			if (deeper_interleaver == 0)
3271173a64cbSPatrick Boettcher 				locks = 2; /* locks is the tmp local variable name */
3272173a64cbSPatrick Boettcher 			else if (deeper_interleaver == 3)
3273173a64cbSPatrick Boettcher 				locks = 8;
3274173a64cbSPatrick Boettcher 			else
3275173a64cbSPatrick Boettcher 				locks = 2 * deeper_interleaver;
3276173a64cbSPatrick Boettcher 
3277173a64cbSPatrick Boettcher 			if (state->diversity_onoff != 0) /* because of diversity sync */
3278173a64cbSPatrick Boettcher 				locks *= 2;
3279173a64cbSPatrick Boettcher 
3280d6c62b76SMauro Carvalho Chehab 			*timeout = now + msecs_to_jiffies(200 * locks); /* give the mpeg lock 800ms if sram is present */
32818af16adfSMauro Carvalho Chehab 			dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %ld\n",
3282d6c62b76SMauro Carvalho Chehab 				deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
3283173a64cbSPatrick Boettcher 
3284173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_10;
3285173a64cbSPatrick Boettcher 		} else
3286173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STOP;
3287173a64cbSPatrick Boettcher 		break;
3288173a64cbSPatrick Boettcher 
3289173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_10: /* 40 */
3290173a64cbSPatrick Boettcher 		locks = dib8000_read_lock(fe);
3291173a64cbSPatrick Boettcher 		if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
32928af16adfSMauro Carvalho Chehab 			dprintk("ISDB-T layer locks: Layer A %s, Layer B %s, Layer C %s\n",
32933c0d394eSMauro Carvalho Chehab 				c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
32943c0d394eSMauro Carvalho Chehab 				c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
32953c0d394eSMauro Carvalho Chehab 				c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
3296746f7ae0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode
3297746f7ae0SMauro Carvalho Chehab 			    && c->isdbt_sb_subchannel < 14
3298746f7ae0SMauro Carvalho Chehab 			    && !state->differential_constellation)
3299173a64cbSPatrick Boettcher 				/* signal to the upper layer, that there was a channel found and the parameters can be read */
3300173a64cbSPatrick Boettcher 				state->status = FE_STATUS_DEMOD_SUCCESS;
3301173a64cbSPatrick Boettcher 			else
3302173a64cbSPatrick Boettcher 				state->status = FE_STATUS_DATA_LOCKED;
3303173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STOP;
3304d6c62b76SMauro Carvalho Chehab 		} else if (time_after(now, *timeout)) {
3305746f7ae0SMauro Carvalho Chehab 			if (c->isdbt_sb_mode
3306746f7ae0SMauro Carvalho Chehab 			    && c->isdbt_sb_subchannel < 14
3307746f7ae0SMauro Carvalho Chehab 			    && !state->differential_constellation) { /* continue to try init prbs autosearch */
3308173a64cbSPatrick Boettcher 				state->subchannel += 3;
3309173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_11;
3310173a64cbSPatrick 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 */
3311173a64cbSPatrick Boettcher 				if (locks & (0x7 << 5)) {
33128af16adfSMauro Carvalho Chehab 					dprintk("Not all ISDB-T layers locked in %d ms: Layer A %s, Layer B %s, Layer C %s\n",
33133c0d394eSMauro Carvalho Chehab 						jiffies_to_msecs(now - *timeout),
33143c0d394eSMauro Carvalho Chehab 						c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
33153c0d394eSMauro Carvalho Chehab 						c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
33163c0d394eSMauro Carvalho Chehab 						c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
33173c0d394eSMauro Carvalho Chehab 
3318173a64cbSPatrick Boettcher 					state->status = FE_STATUS_DATA_LOCKED;
3319173a64cbSPatrick Boettcher 				} else
3320173a64cbSPatrick Boettcher 					state->status = FE_STATUS_TUNE_FAILED;
3321173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP;
3322173a64cbSPatrick Boettcher 			}
3323173a64cbSPatrick Boettcher 		}
3324173a64cbSPatrick Boettcher 		break;
3325173a64cbSPatrick Boettcher 
3326173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_11:  /* 41 : init prbs autosearch */
33278db11aebSMauro Carvalho Chehab 		init_prbs = dib8000_get_init_prbs(state, state->subchannel);
33288db11aebSMauro Carvalho Chehab 
33298db11aebSMauro Carvalho Chehab 		if (init_prbs) {
33308db11aebSMauro Carvalho Chehab 			dib8000_set_subchannel_prbs(state, init_prbs);
3331173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_9;
3332173a64cbSPatrick Boettcher 		} else {
3333173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STOP;
3334173a64cbSPatrick Boettcher 			state->status = FE_STATUS_TUNE_FAILED;
3335173a64cbSPatrick Boettcher 		}
3336173a64cbSPatrick Boettcher 		break;
3337173a64cbSPatrick Boettcher 
3338173a64cbSPatrick Boettcher 	default:
3339173a64cbSPatrick Boettcher 		break;
3340173a64cbSPatrick Boettcher 	}
3341173a64cbSPatrick Boettcher 
3342173a64cbSPatrick Boettcher 	/* tuning is finished - cleanup the demod */
3343173a64cbSPatrick Boettcher 	switch (*tune_state) {
3344173a64cbSPatrick Boettcher 	case CT_DEMOD_STOP: /* (42) */
3345173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3346173a64cbSPatrick Boettcher 		if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
3347173a64cbSPatrick Boettcher 			dib8000_write_word(state, 108, state->agc1_max);
3348173a64cbSPatrick Boettcher 			dib8000_write_word(state, 109, state->agc1_min);
3349173a64cbSPatrick Boettcher 			dib8000_write_word(state, 110, state->agc2_max);
3350173a64cbSPatrick Boettcher 			dib8000_write_word(state, 111, state->agc2_min);
3351173a64cbSPatrick Boettcher 			state->agc1_max = 0;
3352173a64cbSPatrick Boettcher 			state->agc1_min = 0;
3353173a64cbSPatrick Boettcher 			state->agc2_max = 0;
3354173a64cbSPatrick Boettcher 			state->agc2_min = 0;
3355173a64cbSPatrick Boettcher 		}
3356173a64cbSPatrick Boettcher #endif
3357d6c62b76SMauro Carvalho Chehab 		ret = 0;
3358173a64cbSPatrick Boettcher 		break;
3359173a64cbSPatrick Boettcher 	default:
3360173a64cbSPatrick Boettcher 		break;
3361173a64cbSPatrick Boettcher 	}
3362173a64cbSPatrick Boettcher 
3363173a64cbSPatrick Boettcher 	if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
3364173a64cbSPatrick Boettcher 		return ret * state->symbol_duration;
3365173a64cbSPatrick Boettcher 	if ((ret > 0) && (ret < state->symbol_duration))
3366173a64cbSPatrick Boettcher 		return state->symbol_duration; /* at least one symbol */
33679a0bf528SMauro Carvalho Chehab 	return ret;
33689a0bf528SMauro Carvalho Chehab }
33699a0bf528SMauro Carvalho Chehab 
dib8000_wakeup(struct dvb_frontend * fe)33709a0bf528SMauro Carvalho Chehab static int dib8000_wakeup(struct dvb_frontend *fe)
33719a0bf528SMauro Carvalho Chehab {
33729a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
33739a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
33749a0bf528SMauro Carvalho Chehab 	int ret;
33759a0bf528SMauro Carvalho Chehab 
33769a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
33779a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_ADC_ON);
33789a0bf528SMauro Carvalho Chehab 	if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
33798af16adfSMauro Carvalho Chehab 		dprintk("could not start Slow ADC\n");
33809a0bf528SMauro Carvalho Chehab 
3381173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
33829a0bf528SMauro Carvalho Chehab 		dib8000_sad_calib(state);
33839a0bf528SMauro Carvalho Chehab 
33849a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
33859a0bf528SMauro Carvalho Chehab 		ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
33869a0bf528SMauro Carvalho Chehab 		if (ret < 0)
33879a0bf528SMauro Carvalho Chehab 			return ret;
33889a0bf528SMauro Carvalho Chehab 	}
33899a0bf528SMauro Carvalho Chehab 
33909a0bf528SMauro Carvalho Chehab 	return 0;
33919a0bf528SMauro Carvalho Chehab }
33929a0bf528SMauro Carvalho Chehab 
dib8000_sleep(struct dvb_frontend * fe)33939a0bf528SMauro Carvalho Chehab static int dib8000_sleep(struct dvb_frontend *fe)
33949a0bf528SMauro Carvalho Chehab {
33959a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
33969a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
33979a0bf528SMauro Carvalho Chehab 	int ret;
33989a0bf528SMauro Carvalho Chehab 
33999a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
34009a0bf528SMauro Carvalho Chehab 		ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
34019a0bf528SMauro Carvalho Chehab 		if (ret < 0)
34029a0bf528SMauro Carvalho Chehab 			return ret;
34039a0bf528SMauro Carvalho Chehab 	}
34049a0bf528SMauro Carvalho Chehab 
34059a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
34069a0bf528SMauro Carvalho Chehab 		dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
34079a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
34089a0bf528SMauro Carvalho Chehab 	return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
34099a0bf528SMauro Carvalho Chehab }
34109a0bf528SMauro Carvalho Chehab 
34110df289a2SMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat);
341270315b3eSMauro Carvalho Chehab 
dib8000_get_frontend(struct dvb_frontend * fe,struct dtv_frontend_properties * c)34137e3e68bcSMauro Carvalho Chehab static int dib8000_get_frontend(struct dvb_frontend *fe,
34147e3e68bcSMauro Carvalho Chehab 				struct dtv_frontend_properties *c)
34159a0bf528SMauro Carvalho Chehab {
34169a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
34179a0bf528SMauro Carvalho Chehab 	u16 i, val = 0;
34180df289a2SMauro Carvalho Chehab 	enum fe_status stat = 0;
34199a0bf528SMauro Carvalho Chehab 	u8 index_frontend, sub_index_frontend;
34209a0bf528SMauro Carvalho Chehab 
34217e3e68bcSMauro Carvalho Chehab 	c->bandwidth_hz = 6000000;
34229a0bf528SMauro Carvalho Chehab 
342370315b3eSMauro Carvalho Chehab 	/*
342470315b3eSMauro Carvalho Chehab 	 * If called to early, get_frontend makes dib8000_tune to either
342570315b3eSMauro Carvalho Chehab 	 * not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail.
342670315b3eSMauro Carvalho Chehab 	 * So, let's just return if frontend 0 has not locked.
342770315b3eSMauro Carvalho Chehab 	 */
342870315b3eSMauro Carvalho Chehab 	dib8000_read_status(fe, &stat);
342970315b3eSMauro Carvalho Chehab 	if (!(stat & FE_HAS_SYNC))
343070315b3eSMauro Carvalho Chehab 		return 0;
343170315b3eSMauro Carvalho Chehab 
34328af16adfSMauro Carvalho Chehab 	dprintk("dib8000_get_frontend: TMCC lock\n");
34339a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
34349a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
34359a0bf528SMauro Carvalho Chehab 		if (stat&FE_HAS_SYNC) {
34368af16adfSMauro Carvalho Chehab 			dprintk("TMCC lock on the slave%i\n", index_frontend);
34379a0bf528SMauro Carvalho Chehab 			/* synchronize the cache with the other frontends */
34387e3e68bcSMauro Carvalho Chehab 			state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], c);
34399a0bf528SMauro Carvalho Chehab 			for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {
34409a0bf528SMauro Carvalho Chehab 				if (sub_index_frontend != index_frontend) {
34419a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
34429a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
34439a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
34449a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
34459a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
34469a0bf528SMauro Carvalho Chehab 					for (i = 0; i < 3; i++) {
34479a0bf528SMauro 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;
34489a0bf528SMauro Carvalho Chehab 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
34499a0bf528SMauro Carvalho Chehab 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
34509a0bf528SMauro Carvalho Chehab 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
34519a0bf528SMauro Carvalho Chehab 					}
34529a0bf528SMauro Carvalho Chehab 				}
34539a0bf528SMauro Carvalho Chehab 			}
34549a0bf528SMauro Carvalho Chehab 			return 0;
34559a0bf528SMauro Carvalho Chehab 		}
34569a0bf528SMauro Carvalho Chehab 	}
34579a0bf528SMauro Carvalho Chehab 
34587e3e68bcSMauro Carvalho Chehab 	c->isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
34599a0bf528SMauro Carvalho Chehab 
34609a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
34619a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 572);
34629a0bf528SMauro Carvalho Chehab 	else
34639a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 570);
34647e3e68bcSMauro Carvalho Chehab 	c->inversion = (val & 0x40) >> 6;
34659a0bf528SMauro Carvalho Chehab 	switch ((val & 0x30) >> 4) {
34669a0bf528SMauro Carvalho Chehab 	case 1:
34677e3e68bcSMauro Carvalho Chehab 		c->transmission_mode = TRANSMISSION_MODE_2K;
34688af16adfSMauro Carvalho Chehab 		dprintk("dib8000_get_frontend: transmission mode 2K\n");
34699a0bf528SMauro Carvalho Chehab 		break;
34707fec1c80SMauro Carvalho Chehab 	case 2:
34717e3e68bcSMauro Carvalho Chehab 		c->transmission_mode = TRANSMISSION_MODE_4K;
34728af16adfSMauro Carvalho Chehab 		dprintk("dib8000_get_frontend: transmission mode 4K\n");
34737fec1c80SMauro Carvalho Chehab 		break;
34749a0bf528SMauro Carvalho Chehab 	case 3:
34759a0bf528SMauro Carvalho Chehab 	default:
34767e3e68bcSMauro Carvalho Chehab 		c->transmission_mode = TRANSMISSION_MODE_8K;
34778af16adfSMauro Carvalho Chehab 		dprintk("dib8000_get_frontend: transmission mode 8K\n");
34789a0bf528SMauro Carvalho Chehab 		break;
34799a0bf528SMauro Carvalho Chehab 	}
34809a0bf528SMauro Carvalho Chehab 
34819a0bf528SMauro Carvalho Chehab 	switch (val & 0x3) {
34829a0bf528SMauro Carvalho Chehab 	case 0:
34837e3e68bcSMauro Carvalho Chehab 		c->guard_interval = GUARD_INTERVAL_1_32;
34848af16adfSMauro Carvalho Chehab 		dprintk("dib8000_get_frontend: Guard Interval = 1/32\n");
34859a0bf528SMauro Carvalho Chehab 		break;
34869a0bf528SMauro Carvalho Chehab 	case 1:
34877e3e68bcSMauro Carvalho Chehab 		c->guard_interval = GUARD_INTERVAL_1_16;
34888af16adfSMauro Carvalho Chehab 		dprintk("dib8000_get_frontend: Guard Interval = 1/16\n");
34899a0bf528SMauro Carvalho Chehab 		break;
34909a0bf528SMauro Carvalho Chehab 	case 2:
34918af16adfSMauro Carvalho Chehab 		dprintk("dib8000_get_frontend: Guard Interval = 1/8\n");
34927e3e68bcSMauro Carvalho Chehab 		c->guard_interval = GUARD_INTERVAL_1_8;
34939a0bf528SMauro Carvalho Chehab 		break;
34949a0bf528SMauro Carvalho Chehab 	case 3:
34958af16adfSMauro Carvalho Chehab 		dprintk("dib8000_get_frontend: Guard Interval = 1/4\n");
34967e3e68bcSMauro Carvalho Chehab 		c->guard_interval = GUARD_INTERVAL_1_4;
34979a0bf528SMauro Carvalho Chehab 		break;
34989a0bf528SMauro Carvalho Chehab 	}
34999a0bf528SMauro Carvalho Chehab 
35009a0bf528SMauro Carvalho Chehab 	val = dib8000_read_word(state, 505);
35017e3e68bcSMauro Carvalho Chehab 	c->isdbt_partial_reception = val & 1;
35028af16adfSMauro Carvalho Chehab 	dprintk("dib8000_get_frontend: partial_reception = %d\n", c->isdbt_partial_reception);
35039a0bf528SMauro Carvalho Chehab 
35049a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 3; i++) {
3505ecc31d55SMauro Carvalho Chehab 		int show;
3506ecc31d55SMauro Carvalho Chehab 
3507ecc31d55SMauro Carvalho Chehab 		val = dib8000_read_word(state, 493 + i) & 0x0f;
35087e3e68bcSMauro Carvalho Chehab 		c->layer[i].segment_count = val;
3509ecc31d55SMauro Carvalho Chehab 
3510ecc31d55SMauro Carvalho Chehab 		if (val == 0 || val > 13)
3511ecc31d55SMauro Carvalho Chehab 			show = 0;
3512ecc31d55SMauro Carvalho Chehab 		else
3513ecc31d55SMauro Carvalho Chehab 			show = 1;
3514ecc31d55SMauro Carvalho Chehab 
3515ecc31d55SMauro Carvalho Chehab 		if (show)
35168af16adfSMauro Carvalho Chehab 			dprintk("dib8000_get_frontend: Layer %d segments = %d\n",
35177e3e68bcSMauro Carvalho Chehab 				i, c->layer[i].segment_count);
35189a0bf528SMauro Carvalho Chehab 
351951fea113SMauro Carvalho Chehab 		val = dib8000_read_word(state, 499 + i) & 0x3;
352051fea113SMauro Carvalho Chehab 		/* Interleaving can be 0, 1, 2 or 4 */
352151fea113SMauro Carvalho Chehab 		if (val == 3)
352251fea113SMauro Carvalho Chehab 			val = 4;
35237e3e68bcSMauro Carvalho Chehab 		c->layer[i].interleaving = val;
3524ecc31d55SMauro Carvalho Chehab 		if (show)
35258af16adfSMauro Carvalho Chehab 			dprintk("dib8000_get_frontend: Layer %d time_intlv = %d\n",
35267e3e68bcSMauro Carvalho Chehab 				i, c->layer[i].interleaving);
35279a0bf528SMauro Carvalho Chehab 
35289a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 481 + i);
35299a0bf528SMauro Carvalho Chehab 		switch (val & 0x7) {
35309a0bf528SMauro Carvalho Chehab 		case 1:
35317e3e68bcSMauro Carvalho Chehab 			c->layer[i].fec = FEC_1_2;
3532ecc31d55SMauro Carvalho Chehab 			if (show)
35338af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d Code Rate = 1/2\n", i);
35349a0bf528SMauro Carvalho Chehab 			break;
35359a0bf528SMauro Carvalho Chehab 		case 2:
35367e3e68bcSMauro Carvalho Chehab 			c->layer[i].fec = FEC_2_3;
3537ecc31d55SMauro Carvalho Chehab 			if (show)
35388af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d Code Rate = 2/3\n", i);
35399a0bf528SMauro Carvalho Chehab 			break;
35409a0bf528SMauro Carvalho Chehab 		case 3:
35417e3e68bcSMauro Carvalho Chehab 			c->layer[i].fec = FEC_3_4;
3542ecc31d55SMauro Carvalho Chehab 			if (show)
35438af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d Code Rate = 3/4\n", i);
35449a0bf528SMauro Carvalho Chehab 			break;
35459a0bf528SMauro Carvalho Chehab 		case 5:
35467e3e68bcSMauro Carvalho Chehab 			c->layer[i].fec = FEC_5_6;
3547ecc31d55SMauro Carvalho Chehab 			if (show)
35488af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d Code Rate = 5/6\n", i);
35499a0bf528SMauro Carvalho Chehab 			break;
35509a0bf528SMauro Carvalho Chehab 		default:
35517e3e68bcSMauro Carvalho Chehab 			c->layer[i].fec = FEC_7_8;
3552ecc31d55SMauro Carvalho Chehab 			if (show)
35538af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d Code Rate = 7/8\n", i);
35549a0bf528SMauro Carvalho Chehab 			break;
35559a0bf528SMauro Carvalho Chehab 		}
35569a0bf528SMauro Carvalho Chehab 
35579a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 487 + i);
35589a0bf528SMauro Carvalho Chehab 		switch (val & 0x3) {
35599a0bf528SMauro Carvalho Chehab 		case 0:
35607e3e68bcSMauro Carvalho Chehab 			c->layer[i].modulation = DQPSK;
3561ecc31d55SMauro Carvalho Chehab 			if (show)
35628af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d DQPSK\n", i);
35639a0bf528SMauro Carvalho Chehab 			break;
35649a0bf528SMauro Carvalho Chehab 		case 1:
35657e3e68bcSMauro Carvalho Chehab 			c->layer[i].modulation = QPSK;
3566ecc31d55SMauro Carvalho Chehab 			if (show)
35678af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d QPSK\n", i);
35689a0bf528SMauro Carvalho Chehab 			break;
35699a0bf528SMauro Carvalho Chehab 		case 2:
35707e3e68bcSMauro Carvalho Chehab 			c->layer[i].modulation = QAM_16;
3571ecc31d55SMauro Carvalho Chehab 			if (show)
35728af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d QAM16\n", i);
35739a0bf528SMauro Carvalho Chehab 			break;
35749a0bf528SMauro Carvalho Chehab 		case 3:
35759a0bf528SMauro Carvalho Chehab 		default:
35767e3e68bcSMauro Carvalho Chehab 			c->layer[i].modulation = QAM_64;
3577ecc31d55SMauro Carvalho Chehab 			if (show)
35788af16adfSMauro Carvalho Chehab 				dprintk("dib8000_get_frontend: Layer %d QAM64\n", i);
35799a0bf528SMauro Carvalho Chehab 			break;
35809a0bf528SMauro Carvalho Chehab 		}
35819a0bf528SMauro Carvalho Chehab 	}
35829a0bf528SMauro Carvalho Chehab 
35839a0bf528SMauro Carvalho Chehab 	/* synchronize the cache with the other frontends */
35849a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
35857e3e68bcSMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = c->isdbt_sb_mode;
35867e3e68bcSMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.inversion = c->inversion;
35877e3e68bcSMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.transmission_mode = c->transmission_mode;
35887e3e68bcSMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.guard_interval = c->guard_interval;
35897e3e68bcSMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = c->isdbt_partial_reception;
35909a0bf528SMauro Carvalho Chehab 		for (i = 0; i < 3; i++) {
35917e3e68bcSMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = c->layer[i].segment_count;
35927e3e68bcSMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = c->layer[i].interleaving;
35937e3e68bcSMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].fec = c->layer[i].fec;
35947e3e68bcSMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = c->layer[i].modulation;
35959a0bf528SMauro Carvalho Chehab 		}
35969a0bf528SMauro Carvalho Chehab 	}
35979a0bf528SMauro Carvalho Chehab 	return 0;
35989a0bf528SMauro Carvalho Chehab }
35999a0bf528SMauro Carvalho Chehab 
dib8000_set_frontend(struct dvb_frontend * fe)36009a0bf528SMauro Carvalho Chehab static int dib8000_set_frontend(struct dvb_frontend *fe)
36019a0bf528SMauro Carvalho Chehab {
36029a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
3603c82056d0SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3604d6c62b76SMauro Carvalho Chehab 	int l, i, active, time, time_slave = 0;
3605173a64cbSPatrick Boettcher 	u8 exit_condition, index_frontend;
3606d6c62b76SMauro Carvalho Chehab 	unsigned long delay, callback_time;
36079a0bf528SMauro Carvalho Chehab 
3608c82056d0SMauro Carvalho Chehab 	if (c->frequency == 0) {
36098af16adfSMauro Carvalho Chehab 		dprintk("dib8000: must at least specify frequency\n");
36109a0bf528SMauro Carvalho Chehab 		return 0;
36119a0bf528SMauro Carvalho Chehab 	}
36129a0bf528SMauro Carvalho Chehab 
3613c82056d0SMauro Carvalho Chehab 	if (c->bandwidth_hz == 0) {
36148af16adfSMauro Carvalho Chehab 		dprintk("dib8000: no bandwidth specified, set to default\n");
3615c82056d0SMauro Carvalho Chehab 		c->bandwidth_hz = 6000000;
36169a0bf528SMauro Carvalho Chehab 	}
36179a0bf528SMauro Carvalho Chehab 
36189a0bf528SMauro Carvalho Chehab 	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
36199a0bf528SMauro Carvalho Chehab 		/* synchronization of the cache */
36209a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
36219a0bf528SMauro Carvalho Chehab 		memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
36229a0bf528SMauro Carvalho Chehab 
3623173a64cbSPatrick Boettcher 		/* set output mode and diversity input */
3624173a64cbSPatrick Boettcher 		if (state->revision != 0x8090) {
3625173a64cbSPatrick Boettcher 			dib8000_set_diversity_in(state->fe[index_frontend], 1);
3626173a64cbSPatrick Boettcher 			if (index_frontend != 0)
36279a0bf528SMauro Carvalho Chehab 				dib8000_set_output_mode(state->fe[index_frontend],
3628173a64cbSPatrick Boettcher 						OUTMODE_DIVERSITY);
36299a0bf528SMauro Carvalho Chehab 			else
3630173a64cbSPatrick Boettcher 				dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3631173a64cbSPatrick Boettcher 		} else {
3632173a64cbSPatrick Boettcher 			dib8096p_set_diversity_in(state->fe[index_frontend], 1);
3633173a64cbSPatrick Boettcher 			if (index_frontend != 0)
36349a0bf528SMauro Carvalho Chehab 				dib8096p_set_output_mode(state->fe[index_frontend],
3635173a64cbSPatrick Boettcher 						OUTMODE_DIVERSITY);
3636173a64cbSPatrick Boettcher 			else
3637173a64cbSPatrick Boettcher 				dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3638173a64cbSPatrick Boettcher 		}
3639173a64cbSPatrick Boettcher 
3640173a64cbSPatrick Boettcher 		/* tune the tuner */
36419a0bf528SMauro Carvalho Chehab 		if (state->fe[index_frontend]->ops.tuner_ops.set_params)
36429a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
36439a0bf528SMauro Carvalho Chehab 
36449a0bf528SMauro Carvalho Chehab 		dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
36459a0bf528SMauro Carvalho Chehab 	}
36469a0bf528SMauro Carvalho Chehab 
3647173a64cbSPatrick Boettcher 	/* turn off the diversity of the last chip */
3648173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
3649173a64cbSPatrick Boettcher 		dib8000_set_diversity_in(state->fe[index_frontend - 1], 0);
3650173a64cbSPatrick Boettcher 	else
3651173a64cbSPatrick Boettcher 		dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0);
3652173a64cbSPatrick Boettcher 
36539a0bf528SMauro Carvalho Chehab 	/* start up the AGC */
36549a0bf528SMauro Carvalho Chehab 	do {
36559a0bf528SMauro Carvalho Chehab 		time = dib8000_agc_startup(state->fe[0]);
36569a0bf528SMauro Carvalho Chehab 		for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
36579a0bf528SMauro Carvalho Chehab 			time_slave = dib8000_agc_startup(state->fe[index_frontend]);
3658d6c62b76SMauro Carvalho Chehab 			if (time == 0)
36599a0bf528SMauro Carvalho Chehab 				time = time_slave;
3660d6c62b76SMauro Carvalho Chehab 			else if ((time_slave != 0) && (time_slave > time))
36619a0bf528SMauro Carvalho Chehab 				time = time_slave;
36629a0bf528SMauro Carvalho Chehab 		}
3663d6c62b76SMauro Carvalho Chehab 		if (time == 0)
36649a0bf528SMauro Carvalho Chehab 			break;
36654607bb7aSMauro Carvalho Chehab 
36664607bb7aSMauro Carvalho Chehab 		/*
36674607bb7aSMauro Carvalho Chehab 		 * Despite dib8000_agc_startup returns time at a 0.1 ms range,
36684607bb7aSMauro Carvalho Chehab 		 * the actual sleep time depends on CONFIG_HZ. The worse case
36694607bb7aSMauro Carvalho Chehab 		 * is when CONFIG_HZ=100. In such case, the minimum granularity
36704607bb7aSMauro Carvalho Chehab 		 * is 10ms. On some real field tests, the tuner sometimes don't
36714607bb7aSMauro Carvalho Chehab 		 * lock when this timer is lower than 10ms. So, enforce a 10ms
36724607bb7aSMauro Carvalho Chehab 		 * granularity.
36734607bb7aSMauro Carvalho Chehab 		 */
36744607bb7aSMauro Carvalho Chehab 		time = 10 * (time + 99)/100;
36754607bb7aSMauro Carvalho Chehab 		usleep_range(time * 1000, (time + 1) * 1000);
36769a0bf528SMauro Carvalho Chehab 		exit_condition = 1;
36779a0bf528SMauro Carvalho Chehab 		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
36789a0bf528SMauro Carvalho Chehab 			if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
36799a0bf528SMauro Carvalho Chehab 				exit_condition = 0;
36809a0bf528SMauro Carvalho Chehab 				break;
36819a0bf528SMauro Carvalho Chehab 			}
36829a0bf528SMauro Carvalho Chehab 		}
36839a0bf528SMauro Carvalho Chehab 	} while (exit_condition == 0);
36849a0bf528SMauro Carvalho Chehab 
36859a0bf528SMauro Carvalho Chehab 	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
36869a0bf528SMauro Carvalho Chehab 		dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
36879a0bf528SMauro Carvalho Chehab 
3688173a64cbSPatrick Boettcher 	active = 1;
36899a0bf528SMauro Carvalho Chehab 	do {
3690d6c62b76SMauro Carvalho Chehab 		callback_time = 0;
36919a0bf528SMauro Carvalho Chehab 		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3692173a64cbSPatrick Boettcher 			delay = dib8000_tune(state->fe[index_frontend]);
3693d6c62b76SMauro Carvalho Chehab 			if (delay != 0) {
3694d6c62b76SMauro Carvalho Chehab 				delay = jiffies + usecs_to_jiffies(100 * delay);
3695d6c62b76SMauro Carvalho Chehab 				if (!callback_time || delay < callback_time)
3696d6c62b76SMauro Carvalho Chehab 					callback_time = delay;
3697d6c62b76SMauro Carvalho Chehab 			}
3698173a64cbSPatrick Boettcher 
3699173a64cbSPatrick Boettcher 			/* we are in autosearch */
3700173a64cbSPatrick Boettcher 			if (state->channel_parameters_set == 0) { /* searching */
3701173a64cbSPatrick Boettcher 				if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) {
37028af16adfSMauro Carvalho Chehab 					dprintk("autosearch succeeded on fe%i\n", index_frontend);
37037e3e68bcSMauro Carvalho Chehab 					dib8000_get_frontend(state->fe[index_frontend], c); /* we read the channel parameters from the frontend which was successful */
3704173a64cbSPatrick Boettcher 					state->channel_parameters_set = 1;
3705173a64cbSPatrick Boettcher 
3706173a64cbSPatrick Boettcher 					for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
3707173a64cbSPatrick Boettcher 						if (l != index_frontend) { /* and for all frontend except the successful one */
3708ecc31d55SMauro Carvalho Chehab 							dprintk("Restarting frontend %d\n", l);
3709173a64cbSPatrick Boettcher 							dib8000_tune_restart_from_demod(state->fe[l]);
3710173a64cbSPatrick Boettcher 
3711173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3712173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3713173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3714173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3715173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3716173a64cbSPatrick Boettcher 							for (i = 0; i < 3; i++) {
3717173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3718173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3719173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3720173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3721173a64cbSPatrick Boettcher 							}
3722173a64cbSPatrick Boettcher 
37239a0bf528SMauro Carvalho Chehab 						}
37249a0bf528SMauro Carvalho Chehab 					}
37259a0bf528SMauro Carvalho Chehab 				}
3726173a64cbSPatrick Boettcher 			}
3727173a64cbSPatrick Boettcher 		}
3728173a64cbSPatrick Boettcher 		/* tuning is done when the master frontend is done (failed or success) */
3729173a64cbSPatrick Boettcher 		if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
3730173a64cbSPatrick Boettcher 				dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED ||
3731173a64cbSPatrick Boettcher 				dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) {
3732173a64cbSPatrick Boettcher 			active = 0;
3733173a64cbSPatrick Boettcher 			/* we need to wait for all frontends to be finished */
3734173a64cbSPatrick Boettcher 			for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3735173a64cbSPatrick Boettcher 				if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP)
3736173a64cbSPatrick Boettcher 					active = 1;
3737173a64cbSPatrick Boettcher 			}
3738173a64cbSPatrick Boettcher 			if (active == 0)
37398af16adfSMauro Carvalho Chehab 				dprintk("tuning done with status %d\n", dib8000_get_status(state->fe[0]));
37409a0bf528SMauro Carvalho Chehab 		}
37419a0bf528SMauro Carvalho Chehab 
3742d6c62b76SMauro Carvalho Chehab 		if ((active == 1) && (callback_time == 0)) {
37438af16adfSMauro Carvalho Chehab 			dprintk("strange callback time something went wrong\n");
3744173a64cbSPatrick Boettcher 			active = 0;
37459a0bf528SMauro Carvalho Chehab 		}
37469a0bf528SMauro Carvalho Chehab 
3747d6c62b76SMauro Carvalho Chehab 		while ((active == 1) && (time_before(jiffies, callback_time)))
3748173a64cbSPatrick Boettcher 			msleep(100);
3749173a64cbSPatrick Boettcher 	} while (active);
37509a0bf528SMauro Carvalho Chehab 
3751173a64cbSPatrick Boettcher 	/* set output mode */
3752173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
37539a0bf528SMauro Carvalho Chehab 		dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
3754173a64cbSPatrick Boettcher 	else {
37559a0bf528SMauro Carvalho Chehab 		dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
37569a0bf528SMauro Carvalho Chehab 		if (state->cfg.enMpegOutput == 0) {
37579a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
37589a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
37599a0bf528SMauro Carvalho Chehab 		}
37609a0bf528SMauro Carvalho Chehab 	}
37619a0bf528SMauro Carvalho Chehab 
37624d8d5d92SGeert Uytterhoeven 	return 0;
37639a0bf528SMauro Carvalho Chehab }
37649a0bf528SMauro Carvalho Chehab 
37650df289a2SMauro Carvalho Chehab static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat);
37666ef06e78SMauro Carvalho Chehab 
dib8000_read_status(struct dvb_frontend * fe,enum fe_status * stat)37670df289a2SMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat)
37689a0bf528SMauro Carvalho Chehab {
37699a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37709a0bf528SMauro Carvalho Chehab 	u16 lock_slave = 0, lock;
37719a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
37729a0bf528SMauro Carvalho Chehab 
3773173a64cbSPatrick Boettcher 	lock = dib8000_read_lock(fe);
37749a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
37759a0bf528SMauro Carvalho Chehab 		lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
37769a0bf528SMauro Carvalho Chehab 
37779a0bf528SMauro Carvalho Chehab 	*stat = 0;
37789a0bf528SMauro Carvalho Chehab 
37799a0bf528SMauro Carvalho Chehab 	if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
37809a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SIGNAL;
37819a0bf528SMauro Carvalho Chehab 
37829a0bf528SMauro Carvalho Chehab 	if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
37839a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_CARRIER;
37849a0bf528SMauro Carvalho Chehab 
37859a0bf528SMauro Carvalho Chehab 	if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
37869a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SYNC;
37879a0bf528SMauro Carvalho Chehab 
37889a0bf528SMauro Carvalho Chehab 	if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
37899a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_LOCK;
37909a0bf528SMauro Carvalho Chehab 
37919a0bf528SMauro Carvalho Chehab 	if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
37929a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
37939a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
37949a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
37959a0bf528SMauro Carvalho Chehab 
37969a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
37979a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
37989a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
37999a0bf528SMauro Carvalho Chehab 
38009a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
38019a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
38029a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
38039a0bf528SMauro Carvalho Chehab 	}
38046ef06e78SMauro Carvalho Chehab 	dib8000_get_stats(fe, *stat);
38059a0bf528SMauro Carvalho Chehab 
38069a0bf528SMauro Carvalho Chehab 	return 0;
38079a0bf528SMauro Carvalho Chehab }
38089a0bf528SMauro Carvalho Chehab 
dib8000_read_ber(struct dvb_frontend * fe,u32 * ber)38099a0bf528SMauro Carvalho Chehab static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
38109a0bf528SMauro Carvalho Chehab {
38119a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
38129a0bf528SMauro Carvalho Chehab 
38139a0bf528SMauro Carvalho Chehab 	/* 13 segments */
38149a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
38159a0bf528SMauro Carvalho Chehab 		*ber = (dib8000_read_word(state, 562) << 16) |
38169a0bf528SMauro Carvalho Chehab 			dib8000_read_word(state, 563);
38179a0bf528SMauro Carvalho Chehab 	else
38189a0bf528SMauro Carvalho Chehab 		*ber = (dib8000_read_word(state, 560) << 16) |
38199a0bf528SMauro Carvalho Chehab 			dib8000_read_word(state, 561);
38209a0bf528SMauro Carvalho Chehab 	return 0;
38219a0bf528SMauro Carvalho Chehab }
38229a0bf528SMauro Carvalho Chehab 
dib8000_read_unc_blocks(struct dvb_frontend * fe,u32 * unc)38239a0bf528SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
38249a0bf528SMauro Carvalho Chehab {
38259a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
38269a0bf528SMauro Carvalho Chehab 
38279a0bf528SMauro Carvalho Chehab 	/* packet error on 13 seg */
38289a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
38299a0bf528SMauro Carvalho Chehab 		*unc = dib8000_read_word(state, 567);
38309a0bf528SMauro Carvalho Chehab 	else
38319a0bf528SMauro Carvalho Chehab 		*unc = dib8000_read_word(state, 565);
38329a0bf528SMauro Carvalho Chehab 	return 0;
38339a0bf528SMauro Carvalho Chehab }
38349a0bf528SMauro Carvalho Chehab 
dib8000_read_signal_strength(struct dvb_frontend * fe,u16 * strength)38359a0bf528SMauro Carvalho Chehab static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
38369a0bf528SMauro Carvalho Chehab {
38379a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
38389a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
38399a0bf528SMauro Carvalho Chehab 	u16 val;
38409a0bf528SMauro Carvalho Chehab 
38419a0bf528SMauro Carvalho Chehab 	*strength = 0;
38429a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
38439a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
38449a0bf528SMauro Carvalho Chehab 		if (val > 65535 - *strength)
38459a0bf528SMauro Carvalho Chehab 			*strength = 65535;
38469a0bf528SMauro Carvalho Chehab 		else
38479a0bf528SMauro Carvalho Chehab 			*strength += val;
38489a0bf528SMauro Carvalho Chehab 	}
38499a0bf528SMauro Carvalho Chehab 
38509a0bf528SMauro Carvalho Chehab 	val = 65535 - dib8000_read_word(state, 390);
38519a0bf528SMauro Carvalho Chehab 	if (val > 65535 - *strength)
38529a0bf528SMauro Carvalho Chehab 		*strength = 65535;
38539a0bf528SMauro Carvalho Chehab 	else
38549a0bf528SMauro Carvalho Chehab 		*strength += val;
38559a0bf528SMauro Carvalho Chehab 	return 0;
38569a0bf528SMauro Carvalho Chehab }
38579a0bf528SMauro Carvalho Chehab 
dib8000_get_snr(struct dvb_frontend * fe)38589a0bf528SMauro Carvalho Chehab static u32 dib8000_get_snr(struct dvb_frontend *fe)
38599a0bf528SMauro Carvalho Chehab {
38609a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
38619a0bf528SMauro Carvalho Chehab 	u32 n, s, exp;
38629a0bf528SMauro Carvalho Chehab 	u16 val;
38639a0bf528SMauro Carvalho Chehab 
38649a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
38659a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 542);
38669a0bf528SMauro Carvalho Chehab 	else
38679a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 544);
38689a0bf528SMauro Carvalho Chehab 	n = (val >> 6) & 0xff;
38699a0bf528SMauro Carvalho Chehab 	exp = (val & 0x3f);
38709a0bf528SMauro Carvalho Chehab 	if ((exp & 0x20) != 0)
38719a0bf528SMauro Carvalho Chehab 		exp -= 0x40;
38729a0bf528SMauro Carvalho Chehab 	n <<= exp+16;
38739a0bf528SMauro Carvalho Chehab 
38749a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
38759a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 543);
38769a0bf528SMauro Carvalho Chehab 	else
38779a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 545);
38789a0bf528SMauro Carvalho Chehab 	s = (val >> 6) & 0xff;
38799a0bf528SMauro Carvalho Chehab 	exp = (val & 0x3f);
38809a0bf528SMauro Carvalho Chehab 	if ((exp & 0x20) != 0)
38819a0bf528SMauro Carvalho Chehab 		exp -= 0x40;
38829a0bf528SMauro Carvalho Chehab 	s <<= exp+16;
38839a0bf528SMauro Carvalho Chehab 
38849a0bf528SMauro Carvalho Chehab 	if (n > 0) {
38859a0bf528SMauro Carvalho Chehab 		u32 t = (s/n) << 16;
38869a0bf528SMauro Carvalho Chehab 		return t + ((s << 16) - n*t) / n;
38879a0bf528SMauro Carvalho Chehab 	}
38889a0bf528SMauro Carvalho Chehab 	return 0xffffffff;
38899a0bf528SMauro Carvalho Chehab }
38909a0bf528SMauro Carvalho Chehab 
dib8000_read_snr(struct dvb_frontend * fe,u16 * snr)38919a0bf528SMauro Carvalho Chehab static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
38929a0bf528SMauro Carvalho Chehab {
38939a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
38949a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
38959a0bf528SMauro Carvalho Chehab 	u32 snr_master;
38969a0bf528SMauro Carvalho Chehab 
38979a0bf528SMauro Carvalho Chehab 	snr_master = dib8000_get_snr(fe);
38989a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
38999a0bf528SMauro Carvalho Chehab 		snr_master += dib8000_get_snr(state->fe[index_frontend]);
39009a0bf528SMauro Carvalho Chehab 
39019a0bf528SMauro Carvalho Chehab 	if ((snr_master >> 16) != 0) {
39029a0bf528SMauro Carvalho Chehab 		snr_master = 10*intlog10(snr_master>>16);
39039a0bf528SMauro Carvalho Chehab 		*snr = snr_master / ((1 << 24) / 10);
39049a0bf528SMauro Carvalho Chehab 	}
39059a0bf528SMauro Carvalho Chehab 	else
39069a0bf528SMauro Carvalho Chehab 		*snr = 0;
39079a0bf528SMauro Carvalho Chehab 
39089a0bf528SMauro Carvalho Chehab 	return 0;
39099a0bf528SMauro Carvalho Chehab }
39109a0bf528SMauro Carvalho Chehab 
39116ef06e78SMauro Carvalho Chehab struct per_layer_regs {
39126ef06e78SMauro Carvalho Chehab 	u16 lock, ber, per;
39136ef06e78SMauro Carvalho Chehab };
39146ef06e78SMauro Carvalho Chehab 
39156ef06e78SMauro Carvalho Chehab static const struct per_layer_regs per_layer_regs[] = {
39166ef06e78SMauro Carvalho Chehab 	{ 554, 560, 562 },
39176ef06e78SMauro Carvalho Chehab 	{ 555, 576, 578 },
39186ef06e78SMauro Carvalho Chehab 	{ 556, 581, 583 },
39196ef06e78SMauro Carvalho Chehab };
39206ef06e78SMauro Carvalho Chehab 
392142ff76bdSMauro Carvalho Chehab struct linear_segments {
392242ff76bdSMauro Carvalho Chehab 	unsigned x;
392342ff76bdSMauro Carvalho Chehab 	signed y;
392442ff76bdSMauro Carvalho Chehab };
392542ff76bdSMauro Carvalho Chehab 
392642ff76bdSMauro Carvalho Chehab /*
392742ff76bdSMauro Carvalho Chehab  * Table to estimate signal strength in dBm.
392842ff76bdSMauro Carvalho Chehab  * This table was empirically determinated by measuring the signal
392942ff76bdSMauro Carvalho Chehab  * strength generated by a DTA-2111 RF generator directly connected into
393042ff76bdSMauro Carvalho Chehab  * a dib8076 device (a PixelView PV-D231U stick), using a good quality
393142ff76bdSMauro Carvalho Chehab  * 3 meters RC6 cable and good RC6 connectors.
393242ff76bdSMauro Carvalho Chehab  * The real value can actually be different on other devices, depending
393342ff76bdSMauro Carvalho Chehab  * on several factors, like if LNA is enabled or not, if diversity is
393442ff76bdSMauro Carvalho Chehab  * enabled, type of connectors, etc.
393542ff76bdSMauro Carvalho Chehab  * Yet, it is better to use this measure in dB than a random non-linear
393642ff76bdSMauro Carvalho Chehab  * percentage value, especially for antenna adjustments.
393742ff76bdSMauro Carvalho Chehab  * On my tests, the precision of the measure using this table is about
393842ff76bdSMauro Carvalho Chehab  * 0.5 dB, with sounds reasonable enough.
393942ff76bdSMauro Carvalho Chehab  */
394042ff76bdSMauro Carvalho Chehab static struct linear_segments strength_to_db_table[] = {
394142ff76bdSMauro Carvalho Chehab 	{ 55953, 108500 },	/* -22.5 dBm */
394242ff76bdSMauro Carvalho Chehab 	{ 55394, 108000 },
394342ff76bdSMauro Carvalho Chehab 	{ 53834, 107000 },
394442ff76bdSMauro Carvalho Chehab 	{ 52863, 106000 },
394542ff76bdSMauro Carvalho Chehab 	{ 52239, 105000 },
394642ff76bdSMauro Carvalho Chehab 	{ 52012, 104000 },
394742ff76bdSMauro Carvalho Chehab 	{ 51803, 103000 },
394842ff76bdSMauro Carvalho Chehab 	{ 51566, 102000 },
394942ff76bdSMauro Carvalho Chehab 	{ 51356, 101000 },
395042ff76bdSMauro Carvalho Chehab 	{ 51112, 100000 },
395142ff76bdSMauro Carvalho Chehab 	{ 50869,  99000 },
395242ff76bdSMauro Carvalho Chehab 	{ 50600,  98000 },
395342ff76bdSMauro Carvalho Chehab 	{ 50363,  97000 },
395442ff76bdSMauro Carvalho Chehab 	{ 50117,  96000 },	/* -35 dBm */
395542ff76bdSMauro Carvalho Chehab 	{ 49889,  95000 },
395642ff76bdSMauro Carvalho Chehab 	{ 49680,  94000 },
395742ff76bdSMauro Carvalho Chehab 	{ 49493,  93000 },
395842ff76bdSMauro Carvalho Chehab 	{ 49302,  92000 },
395942ff76bdSMauro Carvalho Chehab 	{ 48929,  91000 },
396042ff76bdSMauro Carvalho Chehab 	{ 48416,  90000 },
396142ff76bdSMauro Carvalho Chehab 	{ 48035,  89000 },
396242ff76bdSMauro Carvalho Chehab 	{ 47593,  88000 },
396342ff76bdSMauro Carvalho Chehab 	{ 47282,  87000 },
396442ff76bdSMauro Carvalho Chehab 	{ 46953,  86000 },
396542ff76bdSMauro Carvalho Chehab 	{ 46698,  85000 },
396642ff76bdSMauro Carvalho Chehab 	{ 45617,  84000 },
396742ff76bdSMauro Carvalho Chehab 	{ 44773,  83000 },
396842ff76bdSMauro Carvalho Chehab 	{ 43845,  82000 },
396942ff76bdSMauro Carvalho Chehab 	{ 43020,  81000 },
397042ff76bdSMauro Carvalho Chehab 	{ 42010,  80000 },	/* -51 dBm */
397142ff76bdSMauro Carvalho Chehab 	{     0,      0 },
397242ff76bdSMauro Carvalho Chehab };
397342ff76bdSMauro Carvalho Chehab 
interpolate_value(u32 value,struct linear_segments * segments,unsigned len)397442ff76bdSMauro Carvalho Chehab static u32 interpolate_value(u32 value, struct linear_segments *segments,
397542ff76bdSMauro Carvalho Chehab 			     unsigned len)
397642ff76bdSMauro Carvalho Chehab {
397742ff76bdSMauro Carvalho Chehab 	u64 tmp64;
397842ff76bdSMauro Carvalho Chehab 	u32 dx;
397942ff76bdSMauro Carvalho Chehab 	s32 dy;
398042ff76bdSMauro Carvalho Chehab 	int i, ret;
398142ff76bdSMauro Carvalho Chehab 
398242ff76bdSMauro Carvalho Chehab 	if (value >= segments[0].x)
398342ff76bdSMauro Carvalho Chehab 		return segments[0].y;
398442ff76bdSMauro Carvalho Chehab 	if (value < segments[len-1].x)
398542ff76bdSMauro Carvalho Chehab 		return segments[len-1].y;
398642ff76bdSMauro Carvalho Chehab 
398742ff76bdSMauro Carvalho Chehab 	for (i = 1; i < len - 1; i++) {
398842ff76bdSMauro Carvalho Chehab 		/* If value is identical, no need to interpolate */
398942ff76bdSMauro Carvalho Chehab 		if (value == segments[i].x)
399042ff76bdSMauro Carvalho Chehab 			return segments[i].y;
399142ff76bdSMauro Carvalho Chehab 		if (value > segments[i].x)
399242ff76bdSMauro Carvalho Chehab 			break;
399342ff76bdSMauro Carvalho Chehab 	}
399442ff76bdSMauro Carvalho Chehab 
399542ff76bdSMauro Carvalho Chehab 	/* Linear interpolation between the two (x,y) points */
399642ff76bdSMauro Carvalho Chehab 	dy = segments[i - 1].y - segments[i].y;
399742ff76bdSMauro Carvalho Chehab 	dx = segments[i - 1].x - segments[i].x;
399842ff76bdSMauro Carvalho Chehab 
399942ff76bdSMauro Carvalho Chehab 	tmp64 = value - segments[i].x;
400042ff76bdSMauro Carvalho Chehab 	tmp64 *= dy;
400142ff76bdSMauro Carvalho Chehab 	do_div(tmp64, dx);
400242ff76bdSMauro Carvalho Chehab 	ret = segments[i].y + tmp64;
400342ff76bdSMauro Carvalho Chehab 
400442ff76bdSMauro Carvalho Chehab 	return ret;
400542ff76bdSMauro Carvalho Chehab }
400642ff76bdSMauro Carvalho Chehab 
dib8000_get_time_us(struct dvb_frontend * fe,int layer)4007704f01bbSMauro Carvalho Chehab static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer)
4008704f01bbSMauro Carvalho Chehab {
4009704f01bbSMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
4010704f01bbSMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
4011704f01bbSMauro Carvalho Chehab 	int ini_layer, end_layer, i;
40124bf48150SMauro Carvalho Chehab 	u64 time_us, tmp64;
4013704f01bbSMauro Carvalho Chehab 	u32 tmp, denom;
4014e4a3bc1cSMauro Carvalho Chehab 	int guard, rate_num, rate_denum = 1, bits_per_symbol, nsegs;
4015e4a3bc1cSMauro Carvalho Chehab 	int interleaving = 0, fft_div;
4016704f01bbSMauro Carvalho Chehab 
4017704f01bbSMauro Carvalho Chehab 	if (layer >= 0) {
4018704f01bbSMauro Carvalho Chehab 		ini_layer = layer;
4019704f01bbSMauro Carvalho Chehab 		end_layer = layer + 1;
4020704f01bbSMauro Carvalho Chehab 	} else {
4021704f01bbSMauro Carvalho Chehab 		ini_layer = 0;
4022704f01bbSMauro Carvalho Chehab 		end_layer = 3;
4023704f01bbSMauro Carvalho Chehab 	}
4024704f01bbSMauro Carvalho Chehab 
4025704f01bbSMauro Carvalho Chehab 	switch (c->guard_interval) {
4026704f01bbSMauro Carvalho Chehab 	case GUARD_INTERVAL_1_4:
4027704f01bbSMauro Carvalho Chehab 		guard = 4;
4028704f01bbSMauro Carvalho Chehab 		break;
4029704f01bbSMauro Carvalho Chehab 	case GUARD_INTERVAL_1_8:
4030704f01bbSMauro Carvalho Chehab 		guard = 8;
4031704f01bbSMauro Carvalho Chehab 		break;
4032704f01bbSMauro Carvalho Chehab 	case GUARD_INTERVAL_1_16:
4033704f01bbSMauro Carvalho Chehab 		guard = 16;
4034704f01bbSMauro Carvalho Chehab 		break;
4035704f01bbSMauro Carvalho Chehab 	default:
4036704f01bbSMauro Carvalho Chehab 	case GUARD_INTERVAL_1_32:
4037704f01bbSMauro Carvalho Chehab 		guard = 32;
4038704f01bbSMauro Carvalho Chehab 		break;
4039704f01bbSMauro Carvalho Chehab 	}
4040704f01bbSMauro Carvalho Chehab 
4041704f01bbSMauro Carvalho Chehab 	switch (c->transmission_mode) {
4042704f01bbSMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
4043704f01bbSMauro Carvalho Chehab 		fft_div = 4;
4044704f01bbSMauro Carvalho Chehab 		break;
4045704f01bbSMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
4046704f01bbSMauro Carvalho Chehab 		fft_div = 2;
4047704f01bbSMauro Carvalho Chehab 		break;
4048704f01bbSMauro Carvalho Chehab 	default:
4049704f01bbSMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
4050704f01bbSMauro Carvalho Chehab 		fft_div = 1;
4051704f01bbSMauro Carvalho Chehab 		break;
4052704f01bbSMauro Carvalho Chehab 	}
4053704f01bbSMauro Carvalho Chehab 
4054704f01bbSMauro Carvalho Chehab 	denom = 0;
4055704f01bbSMauro Carvalho Chehab 	for (i = ini_layer; i < end_layer; i++) {
4056704f01bbSMauro Carvalho Chehab 		nsegs = c->layer[i].segment_count;
4057704f01bbSMauro Carvalho Chehab 		if (nsegs == 0 || nsegs > 13)
4058704f01bbSMauro Carvalho Chehab 			continue;
4059704f01bbSMauro Carvalho Chehab 
4060704f01bbSMauro Carvalho Chehab 		switch (c->layer[i].modulation) {
4061704f01bbSMauro Carvalho Chehab 		case DQPSK:
4062704f01bbSMauro Carvalho Chehab 		case QPSK:
4063704f01bbSMauro Carvalho Chehab 			bits_per_symbol = 2;
4064704f01bbSMauro Carvalho Chehab 			break;
4065704f01bbSMauro Carvalho Chehab 		case QAM_16:
4066704f01bbSMauro Carvalho Chehab 			bits_per_symbol = 4;
4067704f01bbSMauro Carvalho Chehab 			break;
4068704f01bbSMauro Carvalho Chehab 		default:
4069704f01bbSMauro Carvalho Chehab 		case QAM_64:
4070704f01bbSMauro Carvalho Chehab 			bits_per_symbol = 6;
4071704f01bbSMauro Carvalho Chehab 			break;
4072704f01bbSMauro Carvalho Chehab 		}
4073704f01bbSMauro Carvalho Chehab 
4074704f01bbSMauro Carvalho Chehab 		switch (c->layer[i].fec) {
4075704f01bbSMauro Carvalho Chehab 		case FEC_1_2:
4076704f01bbSMauro Carvalho Chehab 			rate_num = 1;
4077704f01bbSMauro Carvalho Chehab 			rate_denum = 2;
4078704f01bbSMauro Carvalho Chehab 			break;
4079704f01bbSMauro Carvalho Chehab 		case FEC_2_3:
4080704f01bbSMauro Carvalho Chehab 			rate_num = 2;
4081704f01bbSMauro Carvalho Chehab 			rate_denum = 3;
4082704f01bbSMauro Carvalho Chehab 			break;
4083704f01bbSMauro Carvalho Chehab 		case FEC_3_4:
4084704f01bbSMauro Carvalho Chehab 			rate_num = 3;
4085704f01bbSMauro Carvalho Chehab 			rate_denum = 4;
4086704f01bbSMauro Carvalho Chehab 			break;
4087704f01bbSMauro Carvalho Chehab 		case FEC_5_6:
4088704f01bbSMauro Carvalho Chehab 			rate_num = 5;
4089704f01bbSMauro Carvalho Chehab 			rate_denum = 6;
4090704f01bbSMauro Carvalho Chehab 			break;
4091704f01bbSMauro Carvalho Chehab 		default:
4092704f01bbSMauro Carvalho Chehab 		case FEC_7_8:
4093704f01bbSMauro Carvalho Chehab 			rate_num = 7;
4094704f01bbSMauro Carvalho Chehab 			rate_denum = 8;
4095704f01bbSMauro Carvalho Chehab 			break;
4096704f01bbSMauro Carvalho Chehab 		}
4097704f01bbSMauro Carvalho Chehab 
4098704f01bbSMauro Carvalho Chehab 		interleaving = c->layer[i].interleaving;
4099704f01bbSMauro Carvalho Chehab 
4100704f01bbSMauro Carvalho Chehab 		denom += bits_per_symbol * rate_num * fft_div * nsegs * 384;
4101704f01bbSMauro Carvalho Chehab 	}
4102704f01bbSMauro Carvalho Chehab 
4103704f01bbSMauro Carvalho Chehab 	/* If all goes wrong, wait for 1s for the next stats */
4104704f01bbSMauro Carvalho Chehab 	if (!denom)
4105704f01bbSMauro Carvalho Chehab 		return 0;
4106704f01bbSMauro Carvalho Chehab 
4107704f01bbSMauro Carvalho Chehab 	/* Estimate the period for the total bit rate */
4108704f01bbSMauro Carvalho Chehab 	time_us = rate_denum * (1008 * 1562500L);
41094bf48150SMauro Carvalho Chehab 	tmp64 = time_us;
41104bf48150SMauro Carvalho Chehab 	do_div(tmp64, guard);
41114bf48150SMauro Carvalho Chehab 	time_us = time_us + tmp64;
4112704f01bbSMauro Carvalho Chehab 	time_us += denom / 2;
4113704f01bbSMauro Carvalho Chehab 	do_div(time_us, denom);
4114704f01bbSMauro Carvalho Chehab 
4115704f01bbSMauro Carvalho Chehab 	tmp = 1008 * 96 * interleaving;
4116704f01bbSMauro Carvalho Chehab 	time_us += tmp + tmp / guard;
4117704f01bbSMauro Carvalho Chehab 
4118704f01bbSMauro Carvalho Chehab 	return time_us;
4119704f01bbSMauro Carvalho Chehab }
4120704f01bbSMauro Carvalho Chehab 
dib8000_get_stats(struct dvb_frontend * fe,enum fe_status stat)41210df289a2SMauro Carvalho Chehab static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat)
41226ef06e78SMauro Carvalho Chehab {
41236ef06e78SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
41246ef06e78SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
4125704f01bbSMauro Carvalho Chehab 	int i;
41260400c535SMauro Carvalho Chehab 	int show_per_stats = 0;
41270400c535SMauro Carvalho Chehab 	u32 time_us = 0, snr, val;
41280400c535SMauro Carvalho Chehab 	u64 blocks;
412942ff76bdSMauro Carvalho Chehab 	s32 db;
41306ef06e78SMauro Carvalho Chehab 	u16 strength;
41316ef06e78SMauro Carvalho Chehab 
41326ef06e78SMauro Carvalho Chehab 	/* Get Signal strength */
41336ef06e78SMauro Carvalho Chehab 	dib8000_read_signal_strength(fe, &strength);
413442ff76bdSMauro Carvalho Chehab 	val = strength;
413542ff76bdSMauro Carvalho Chehab 	db = interpolate_value(val,
413642ff76bdSMauro Carvalho Chehab 			       strength_to_db_table,
413742ff76bdSMauro Carvalho Chehab 			       ARRAY_SIZE(strength_to_db_table)) - 131000;
413842ff76bdSMauro Carvalho Chehab 	c->strength.stat[0].svalue = db;
41396ef06e78SMauro Carvalho Chehab 
4140704f01bbSMauro Carvalho Chehab 	/* UCB/BER/CNR measures require lock */
4141704f01bbSMauro Carvalho Chehab 	if (!(stat & FE_HAS_LOCK)) {
4142704f01bbSMauro Carvalho Chehab 		c->cnr.len = 1;
41430400c535SMauro Carvalho Chehab 		c->block_count.len = 1;
4144704f01bbSMauro Carvalho Chehab 		c->block_error.len = 1;
4145704f01bbSMauro Carvalho Chehab 		c->post_bit_error.len = 1;
4146704f01bbSMauro Carvalho Chehab 		c->post_bit_count.len = 1;
4147704f01bbSMauro Carvalho Chehab 		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4148704f01bbSMauro Carvalho Chehab 		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4149704f01bbSMauro Carvalho Chehab 		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4150704f01bbSMauro Carvalho Chehab 		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
41510400c535SMauro Carvalho Chehab 		c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
41526ef06e78SMauro Carvalho Chehab 		return 0;
4153704f01bbSMauro Carvalho Chehab 	}
4154704f01bbSMauro Carvalho Chehab 
4155704f01bbSMauro Carvalho Chehab 	/* Check if time for stats was elapsed */
41560400c535SMauro Carvalho Chehab 	if (time_after(jiffies, state->per_jiffies_stats)) {
41570400c535SMauro Carvalho Chehab 		state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
41586ef06e78SMauro Carvalho Chehab 
41596ef06e78SMauro Carvalho Chehab 		/* Get SNR */
41606ef06e78SMauro Carvalho Chehab 		snr = dib8000_get_snr(fe);
41616ef06e78SMauro Carvalho Chehab 		for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) {
41626ef06e78SMauro Carvalho Chehab 			if (state->fe[i])
41636ef06e78SMauro Carvalho Chehab 				snr += dib8000_get_snr(state->fe[i]);
41646ef06e78SMauro Carvalho Chehab 		}
41656ef06e78SMauro Carvalho Chehab 		snr = snr >> 16;
41666ef06e78SMauro Carvalho Chehab 
41676ef06e78SMauro Carvalho Chehab 		if (snr) {
41686ef06e78SMauro Carvalho Chehab 			snr = 10 * intlog10(snr);
41696ef06e78SMauro Carvalho Chehab 			snr = (1000L * snr) >> 24;
41706ef06e78SMauro Carvalho Chehab 		} else {
41716ef06e78SMauro Carvalho Chehab 			snr = 0;
41726ef06e78SMauro Carvalho Chehab 		}
41736ef06e78SMauro Carvalho Chehab 		c->cnr.stat[0].svalue = snr;
41746ef06e78SMauro Carvalho Chehab 		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
41756ef06e78SMauro Carvalho Chehab 
41760400c535SMauro Carvalho Chehab 		/* Get UCB measures */
41770400c535SMauro Carvalho Chehab 		dib8000_read_unc_blocks(fe, &val);
41780400c535SMauro Carvalho Chehab 		if (val < state->init_ucb)
41795dc8526bSMauro Carvalho Chehab 			state->init_ucb += 0x100000000LL;
41800400c535SMauro Carvalho Chehab 
41810400c535SMauro Carvalho Chehab 		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
41820400c535SMauro Carvalho Chehab 		c->block_error.stat[0].uvalue = val + state->init_ucb;
41830400c535SMauro Carvalho Chehab 
41840400c535SMauro Carvalho Chehab 		/* Estimate the number of packets based on bitrate */
41850400c535SMauro Carvalho Chehab 		if (!time_us)
41860400c535SMauro Carvalho Chehab 			time_us = dib8000_get_time_us(fe, -1);
41870400c535SMauro Carvalho Chehab 
41880400c535SMauro Carvalho Chehab 		if (time_us) {
41895dc8526bSMauro Carvalho Chehab 			blocks = 1250000ULL * 1000000ULL;
41900400c535SMauro Carvalho Chehab 			do_div(blocks, time_us * 8 * 204);
41910400c535SMauro Carvalho Chehab 			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
41920400c535SMauro Carvalho Chehab 			c->block_count.stat[0].uvalue += blocks;
41930400c535SMauro Carvalho Chehab 		}
41940400c535SMauro Carvalho Chehab 
41950400c535SMauro Carvalho Chehab 		show_per_stats = 1;
41960400c535SMauro Carvalho Chehab 	}
41970400c535SMauro Carvalho Chehab 
41980400c535SMauro Carvalho Chehab 	/* Get post-BER measures */
41990400c535SMauro Carvalho Chehab 	if (time_after(jiffies, state->ber_jiffies_stats)) {
42000400c535SMauro Carvalho Chehab 		time_us = dib8000_get_time_us(fe, -1);
42010400c535SMauro Carvalho Chehab 		state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
42020400c535SMauro Carvalho Chehab 
42038af16adfSMauro Carvalho Chehab 		dprintk("Next all layers stats available in %u us.\n", time_us);
42046ef06e78SMauro Carvalho Chehab 
42056ef06e78SMauro Carvalho Chehab 		dib8000_read_ber(fe, &val);
42066ef06e78SMauro Carvalho Chehab 		c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
42076ef06e78SMauro Carvalho Chehab 		c->post_bit_error.stat[0].uvalue += val;
42086ef06e78SMauro Carvalho Chehab 
42096ef06e78SMauro Carvalho Chehab 		c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
42106ef06e78SMauro Carvalho Chehab 		c->post_bit_count.stat[0].uvalue += 100000000;
4211704f01bbSMauro Carvalho Chehab 	}
42126ef06e78SMauro Carvalho Chehab 
42136ef06e78SMauro Carvalho Chehab 	if (state->revision < 0x8002)
42146ef06e78SMauro Carvalho Chehab 		return 0;
42156ef06e78SMauro Carvalho Chehab 
42166ef06e78SMauro Carvalho Chehab 	c->block_error.len = 4;
42176ef06e78SMauro Carvalho Chehab 	c->post_bit_error.len = 4;
42186ef06e78SMauro Carvalho Chehab 	c->post_bit_count.len = 4;
42196ef06e78SMauro Carvalho Chehab 
42206ef06e78SMauro Carvalho Chehab 	for (i = 0; i < 3; i++) {
42210400c535SMauro Carvalho Chehab 		unsigned nsegs = c->layer[i].segment_count;
42220400c535SMauro Carvalho Chehab 
42230400c535SMauro Carvalho Chehab 		if (nsegs == 0 || nsegs > 13)
4224704f01bbSMauro Carvalho Chehab 			continue;
4225704f01bbSMauro Carvalho Chehab 
42260400c535SMauro Carvalho Chehab 		time_us = 0;
42270400c535SMauro Carvalho Chehab 
42280400c535SMauro Carvalho Chehab 		if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) {
42290400c535SMauro Carvalho Chehab 			time_us = dib8000_get_time_us(fe, i);
42300400c535SMauro Carvalho Chehab 
42310400c535SMauro Carvalho Chehab 			state->ber_jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
4232704f01bbSMauro Carvalho Chehab 			dprintk("Next layer %c  stats will be available in %u us\n",
4233704f01bbSMauro Carvalho Chehab 				'A' + i, time_us);
4234704f01bbSMauro Carvalho Chehab 
42356ef06e78SMauro Carvalho Chehab 			val = dib8000_read_word(state, per_layer_regs[i].ber);
42366ef06e78SMauro Carvalho Chehab 			c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
42376ef06e78SMauro Carvalho Chehab 			c->post_bit_error.stat[1 + i].uvalue += val;
42386ef06e78SMauro Carvalho Chehab 
42396ef06e78SMauro Carvalho Chehab 			c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
42406ef06e78SMauro Carvalho Chehab 			c->post_bit_count.stat[1 + i].uvalue += 100000000;
42410400c535SMauro Carvalho Chehab 		}
42426ef06e78SMauro Carvalho Chehab 
42430400c535SMauro Carvalho Chehab 		if (show_per_stats) {
42446ef06e78SMauro Carvalho Chehab 			val = dib8000_read_word(state, per_layer_regs[i].per);
42456ef06e78SMauro Carvalho Chehab 
42466ef06e78SMauro Carvalho Chehab 			c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
42476ef06e78SMauro Carvalho Chehab 			c->block_error.stat[1 + i].uvalue += val;
42480400c535SMauro Carvalho Chehab 
42490400c535SMauro Carvalho Chehab 			if (!time_us)
42500400c535SMauro Carvalho Chehab 				time_us = dib8000_get_time_us(fe, i);
42510400c535SMauro Carvalho Chehab 			if (time_us) {
42525dc8526bSMauro Carvalho Chehab 				blocks = 1250000ULL * 1000000ULL;
42530400c535SMauro Carvalho Chehab 				do_div(blocks, time_us * 8 * 204);
42540400c535SMauro Carvalho Chehab 				c->block_count.stat[0].scale = FE_SCALE_COUNTER;
42550400c535SMauro Carvalho Chehab 				c->block_count.stat[0].uvalue += blocks;
42560400c535SMauro Carvalho Chehab 			}
42570400c535SMauro Carvalho Chehab 		}
42586ef06e78SMauro Carvalho Chehab 	}
42596ef06e78SMauro Carvalho Chehab 	return 0;
42606ef06e78SMauro Carvalho Chehab }
42616ef06e78SMauro Carvalho Chehab 
dib8000_set_slave_frontend(struct dvb_frontend * fe,struct dvb_frontend * fe_slave)4262d44913c1SMauro Carvalho Chehab static int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
42639a0bf528SMauro Carvalho Chehab {
42649a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
42659a0bf528SMauro Carvalho Chehab 	u8 index_frontend = 1;
42669a0bf528SMauro Carvalho Chehab 
42679a0bf528SMauro Carvalho Chehab 	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
42689a0bf528SMauro Carvalho Chehab 		index_frontend++;
42699a0bf528SMauro Carvalho Chehab 	if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
42708af16adfSMauro Carvalho Chehab 		dprintk("set slave fe %p to index %i\n", fe_slave, index_frontend);
42719a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend] = fe_slave;
42729a0bf528SMauro Carvalho Chehab 		return 0;
42739a0bf528SMauro Carvalho Chehab 	}
42749a0bf528SMauro Carvalho Chehab 
42758af16adfSMauro Carvalho Chehab 	dprintk("too many slave frontend\n");
42769a0bf528SMauro Carvalho Chehab 	return -ENOMEM;
42779a0bf528SMauro Carvalho Chehab }
42789a0bf528SMauro Carvalho Chehab 
dib8000_get_slave_frontend(struct dvb_frontend * fe,int slave_index)4279d44913c1SMauro Carvalho Chehab static struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
42809a0bf528SMauro Carvalho Chehab {
42819a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
42829a0bf528SMauro Carvalho Chehab 
42839a0bf528SMauro Carvalho Chehab 	if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
42849a0bf528SMauro Carvalho Chehab 		return NULL;
42859a0bf528SMauro Carvalho Chehab 	return state->fe[slave_index];
42869a0bf528SMauro Carvalho Chehab }
42879a0bf528SMauro Carvalho Chehab 
dib8000_i2c_enumeration(struct i2c_adapter * host,int no_of_demods,u8 default_addr,u8 first_addr,u8 is_dib8096p)4288d44913c1SMauro Carvalho Chehab static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
42899a0bf528SMauro Carvalho Chehab 		u8 default_addr, u8 first_addr, u8 is_dib8096p)
42909a0bf528SMauro Carvalho Chehab {
42919a0bf528SMauro Carvalho Chehab 	int k = 0, ret = 0;
42929a0bf528SMauro Carvalho Chehab 	u8 new_addr = 0;
42939a0bf528SMauro Carvalho Chehab 	struct i2c_device client = {.adap = host };
42949a0bf528SMauro Carvalho Chehab 
42956396bb22SKees Cook 	client.i2c_write_buffer = kzalloc(4, GFP_KERNEL);
42969a0bf528SMauro Carvalho Chehab 	if (!client.i2c_write_buffer) {
42978af16adfSMauro Carvalho Chehab 		dprintk("%s: not enough memory\n", __func__);
42989a0bf528SMauro Carvalho Chehab 		return -ENOMEM;
42999a0bf528SMauro Carvalho Chehab 	}
43006396bb22SKees Cook 	client.i2c_read_buffer = kzalloc(4, GFP_KERNEL);
43019a0bf528SMauro Carvalho Chehab 	if (!client.i2c_read_buffer) {
43028af16adfSMauro Carvalho Chehab 		dprintk("%s: not enough memory\n", __func__);
43039a0bf528SMauro Carvalho Chehab 		ret = -ENOMEM;
43049a0bf528SMauro Carvalho Chehab 		goto error_memory_read;
43059a0bf528SMauro Carvalho Chehab 	}
43069a0bf528SMauro Carvalho Chehab 	client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
43079a0bf528SMauro Carvalho Chehab 	if (!client.i2c_buffer_lock) {
43088af16adfSMauro Carvalho Chehab 		dprintk("%s: not enough memory\n", __func__);
43099a0bf528SMauro Carvalho Chehab 		ret = -ENOMEM;
43109a0bf528SMauro Carvalho Chehab 		goto error_memory_lock;
43119a0bf528SMauro Carvalho Chehab 	}
43129a0bf528SMauro Carvalho Chehab 	mutex_init(client.i2c_buffer_lock);
43139a0bf528SMauro Carvalho Chehab 
43149a0bf528SMauro Carvalho Chehab 	for (k = no_of_demods - 1; k >= 0; k--) {
43159a0bf528SMauro Carvalho Chehab 		/* designated i2c address */
43169a0bf528SMauro Carvalho Chehab 		new_addr = first_addr + (k << 1);
43179a0bf528SMauro Carvalho Chehab 
43189a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
43199a0bf528SMauro Carvalho Chehab 		if (!is_dib8096p)
43209a0bf528SMauro Carvalho Chehab 			dib8000_i2c_write16(&client, 1287, 0x0003);	/* sram lead in, rdy */
43219a0bf528SMauro Carvalho Chehab 		if (dib8000_identify(&client) == 0) {
43229a0bf528SMauro Carvalho Chehab 			/* sram lead in, rdy */
43239a0bf528SMauro Carvalho Chehab 			if (!is_dib8096p)
43249a0bf528SMauro Carvalho Chehab 				dib8000_i2c_write16(&client, 1287, 0x0003);
43259a0bf528SMauro Carvalho Chehab 			client.addr = default_addr;
43269a0bf528SMauro Carvalho Chehab 			if (dib8000_identify(&client) == 0) {
43278af16adfSMauro Carvalho Chehab 				dprintk("#%d: not identified\n", k);
43289a0bf528SMauro Carvalho Chehab 				ret  = -EINVAL;
43299a0bf528SMauro Carvalho Chehab 				goto error;
43309a0bf528SMauro Carvalho Chehab 			}
43319a0bf528SMauro Carvalho Chehab 		}
43329a0bf528SMauro Carvalho Chehab 
43339a0bf528SMauro Carvalho Chehab 		/* start diversity to pull_down div_str - just for i2c-enumeration */
43349a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
43359a0bf528SMauro Carvalho Chehab 
43369a0bf528SMauro Carvalho Chehab 		/* set new i2c address and force divstart */
43379a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
43389a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
43399a0bf528SMauro Carvalho Chehab 		dib8000_identify(&client);
43409a0bf528SMauro Carvalho Chehab 
43418af16adfSMauro Carvalho Chehab 		dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
43429a0bf528SMauro Carvalho Chehab 	}
43439a0bf528SMauro Carvalho Chehab 
43449a0bf528SMauro Carvalho Chehab 	for (k = 0; k < no_of_demods; k++) {
43459a0bf528SMauro Carvalho Chehab 		new_addr = first_addr | (k << 1);
43469a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
43479a0bf528SMauro Carvalho Chehab 
43489a0bf528SMauro Carvalho Chehab 		// unforce divstr
43499a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1285, new_addr << 2);
43509a0bf528SMauro Carvalho Chehab 
43519a0bf528SMauro Carvalho Chehab 		/* deactivate div - it was just for i2c-enumeration */
43529a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1286, 0);
43539a0bf528SMauro Carvalho Chehab 	}
43549a0bf528SMauro Carvalho Chehab 
43559a0bf528SMauro Carvalho Chehab error:
43569a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_buffer_lock);
43579a0bf528SMauro Carvalho Chehab error_memory_lock:
43589a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_read_buffer);
43599a0bf528SMauro Carvalho Chehab error_memory_read:
43609a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_write_buffer);
43619a0bf528SMauro Carvalho Chehab 
43629a0bf528SMauro Carvalho Chehab 	return ret;
43639a0bf528SMauro Carvalho Chehab }
43649a0bf528SMauro Carvalho Chehab 
dib8000_fe_get_tune_settings(struct dvb_frontend * fe,struct dvb_frontend_tune_settings * tune)43659a0bf528SMauro Carvalho Chehab static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
43669a0bf528SMauro Carvalho Chehab {
43679a0bf528SMauro Carvalho Chehab 	tune->min_delay_ms = 1000;
43689a0bf528SMauro Carvalho Chehab 	tune->step_size = 0;
43699a0bf528SMauro Carvalho Chehab 	tune->max_drift = 0;
43709a0bf528SMauro Carvalho Chehab 	return 0;
43719a0bf528SMauro Carvalho Chehab }
43729a0bf528SMauro Carvalho Chehab 
dib8000_release(struct dvb_frontend * fe)43739a0bf528SMauro Carvalho Chehab static void dib8000_release(struct dvb_frontend *fe)
43749a0bf528SMauro Carvalho Chehab {
43759a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
43769a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
43779a0bf528SMauro Carvalho Chehab 
43789a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
43799a0bf528SMauro Carvalho Chehab 		dvb_frontend_detach(st->fe[index_frontend]);
43809a0bf528SMauro Carvalho Chehab 
43819a0bf528SMauro Carvalho Chehab 	dibx000_exit_i2c_master(&st->i2c_master);
43829a0bf528SMauro Carvalho Chehab 	i2c_del_adapter(&st->dib8096p_tuner_adap);
43839a0bf528SMauro Carvalho Chehab 	kfree(st->fe[0]);
43849a0bf528SMauro Carvalho Chehab 	kfree(st);
43859a0bf528SMauro Carvalho Chehab }
43869a0bf528SMauro Carvalho Chehab 
dib8000_get_i2c_master(struct dvb_frontend * fe,enum dibx000_i2c_interface intf,int gating)4387d44913c1SMauro Carvalho Chehab static struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
43889a0bf528SMauro Carvalho Chehab {
43899a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
43909a0bf528SMauro Carvalho Chehab 	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
43919a0bf528SMauro Carvalho Chehab }
43929a0bf528SMauro Carvalho Chehab 
dib8000_pid_filter_ctrl(struct dvb_frontend * fe,u8 onoff)4393d44913c1SMauro Carvalho Chehab static int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
43949a0bf528SMauro Carvalho Chehab {
43959a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
43969a0bf528SMauro Carvalho Chehab 	u16 val = dib8000_read_word(st, 299) & 0xffef;
43979a0bf528SMauro Carvalho Chehab 	val |= (onoff & 0x1) << 4;
43989a0bf528SMauro Carvalho Chehab 
43998af16adfSMauro Carvalho Chehab 	dprintk("pid filter enabled %d\n", onoff);
44009a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(st, 299, val);
44019a0bf528SMauro Carvalho Chehab }
44029a0bf528SMauro Carvalho Chehab 
dib8000_pid_filter(struct dvb_frontend * fe,u8 id,u16 pid,u8 onoff)4403d44913c1SMauro Carvalho Chehab static int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
44049a0bf528SMauro Carvalho Chehab {
44059a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
44068af16adfSMauro Carvalho Chehab 	dprintk("Index %x, PID %d, OnOff %d\n", id, pid, onoff);
44079a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
44089a0bf528SMauro Carvalho Chehab }
44099a0bf528SMauro Carvalho Chehab 
44109a0bf528SMauro Carvalho Chehab static const struct dvb_frontend_ops dib8000_ops = {
44119a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ISDBT },
44129a0bf528SMauro Carvalho Chehab 	.info = {
44139a0bf528SMauro Carvalho Chehab 		 .name = "DiBcom 8000 ISDB-T",
4414f1b1eabfSMauro Carvalho Chehab 		 .frequency_min_hz =  44250 * kHz,
4415f1b1eabfSMauro Carvalho Chehab 		 .frequency_max_hz = 867250 * kHz,
4416f1b1eabfSMauro Carvalho Chehab 		 .frequency_stepsize_hz = 62500,
44179a0bf528SMauro Carvalho Chehab 		 .caps = FE_CAN_INVERSION_AUTO |
44189a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
44199a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
44209a0bf528SMauro Carvalho Chehab 		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
44219a0bf528SMauro Carvalho Chehab 		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
44229a0bf528SMauro Carvalho Chehab 		 },
44239a0bf528SMauro Carvalho Chehab 
44249a0bf528SMauro Carvalho Chehab 	.release = dib8000_release,
44259a0bf528SMauro Carvalho Chehab 
44269a0bf528SMauro Carvalho Chehab 	.init = dib8000_wakeup,
44279a0bf528SMauro Carvalho Chehab 	.sleep = dib8000_sleep,
44289a0bf528SMauro Carvalho Chehab 
44299a0bf528SMauro Carvalho Chehab 	.set_frontend = dib8000_set_frontend,
44309a0bf528SMauro Carvalho Chehab 	.get_tune_settings = dib8000_fe_get_tune_settings,
44319a0bf528SMauro Carvalho Chehab 	.get_frontend = dib8000_get_frontend,
44329a0bf528SMauro Carvalho Chehab 
44339a0bf528SMauro Carvalho Chehab 	.read_status = dib8000_read_status,
44349a0bf528SMauro Carvalho Chehab 	.read_ber = dib8000_read_ber,
44359a0bf528SMauro Carvalho Chehab 	.read_signal_strength = dib8000_read_signal_strength,
44369a0bf528SMauro Carvalho Chehab 	.read_snr = dib8000_read_snr,
44379a0bf528SMauro Carvalho Chehab 	.read_ucblocks = dib8000_read_unc_blocks,
44389a0bf528SMauro Carvalho Chehab };
44399a0bf528SMauro Carvalho Chehab 
dib8000_init(struct i2c_adapter * i2c_adap,u8 i2c_addr,struct dib8000_config * cfg)4440d44913c1SMauro Carvalho Chehab static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
44419a0bf528SMauro Carvalho Chehab {
44429a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *fe;
44439a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state;
44449a0bf528SMauro Carvalho Chehab 
44458af16adfSMauro Carvalho Chehab 	dprintk("dib8000_init\n");
44469a0bf528SMauro Carvalho Chehab 
44479a0bf528SMauro Carvalho Chehab 	state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
44489a0bf528SMauro Carvalho Chehab 	if (state == NULL)
44499a0bf528SMauro Carvalho Chehab 		return NULL;
44509a0bf528SMauro Carvalho Chehab 	fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
44519a0bf528SMauro Carvalho Chehab 	if (fe == NULL)
44529a0bf528SMauro Carvalho Chehab 		goto error;
44539a0bf528SMauro Carvalho Chehab 
44549a0bf528SMauro Carvalho Chehab 	memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
44559a0bf528SMauro Carvalho Chehab 	state->i2c.adap = i2c_adap;
44569a0bf528SMauro Carvalho Chehab 	state->i2c.addr = i2c_addr;
44579a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_write_buffer = state->i2c_write_buffer;
44589a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_read_buffer = state->i2c_read_buffer;
44599a0bf528SMauro Carvalho Chehab 	mutex_init(&state->i2c_buffer_lock);
44609a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
44619a0bf528SMauro Carvalho Chehab 	state->gpio_val = cfg->gpio_val;
44629a0bf528SMauro Carvalho Chehab 	state->gpio_dir = cfg->gpio_dir;
44639a0bf528SMauro Carvalho Chehab 
44649a0bf528SMauro Carvalho Chehab 	/* Ensure the output mode remains at the previous default if it's
44659a0bf528SMauro Carvalho Chehab 	 * not specifically set by the caller.
44669a0bf528SMauro Carvalho Chehab 	 */
44679a0bf528SMauro Carvalho Chehab 	if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
44689a0bf528SMauro Carvalho Chehab 		state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
44699a0bf528SMauro Carvalho Chehab 
44709a0bf528SMauro Carvalho Chehab 	state->fe[0] = fe;
44719a0bf528SMauro Carvalho Chehab 	fe->demodulator_priv = state;
44729a0bf528SMauro Carvalho Chehab 	memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
44739a0bf528SMauro Carvalho Chehab 
44749a0bf528SMauro Carvalho Chehab 	state->timf_default = cfg->pll->timf;
44759a0bf528SMauro Carvalho Chehab 
44768dbdcc72SZhou Qingyang 	if (dib8000_identify(&state->i2c) == 0) {
44778dbdcc72SZhou Qingyang 		kfree(fe);
44789a0bf528SMauro Carvalho Chehab 		goto error;
44798dbdcc72SZhou Qingyang 	}
44809a0bf528SMauro Carvalho Chehab 
44819a0bf528SMauro Carvalho Chehab 	dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
44829a0bf528SMauro Carvalho Chehab 
44839a0bf528SMauro Carvalho Chehab 	/* init 8096p tuner adapter */
448485709cbfSMauro Carvalho Chehab 	strscpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
44859a0bf528SMauro Carvalho Chehab 		sizeof(state->dib8096p_tuner_adap.name));
44869a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
44879a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.algo_data = NULL;
44889a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
44899a0bf528SMauro Carvalho Chehab 	i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
44909a0bf528SMauro Carvalho Chehab 	i2c_add_adapter(&state->dib8096p_tuner_adap);
44919a0bf528SMauro Carvalho Chehab 
44929a0bf528SMauro Carvalho Chehab 	dib8000_reset(fe);
44939a0bf528SMauro Carvalho Chehab 
44949a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));	/* ber_rs_len = 3 */
4495173a64cbSPatrick Boettcher 	state->current_demod_bw = 6000;
44969a0bf528SMauro Carvalho Chehab 
44979a0bf528SMauro Carvalho Chehab 	return fe;
44989a0bf528SMauro Carvalho Chehab 
44999a0bf528SMauro Carvalho Chehab error:
45009a0bf528SMauro Carvalho Chehab 	kfree(state);
45019a0bf528SMauro Carvalho Chehab 	return NULL;
45029a0bf528SMauro Carvalho Chehab }
45039a0bf528SMauro Carvalho Chehab 
dib8000_attach(struct dib8000_ops * ops)4504d44913c1SMauro Carvalho Chehab void *dib8000_attach(struct dib8000_ops *ops)
4505d44913c1SMauro Carvalho Chehab {
4506d44913c1SMauro Carvalho Chehab 	if (!ops)
4507d44913c1SMauro Carvalho Chehab 		return NULL;
4508d44913c1SMauro Carvalho Chehab 
4509d44913c1SMauro Carvalho Chehab 	ops->pwm_agc_reset = dib8000_pwm_agc_reset;
4510d44913c1SMauro Carvalho Chehab 	ops->get_dc_power = dib8090p_get_dc_power;
4511d44913c1SMauro Carvalho Chehab 	ops->set_gpio = dib8000_set_gpio;
4512d44913c1SMauro Carvalho Chehab 	ops->get_slave_frontend = dib8000_get_slave_frontend;
4513d44913c1SMauro Carvalho Chehab 	ops->set_tune_state = dib8000_set_tune_state;
4514d44913c1SMauro Carvalho Chehab 	ops->pid_filter_ctrl = dib8000_pid_filter_ctrl;
4515d44913c1SMauro Carvalho Chehab 	ops->get_adc_power = dib8000_get_adc_power;
4516d44913c1SMauro Carvalho Chehab 	ops->update_pll = dib8000_update_pll;
4517d44913c1SMauro Carvalho Chehab 	ops->tuner_sleep = dib8096p_tuner_sleep;
4518d44913c1SMauro Carvalho Chehab 	ops->get_tune_state = dib8000_get_tune_state;
4519d44913c1SMauro Carvalho Chehab 	ops->get_i2c_tuner = dib8096p_get_i2c_tuner;
4520d44913c1SMauro Carvalho Chehab 	ops->set_slave_frontend = dib8000_set_slave_frontend;
4521d44913c1SMauro Carvalho Chehab 	ops->pid_filter = dib8000_pid_filter;
4522d44913c1SMauro Carvalho Chehab 	ops->ctrl_timf = dib8000_ctrl_timf;
4523d44913c1SMauro Carvalho Chehab 	ops->init = dib8000_init;
4524d44913c1SMauro Carvalho Chehab 	ops->get_i2c_master = dib8000_get_i2c_master;
4525d44913c1SMauro Carvalho Chehab 	ops->i2c_enumeration = dib8000_i2c_enumeration;
4526d44913c1SMauro Carvalho Chehab 	ops->set_wbd_ref = dib8000_set_wbd_ref;
4527d44913c1SMauro Carvalho Chehab 
4528d44913c1SMauro Carvalho Chehab 	return ops;
4529d44913c1SMauro Carvalho Chehab }
4530*86495af1SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(dib8000_attach);
45319a0bf528SMauro Carvalho Chehab 
453299e44da7SPatrick Boettcher MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@parrot.com, Patrick Boettcher <patrick.boettcher@posteo.de>");
45339a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
45349a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
4535