19a0bf528SMauro Carvalho Chehab /*
29a0bf528SMauro Carvalho Chehab  * Linux-DVB Driver for DiBcom's DiB8000 chip (ISDB-T).
39a0bf528SMauro Carvalho Chehab  *
49a0bf528SMauro Carvalho Chehab  * Copyright (C) 2009 DiBcom (http://www.dibcom.fr/)
59a0bf528SMauro Carvalho Chehab  *
69a0bf528SMauro Carvalho Chehab  * This program is free software; you can redistribute it and/or
79a0bf528SMauro Carvalho Chehab  *  modify it under the terms of the GNU General Public License as
89a0bf528SMauro Carvalho Chehab  *  published by the Free Software Foundation, version 2.
99a0bf528SMauro Carvalho Chehab  */
109a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
119a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
129a0bf528SMauro Carvalho Chehab #include <linux/i2c.h>
139a0bf528SMauro Carvalho Chehab #include <linux/mutex.h>
149a0bf528SMauro Carvalho Chehab 
159a0bf528SMauro Carvalho Chehab #include "dvb_math.h"
169a0bf528SMauro Carvalho Chehab 
179a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h"
189a0bf528SMauro Carvalho Chehab 
199a0bf528SMauro Carvalho Chehab #include "dib8000.h"
209a0bf528SMauro Carvalho Chehab 
219a0bf528SMauro Carvalho Chehab #define LAYER_ALL -1
229a0bf528SMauro Carvalho Chehab #define LAYER_A   1
239a0bf528SMauro Carvalho Chehab #define LAYER_B   2
249a0bf528SMauro Carvalho Chehab #define LAYER_C   3
259a0bf528SMauro Carvalho Chehab 
269a0bf528SMauro Carvalho Chehab #define MAX_NUMBER_OF_FRONTENDS 6
27173a64cbSPatrick Boettcher /* #define DIB8000_AGC_FREEZE */
289a0bf528SMauro Carvalho Chehab 
299a0bf528SMauro Carvalho Chehab static int debug;
309a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
319a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
329a0bf528SMauro Carvalho Chehab 
339a0bf528SMauro Carvalho Chehab #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0)
349a0bf528SMauro Carvalho Chehab 
359a0bf528SMauro Carvalho Chehab struct i2c_device {
369a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *adap;
379a0bf528SMauro Carvalho Chehab 	u8 addr;
389a0bf528SMauro Carvalho Chehab 	u8 *i2c_write_buffer;
399a0bf528SMauro Carvalho Chehab 	u8 *i2c_read_buffer;
409a0bf528SMauro Carvalho Chehab 	struct mutex *i2c_buffer_lock;
419a0bf528SMauro Carvalho Chehab };
429a0bf528SMauro Carvalho Chehab 
43173a64cbSPatrick Boettcher enum param_loop_step {
44173a64cbSPatrick Boettcher 	LOOP_TUNE_1,
45173a64cbSPatrick Boettcher 	LOOP_TUNE_2
46173a64cbSPatrick Boettcher };
47173a64cbSPatrick Boettcher 
48173a64cbSPatrick Boettcher enum dib8000_autosearch_step {
49173a64cbSPatrick Boettcher 	AS_START = 0,
50173a64cbSPatrick Boettcher 	AS_SEARCHING_FFT,
51173a64cbSPatrick Boettcher 	AS_SEARCHING_GUARD,
52173a64cbSPatrick Boettcher 	AS_DONE = 100,
53173a64cbSPatrick Boettcher };
54173a64cbSPatrick Boettcher 
55173a64cbSPatrick Boettcher enum timeout_mode {
56173a64cbSPatrick Boettcher 	SYMBOL_DEPENDENT_OFF = 0,
57173a64cbSPatrick Boettcher 	SYMBOL_DEPENDENT_ON,
58173a64cbSPatrick Boettcher };
59173a64cbSPatrick Boettcher 
609a0bf528SMauro Carvalho Chehab struct dib8000_state {
619a0bf528SMauro Carvalho Chehab 	struct dib8000_config cfg;
629a0bf528SMauro Carvalho Chehab 
639a0bf528SMauro Carvalho Chehab 	struct i2c_device i2c;
649a0bf528SMauro Carvalho Chehab 
659a0bf528SMauro Carvalho Chehab 	struct dibx000_i2c_master i2c_master;
669a0bf528SMauro Carvalho Chehab 
679a0bf528SMauro Carvalho Chehab 	u16 wbd_ref;
689a0bf528SMauro Carvalho Chehab 
699a0bf528SMauro Carvalho Chehab 	u8 current_band;
709a0bf528SMauro Carvalho Chehab 	u32 current_bandwidth;
719a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *current_agc;
729a0bf528SMauro Carvalho Chehab 	u32 timf;
739a0bf528SMauro Carvalho Chehab 	u32 timf_default;
749a0bf528SMauro Carvalho Chehab 
759a0bf528SMauro Carvalho Chehab 	u8 div_force_off:1;
769a0bf528SMauro Carvalho Chehab 	u8 div_state:1;
779a0bf528SMauro Carvalho Chehab 	u16 div_sync_wait;
789a0bf528SMauro Carvalho Chehab 
799a0bf528SMauro Carvalho Chehab 	u8 agc_state;
809a0bf528SMauro Carvalho Chehab 	u8 differential_constellation;
819a0bf528SMauro Carvalho Chehab 	u8 diversity_onoff;
829a0bf528SMauro Carvalho Chehab 
839a0bf528SMauro Carvalho Chehab 	s16 ber_monitored_layer;
849a0bf528SMauro Carvalho Chehab 	u16 gpio_dir;
859a0bf528SMauro Carvalho Chehab 	u16 gpio_val;
869a0bf528SMauro Carvalho Chehab 
879a0bf528SMauro Carvalho Chehab 	u16 revision;
889a0bf528SMauro Carvalho Chehab 	u8 isdbt_cfg_loaded;
899a0bf528SMauro Carvalho Chehab 	enum frontend_tune_state tune_state;
90173a64cbSPatrick Boettcher 	s32 status;
919a0bf528SMauro Carvalho Chehab 
929a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
939a0bf528SMauro Carvalho Chehab 
949a0bf528SMauro Carvalho Chehab 	/* for the I2C transfer */
959a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2];
969a0bf528SMauro Carvalho Chehab 	u8 i2c_write_buffer[4];
979a0bf528SMauro Carvalho Chehab 	u8 i2c_read_buffer[2];
989a0bf528SMauro Carvalho Chehab 	struct mutex i2c_buffer_lock;
999a0bf528SMauro Carvalho Chehab 	u8 input_mode_mpeg;
1009a0bf528SMauro Carvalho Chehab 
1019a0bf528SMauro Carvalho Chehab 	u16 tuner_enable;
1029a0bf528SMauro Carvalho Chehab 	struct i2c_adapter dib8096p_tuner_adap;
103173a64cbSPatrick Boettcher 	u16 current_demod_bw;
104173a64cbSPatrick Boettcher 
105173a64cbSPatrick Boettcher 	u16 seg_mask;
106173a64cbSPatrick Boettcher 	u16 seg_diff_mask;
107173a64cbSPatrick Boettcher 	u16 mode;
108173a64cbSPatrick Boettcher 	u8 layer_b_nb_seg;
109173a64cbSPatrick Boettcher 	u8 layer_c_nb_seg;
110173a64cbSPatrick Boettcher 
111173a64cbSPatrick Boettcher 	u8 channel_parameters_set;
112173a64cbSPatrick Boettcher 	u16 autosearch_state;
113173a64cbSPatrick Boettcher 	u16 found_nfft;
114173a64cbSPatrick Boettcher 	u16 found_guard;
115173a64cbSPatrick Boettcher 	u8 subchannel;
116173a64cbSPatrick Boettcher 	u8 symbol_duration;
117173a64cbSPatrick Boettcher 	u32 timeout;
118173a64cbSPatrick Boettcher 	u8 longest_intlv_layer;
119173a64cbSPatrick Boettcher 	u16 output_mode;
120173a64cbSPatrick Boettcher 
121173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
122173a64cbSPatrick Boettcher 	u16 agc1_max;
123173a64cbSPatrick Boettcher 	u16 agc1_min;
124173a64cbSPatrick Boettcher 	u16 agc2_max;
125173a64cbSPatrick Boettcher 	u16 agc2_min;
126173a64cbSPatrick Boettcher #endif
1279a0bf528SMauro Carvalho Chehab };
1289a0bf528SMauro Carvalho Chehab 
1299a0bf528SMauro Carvalho Chehab enum dib8000_power_mode {
1309a0bf528SMauro Carvalho Chehab 	DIB8000_POWER_ALL = 0,
1319a0bf528SMauro Carvalho Chehab 	DIB8000_POWER_INTERFACE_ONLY,
1329a0bf528SMauro Carvalho Chehab };
1339a0bf528SMauro Carvalho Chehab 
1349a0bf528SMauro Carvalho Chehab static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
1359a0bf528SMauro Carvalho Chehab {
1369a0bf528SMauro Carvalho Chehab 	u16 ret;
1379a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2] = {
1389a0bf528SMauro Carvalho Chehab 		{.addr = i2c->addr >> 1, .flags = 0, .len = 2},
1399a0bf528SMauro Carvalho Chehab 		{.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
1409a0bf528SMauro Carvalho Chehab 	};
1419a0bf528SMauro Carvalho Chehab 
1429a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
1439a0bf528SMauro Carvalho Chehab 		dprintk("could not acquire lock");
1449a0bf528SMauro Carvalho Chehab 		return 0;
1459a0bf528SMauro Carvalho Chehab 	}
1469a0bf528SMauro Carvalho Chehab 
1479a0bf528SMauro Carvalho Chehab 	msg[0].buf    = i2c->i2c_write_buffer;
1489a0bf528SMauro Carvalho Chehab 	msg[0].buf[0] = reg >> 8;
1499a0bf528SMauro Carvalho Chehab 	msg[0].buf[1] = reg & 0xff;
1509a0bf528SMauro Carvalho Chehab 	msg[1].buf    = i2c->i2c_read_buffer;
1519a0bf528SMauro Carvalho Chehab 
1529a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(i2c->adap, msg, 2) != 2)
1539a0bf528SMauro Carvalho Chehab 		dprintk("i2c read error on %d", reg);
1549a0bf528SMauro Carvalho Chehab 
1559a0bf528SMauro Carvalho Chehab 	ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
1569a0bf528SMauro Carvalho Chehab 	mutex_unlock(i2c->i2c_buffer_lock);
1579a0bf528SMauro Carvalho Chehab 	return ret;
1589a0bf528SMauro Carvalho Chehab }
1599a0bf528SMauro Carvalho Chehab 
1609a0bf528SMauro Carvalho Chehab static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
1619a0bf528SMauro Carvalho Chehab {
1629a0bf528SMauro Carvalho Chehab 	u16 ret;
1639a0bf528SMauro Carvalho Chehab 
1649a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
1659a0bf528SMauro Carvalho Chehab 		dprintk("could not acquire lock");
1669a0bf528SMauro Carvalho Chehab 		return 0;
1679a0bf528SMauro Carvalho Chehab 	}
1689a0bf528SMauro Carvalho Chehab 
1699a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = reg >> 8;
1709a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
1719a0bf528SMauro Carvalho Chehab 
1729a0bf528SMauro Carvalho Chehab 	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
1739a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c.addr >> 1;
1749a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
1759a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
1769a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 2;
1779a0bf528SMauro Carvalho Chehab 	state->msg[1].addr = state->i2c.addr >> 1;
1789a0bf528SMauro Carvalho Chehab 	state->msg[1].flags = I2C_M_RD;
1799a0bf528SMauro Carvalho Chehab 	state->msg[1].buf = state->i2c_read_buffer;
1809a0bf528SMauro Carvalho Chehab 	state->msg[1].len = 2;
1819a0bf528SMauro Carvalho Chehab 
1829a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
1839a0bf528SMauro Carvalho Chehab 		dprintk("i2c read error on %d", reg);
1849a0bf528SMauro Carvalho Chehab 
1859a0bf528SMauro Carvalho Chehab 	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
1869a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
1879a0bf528SMauro Carvalho Chehab 
1889a0bf528SMauro Carvalho Chehab 	return ret;
1899a0bf528SMauro Carvalho Chehab }
1909a0bf528SMauro Carvalho Chehab 
1919a0bf528SMauro Carvalho Chehab static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
1929a0bf528SMauro Carvalho Chehab {
1939a0bf528SMauro Carvalho Chehab 	u16 rw[2];
1949a0bf528SMauro Carvalho Chehab 
1959a0bf528SMauro Carvalho Chehab 	rw[0] = dib8000_read_word(state, reg + 0);
1969a0bf528SMauro Carvalho Chehab 	rw[1] = dib8000_read_word(state, reg + 1);
1979a0bf528SMauro Carvalho Chehab 
1989a0bf528SMauro Carvalho Chehab 	return ((rw[0] << 16) | (rw[1]));
1999a0bf528SMauro Carvalho Chehab }
2009a0bf528SMauro Carvalho Chehab 
2019a0bf528SMauro Carvalho Chehab static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
2029a0bf528SMauro Carvalho Chehab {
2039a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
2049a0bf528SMauro Carvalho Chehab 	int ret = 0;
2059a0bf528SMauro Carvalho Chehab 
2069a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
2079a0bf528SMauro Carvalho Chehab 		dprintk("could not acquire lock");
2089a0bf528SMauro Carvalho Chehab 		return -EINVAL;
2099a0bf528SMauro Carvalho Chehab 	}
2109a0bf528SMauro Carvalho Chehab 
2119a0bf528SMauro Carvalho Chehab 	msg.buf    = i2c->i2c_write_buffer;
2129a0bf528SMauro Carvalho Chehab 	msg.buf[0] = (reg >> 8) & 0xff;
2139a0bf528SMauro Carvalho Chehab 	msg.buf[1] = reg & 0xff;
2149a0bf528SMauro Carvalho Chehab 	msg.buf[2] = (val >> 8) & 0xff;
2159a0bf528SMauro Carvalho Chehab 	msg.buf[3] = val & 0xff;
2169a0bf528SMauro Carvalho Chehab 
2179a0bf528SMauro Carvalho Chehab 	ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
2189a0bf528SMauro Carvalho Chehab 	mutex_unlock(i2c->i2c_buffer_lock);
2199a0bf528SMauro Carvalho Chehab 
2209a0bf528SMauro Carvalho Chehab 	return ret;
2219a0bf528SMauro Carvalho Chehab }
2229a0bf528SMauro Carvalho Chehab 
2239a0bf528SMauro Carvalho Chehab static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
2249a0bf528SMauro Carvalho Chehab {
2259a0bf528SMauro Carvalho Chehab 	int ret;
2269a0bf528SMauro Carvalho Chehab 
2279a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2289a0bf528SMauro Carvalho Chehab 		dprintk("could not acquire lock");
2299a0bf528SMauro Carvalho Chehab 		return -EINVAL;
2309a0bf528SMauro Carvalho Chehab 	}
2319a0bf528SMauro Carvalho Chehab 
2329a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
2339a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
2349a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
2359a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[3] = val & 0xff;
2369a0bf528SMauro Carvalho Chehab 
2379a0bf528SMauro Carvalho Chehab 	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
2389a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c.addr >> 1;
2399a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
2409a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
2419a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 4;
2429a0bf528SMauro Carvalho Chehab 
2439a0bf528SMauro Carvalho Chehab 	ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
2449a0bf528SMauro Carvalho Chehab 			-EREMOTEIO : 0);
2459a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
2469a0bf528SMauro Carvalho Chehab 
2479a0bf528SMauro Carvalho Chehab 	return ret;
2489a0bf528SMauro Carvalho Chehab }
2499a0bf528SMauro Carvalho Chehab 
2509a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
2519a0bf528SMauro Carvalho Chehab 	(769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c,
2529a0bf528SMauro Carvalho Chehab 		(920 << 5) | 0x09
2539a0bf528SMauro Carvalho Chehab };
2549a0bf528SMauro Carvalho Chehab 
2559a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_1seg[8] = {
2569a0bf528SMauro Carvalho Chehab 	(692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
2579a0bf528SMauro Carvalho Chehab };
2589a0bf528SMauro Carvalho Chehab 
2599a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
2609a0bf528SMauro Carvalho Chehab 	(832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11,
2619a0bf528SMauro Carvalho Chehab 		(-931 << 5) | 0x0f
2629a0bf528SMauro Carvalho Chehab };
2639a0bf528SMauro Carvalho Chehab 
2649a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
2659a0bf528SMauro Carvalho Chehab 	(622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e,
2669a0bf528SMauro Carvalho Chehab 		(982 << 5) | 0x0c
2679a0bf528SMauro Carvalho Chehab };
2689a0bf528SMauro Carvalho Chehab 
2699a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
2709a0bf528SMauro Carvalho Chehab 	(699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12,
2719a0bf528SMauro Carvalho Chehab 		(-720 << 5) | 0x0d
2729a0bf528SMauro Carvalho Chehab };
2739a0bf528SMauro Carvalho Chehab 
2749a0bf528SMauro Carvalho Chehab static const s16 coeff_2k_sb_3seg[8] = {
2759a0bf528SMauro Carvalho Chehab 	(664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e,
2769a0bf528SMauro Carvalho Chehab 		(-610 << 5) | 0x0a
2779a0bf528SMauro Carvalho Chehab };
2789a0bf528SMauro Carvalho Chehab 
2799a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
2809a0bf528SMauro Carvalho Chehab 	(-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f,
2819a0bf528SMauro Carvalho Chehab 		(-922 << 5) | 0x0d
2829a0bf528SMauro Carvalho Chehab };
2839a0bf528SMauro Carvalho Chehab 
2849a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_1seg[8] = {
2859a0bf528SMauro Carvalho Chehab 	(638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d,
2869a0bf528SMauro Carvalho Chehab 		(-655 << 5) | 0x0a
2879a0bf528SMauro Carvalho Chehab };
2889a0bf528SMauro Carvalho Chehab 
2899a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
2909a0bf528SMauro Carvalho Chehab 	(-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14,
2919a0bf528SMauro Carvalho Chehab 		(-958 << 5) | 0x13
2929a0bf528SMauro Carvalho Chehab };
2939a0bf528SMauro Carvalho Chehab 
2949a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
2959a0bf528SMauro Carvalho Chehab 	(-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12,
2969a0bf528SMauro Carvalho Chehab 		(-568 << 5) | 0x0f
2979a0bf528SMauro Carvalho Chehab };
2989a0bf528SMauro Carvalho Chehab 
2999a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
3009a0bf528SMauro Carvalho Chehab 	(-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14,
3019a0bf528SMauro Carvalho Chehab 		(-848 << 5) | 0x13
3029a0bf528SMauro Carvalho Chehab };
3039a0bf528SMauro Carvalho Chehab 
3049a0bf528SMauro Carvalho Chehab static const s16 coeff_4k_sb_3seg[8] = {
3059a0bf528SMauro Carvalho Chehab 	(612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12,
3069a0bf528SMauro Carvalho Chehab 		(-869 << 5) | 0x13
3079a0bf528SMauro Carvalho Chehab };
3089a0bf528SMauro Carvalho Chehab 
3099a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
3109a0bf528SMauro Carvalho Chehab 	(-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13,
3119a0bf528SMauro Carvalho Chehab 		(-598 << 5) | 0x10
3129a0bf528SMauro Carvalho Chehab };
3139a0bf528SMauro Carvalho Chehab 
3149a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_1seg[8] = {
3159a0bf528SMauro Carvalho Chehab 	(673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f,
3169a0bf528SMauro Carvalho Chehab 		(585 << 5) | 0x0f
3179a0bf528SMauro Carvalho Chehab };
3189a0bf528SMauro Carvalho Chehab 
3199a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
3209a0bf528SMauro Carvalho Chehab 	(863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18,
3219a0bf528SMauro Carvalho Chehab 		(0 << 5) | 0x14
3229a0bf528SMauro Carvalho Chehab };
3239a0bf528SMauro Carvalho Chehab 
3249a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
3259a0bf528SMauro Carvalho Chehab 	(-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15,
3269a0bf528SMauro Carvalho Chehab 		(-877 << 5) | 0x15
3279a0bf528SMauro Carvalho Chehab };
3289a0bf528SMauro Carvalho Chehab 
3299a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
3309a0bf528SMauro Carvalho Chehab 	(-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18,
3319a0bf528SMauro Carvalho Chehab 		(-921 << 5) | 0x14
3329a0bf528SMauro Carvalho Chehab };
3339a0bf528SMauro Carvalho Chehab 
3349a0bf528SMauro Carvalho Chehab static const s16 coeff_8k_sb_3seg[8] = {
3359a0bf528SMauro Carvalho Chehab 	(514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15,
3369a0bf528SMauro Carvalho Chehab 		(690 << 5) | 0x14
3379a0bf528SMauro Carvalho Chehab };
3389a0bf528SMauro Carvalho Chehab 
3399a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_3seg[24] = {
3409a0bf528SMauro 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
3419a0bf528SMauro Carvalho Chehab };
3429a0bf528SMauro Carvalho Chehab 
3439a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_1seg[24] = {
3449a0bf528SMauro 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
3459a0bf528SMauro Carvalho Chehab };
3469a0bf528SMauro Carvalho Chehab 
3479a0bf528SMauro Carvalho Chehab static const s16 ana_fe_coeff_13seg[24] = {
3489a0bf528SMauro 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
3499a0bf528SMauro Carvalho Chehab };
3509a0bf528SMauro Carvalho Chehab 
3519a0bf528SMauro Carvalho Chehab static u16 fft_to_mode(struct dib8000_state *state)
3529a0bf528SMauro Carvalho Chehab {
3539a0bf528SMauro Carvalho Chehab 	u16 mode;
3549a0bf528SMauro Carvalho Chehab 	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
3559a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
3569a0bf528SMauro Carvalho Chehab 		mode = 1;
3579a0bf528SMauro Carvalho Chehab 		break;
3589a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
3599a0bf528SMauro Carvalho Chehab 		mode = 2;
3609a0bf528SMauro Carvalho Chehab 		break;
3619a0bf528SMauro Carvalho Chehab 	default:
3629a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_AUTO:
3639a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
3649a0bf528SMauro Carvalho Chehab 		mode = 3;
3659a0bf528SMauro Carvalho Chehab 		break;
3669a0bf528SMauro Carvalho Chehab 	}
3679a0bf528SMauro Carvalho Chehab 	return mode;
3689a0bf528SMauro Carvalho Chehab }
3699a0bf528SMauro Carvalho Chehab 
3709a0bf528SMauro Carvalho Chehab static void dib8000_set_acquisition_mode(struct dib8000_state *state)
3719a0bf528SMauro Carvalho Chehab {
3729a0bf528SMauro Carvalho Chehab 	u16 nud = dib8000_read_word(state, 298);
3739a0bf528SMauro Carvalho Chehab 	nud |= (1 << 3) | (1 << 0);
3749a0bf528SMauro Carvalho Chehab 	dprintk("acquisition mode activated");
3759a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 298, nud);
3769a0bf528SMauro Carvalho Chehab }
3779a0bf528SMauro Carvalho Chehab static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
3789a0bf528SMauro Carvalho Chehab {
3799a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
3809a0bf528SMauro Carvalho Chehab 	u16 outreg, fifo_threshold, smo_mode, sram = 0x0205;	/* by default SDRAM deintlv is enabled */
3819a0bf528SMauro Carvalho Chehab 
382173a64cbSPatrick Boettcher 	state->output_mode = mode;
3839a0bf528SMauro Carvalho Chehab 	outreg = 0;
3849a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
3859a0bf528SMauro Carvalho Chehab 	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
3869a0bf528SMauro Carvalho Chehab 
3879a0bf528SMauro Carvalho Chehab 	dprintk("-I-	Setting output mode for demod %p to %d",
3889a0bf528SMauro Carvalho Chehab 			&state->fe[0], mode);
3899a0bf528SMauro Carvalho Chehab 
3909a0bf528SMauro Carvalho Chehab 	switch (mode) {
3919a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:	// STBs with parallel gated clock
3929a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10);	/* 0x0400 */
3939a0bf528SMauro Carvalho Chehab 		break;
3949a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK:	// STBs with parallel continues clock
3959a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (1 << 6);	/* 0x0440 */
3969a0bf528SMauro Carvalho Chehab 		break;
3979a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:	// STBs with serial input
3989a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (2 << 6) | (0 << 1);	/* 0x0482 */
3999a0bf528SMauro Carvalho Chehab 		break;
4009a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
4019a0bf528SMauro Carvalho Chehab 		if (state->cfg.hostbus_diversity) {
4029a0bf528SMauro Carvalho Chehab 			outreg = (1 << 10) | (4 << 6);	/* 0x0500 */
4039a0bf528SMauro Carvalho Chehab 			sram &= 0xfdff;
4049a0bf528SMauro Carvalho Chehab 		} else
4059a0bf528SMauro Carvalho Chehab 			sram |= 0x0c00;
4069a0bf528SMauro Carvalho Chehab 		break;
4079a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:	// e.g. USB feeding
4089a0bf528SMauro Carvalho Chehab 		smo_mode |= (3 << 1);
4099a0bf528SMauro Carvalho Chehab 		fifo_threshold = 512;
4109a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (5 << 6);
4119a0bf528SMauro Carvalho Chehab 		break;
4129a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:	// disable
4139a0bf528SMauro Carvalho Chehab 		outreg = 0;
4149a0bf528SMauro Carvalho Chehab 		break;
4159a0bf528SMauro Carvalho Chehab 
4169a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
4179a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (3 << 6);
4189a0bf528SMauro Carvalho Chehab 		dib8000_set_acquisition_mode(state);
4199a0bf528SMauro Carvalho Chehab 		break;
4209a0bf528SMauro Carvalho Chehab 
4219a0bf528SMauro Carvalho Chehab 	default:
4229a0bf528SMauro Carvalho Chehab 		dprintk("Unhandled output_mode passed to be set for demod %p",
4239a0bf528SMauro Carvalho Chehab 				&state->fe[0]);
4249a0bf528SMauro Carvalho Chehab 		return -EINVAL;
4259a0bf528SMauro Carvalho Chehab 	}
4269a0bf528SMauro Carvalho Chehab 
4279a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
4289a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
4299a0bf528SMauro Carvalho Chehab 
4309a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 299, smo_mode);
4319a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 300, fifo_threshold);	/* synchronous fread */
4329a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1286, outreg);
4339a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1291, sram);
4349a0bf528SMauro Carvalho Chehab 
4359a0bf528SMauro Carvalho Chehab 	return 0;
4369a0bf528SMauro Carvalho Chehab }
4379a0bf528SMauro Carvalho Chehab 
4389a0bf528SMauro Carvalho Chehab static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
4399a0bf528SMauro Carvalho Chehab {
4409a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
441173a64cbSPatrick Boettcher 	u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0;
4429a0bf528SMauro Carvalho Chehab 
443173a64cbSPatrick Boettcher 	dprintk("set diversity input to %i", onoff);
4449a0bf528SMauro Carvalho Chehab 	if (!state->differential_constellation) {
4459a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 272, 1 << 9);	//dvsy_off_lmod4 = 1
4469a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2);	// sync_enable = 1; comb_mode = 2
4479a0bf528SMauro Carvalho Chehab 	} else {
4489a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 272, 0);	//dvsy_off_lmod4 = 0
4499a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 273, sync_wait);	// sync_enable = 0; comb_mode = 0
4509a0bf528SMauro Carvalho Chehab 	}
4519a0bf528SMauro Carvalho Chehab 	state->diversity_onoff = onoff;
4529a0bf528SMauro Carvalho Chehab 
4539a0bf528SMauro Carvalho Chehab 	switch (onoff) {
4549a0bf528SMauro Carvalho Chehab 	case 0:		/* only use the internal way - not the diversity input */
4559a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 270, 1);
4569a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 271, 0);
4579a0bf528SMauro Carvalho Chehab 		break;
4589a0bf528SMauro Carvalho Chehab 	case 1:		/* both ways */
4599a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 270, 6);
4609a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 271, 6);
4619a0bf528SMauro Carvalho Chehab 		break;
4629a0bf528SMauro Carvalho Chehab 	case 2:		/* only the diversity input */
4639a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 270, 0);
4649a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 271, 1);
4659a0bf528SMauro Carvalho Chehab 		break;
4669a0bf528SMauro Carvalho Chehab 	}
467173a64cbSPatrick Boettcher 
468173a64cbSPatrick Boettcher 	if (state->revision == 0x8002) {
469173a64cbSPatrick Boettcher 		tmp = dib8000_read_word(state, 903);
470173a64cbSPatrick Boettcher 		dib8000_write_word(state, 903, tmp & ~(1 << 3));
471173a64cbSPatrick Boettcher 		msleep(30);
472173a64cbSPatrick Boettcher 		dib8000_write_word(state, 903, tmp | (1 << 3));
473173a64cbSPatrick Boettcher 	}
4749a0bf528SMauro Carvalho Chehab 	return 0;
4759a0bf528SMauro Carvalho Chehab }
4769a0bf528SMauro Carvalho Chehab 
4779a0bf528SMauro Carvalho Chehab static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
4789a0bf528SMauro Carvalho Chehab {
4799a0bf528SMauro Carvalho Chehab 	/* by default everything is going to be powered off */
4809a0bf528SMauro Carvalho Chehab 	u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
4819a0bf528SMauro Carvalho Chehab 		reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
4829a0bf528SMauro Carvalho Chehab 		reg_1280;
4839a0bf528SMauro Carvalho Chehab 
4849a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
4859a0bf528SMauro Carvalho Chehab 		reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
4869a0bf528SMauro Carvalho Chehab 	else
4879a0bf528SMauro Carvalho Chehab 		reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80;
4889a0bf528SMauro Carvalho Chehab 
4899a0bf528SMauro Carvalho Chehab 	/* now, depending on the requested mode, we power on */
4909a0bf528SMauro Carvalho Chehab 	switch (mode) {
4919a0bf528SMauro Carvalho Chehab 		/* power up everything in the demod */
4929a0bf528SMauro Carvalho Chehab 	case DIB8000_POWER_ALL:
4939a0bf528SMauro Carvalho Chehab 		reg_774 = 0x0000;
4949a0bf528SMauro Carvalho Chehab 		reg_775 = 0x0000;
4959a0bf528SMauro Carvalho Chehab 		reg_776 = 0x0000;
4969a0bf528SMauro Carvalho Chehab 		reg_900 &= 0xfffc;
4979a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090)
4989a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x00ff;
4999a0bf528SMauro Carvalho Chehab 		else
5009a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x707f;
5019a0bf528SMauro Carvalho Chehab 		break;
5029a0bf528SMauro Carvalho Chehab 	case DIB8000_POWER_INTERFACE_ONLY:
5039a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090)
5049a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x00ff;
5059a0bf528SMauro Carvalho Chehab 		else
5069a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0xfa7b;
5079a0bf528SMauro Carvalho Chehab 		break;
5089a0bf528SMauro Carvalho Chehab 	}
5099a0bf528SMauro Carvalho Chehab 
5109a0bf528SMauro Carvalho Chehab 	dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280);
5119a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 774, reg_774);
5129a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 775, reg_775);
5139a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 776, reg_776);
5149a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 900, reg_900);
5159a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1280, reg_1280);
5169a0bf528SMauro Carvalho Chehab }
5179a0bf528SMauro Carvalho Chehab 
5189a0bf528SMauro Carvalho Chehab static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
5199a0bf528SMauro Carvalho Chehab {
5209a0bf528SMauro Carvalho Chehab 	int ret = 0;
5219a0bf528SMauro Carvalho Chehab 	u16 reg, reg_907 = dib8000_read_word(state, 907);
5229a0bf528SMauro Carvalho Chehab 	u16 reg_908 = dib8000_read_word(state, 908);
5239a0bf528SMauro Carvalho Chehab 
5249a0bf528SMauro Carvalho Chehab 	switch (no) {
5259a0bf528SMauro Carvalho Chehab 	case DIBX000_SLOW_ADC_ON:
5269a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090) {
5279a0bf528SMauro Carvalho Chehab 			reg_908 |= (1 << 1) | (1 << 0);
5289a0bf528SMauro Carvalho Chehab 			ret |= dib8000_write_word(state, 908, reg_908);
5299a0bf528SMauro Carvalho Chehab 			reg_908 &= ~(1 << 1);
5309a0bf528SMauro Carvalho Chehab 		} else {
5319a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1925);
5329a0bf528SMauro Carvalho Chehab 			/* en_slowAdc = 1 & reset_sladc = 1 */
5339a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1925, reg |
5349a0bf528SMauro Carvalho Chehab 					(1<<4) | (1<<2));
5359a0bf528SMauro Carvalho Chehab 
5369a0bf528SMauro Carvalho Chehab 			/* read acces to make it works... strange ... */
5379a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1925);
5389a0bf528SMauro Carvalho Chehab 			msleep(20);
5399a0bf528SMauro Carvalho Chehab 			/* en_slowAdc = 1 & reset_sladc = 0 */
5409a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1925, reg & ~(1<<4));
5419a0bf528SMauro Carvalho Chehab 
5429a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 921) & ~((0x3 << 14)
5439a0bf528SMauro Carvalho Chehab 					| (0x3 << 12));
5449a0bf528SMauro Carvalho Chehab 			/* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ;
5459a0bf528SMauro Carvalho Chehab 			   (Vin2 = Vcm) */
5469a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 921, reg | (1 << 14)
5479a0bf528SMauro Carvalho Chehab 					| (3 << 12));
5489a0bf528SMauro Carvalho Chehab 		}
5499a0bf528SMauro Carvalho Chehab 		break;
5509a0bf528SMauro Carvalho Chehab 
5519a0bf528SMauro Carvalho Chehab 	case DIBX000_SLOW_ADC_OFF:
5529a0bf528SMauro Carvalho Chehab 		if (state->revision == 0x8090) {
5539a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1925);
5549a0bf528SMauro Carvalho Chehab 			/* reset_sladc = 1 en_slowAdc = 0 */
5559a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1925,
5569a0bf528SMauro Carvalho Chehab 					(reg & ~(1<<2)) | (1<<4));
5579a0bf528SMauro Carvalho Chehab 		}
5589a0bf528SMauro Carvalho Chehab 		reg_908 |= (1 << 1) | (1 << 0);
5599a0bf528SMauro Carvalho Chehab 		break;
5609a0bf528SMauro Carvalho Chehab 
5619a0bf528SMauro Carvalho Chehab 	case DIBX000_ADC_ON:
5629a0bf528SMauro Carvalho Chehab 		reg_907 &= 0x0fff;
5639a0bf528SMauro Carvalho Chehab 		reg_908 &= 0x0003;
5649a0bf528SMauro Carvalho Chehab 		break;
5659a0bf528SMauro Carvalho Chehab 
5669a0bf528SMauro Carvalho Chehab 	case DIBX000_ADC_OFF:	// leave the VBG voltage on
5679a0bf528SMauro Carvalho Chehab 		reg_907 |= (1 << 14) | (1 << 13) | (1 << 12);
5689a0bf528SMauro Carvalho Chehab 		reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
5699a0bf528SMauro Carvalho Chehab 		break;
5709a0bf528SMauro Carvalho Chehab 
5719a0bf528SMauro Carvalho Chehab 	case DIBX000_VBG_ENABLE:
5729a0bf528SMauro Carvalho Chehab 		reg_907 &= ~(1 << 15);
5739a0bf528SMauro Carvalho Chehab 		break;
5749a0bf528SMauro Carvalho Chehab 
5759a0bf528SMauro Carvalho Chehab 	case DIBX000_VBG_DISABLE:
5769a0bf528SMauro Carvalho Chehab 		reg_907 |= (1 << 15);
5779a0bf528SMauro Carvalho Chehab 		break;
5789a0bf528SMauro Carvalho Chehab 
5799a0bf528SMauro Carvalho Chehab 	default:
5809a0bf528SMauro Carvalho Chehab 		break;
5819a0bf528SMauro Carvalho Chehab 	}
5829a0bf528SMauro Carvalho Chehab 
5839a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 907, reg_907);
5849a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 908, reg_908);
5859a0bf528SMauro Carvalho Chehab 
5869a0bf528SMauro Carvalho Chehab 	return ret;
5879a0bf528SMauro Carvalho Chehab }
5889a0bf528SMauro Carvalho Chehab 
5899a0bf528SMauro Carvalho Chehab static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
5909a0bf528SMauro Carvalho Chehab {
5919a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
5929a0bf528SMauro Carvalho Chehab 	u32 timf;
5939a0bf528SMauro Carvalho Chehab 
5949a0bf528SMauro Carvalho Chehab 	if (bw == 0)
5959a0bf528SMauro Carvalho Chehab 		bw = 6000;
5969a0bf528SMauro Carvalho Chehab 
5979a0bf528SMauro Carvalho Chehab 	if (state->timf == 0) {
5989a0bf528SMauro Carvalho Chehab 		dprintk("using default timf");
5999a0bf528SMauro Carvalho Chehab 		timf = state->timf_default;
6009a0bf528SMauro Carvalho Chehab 	} else {
6019a0bf528SMauro Carvalho Chehab 		dprintk("using updated timf");
6029a0bf528SMauro Carvalho Chehab 		timf = state->timf;
6039a0bf528SMauro Carvalho Chehab 	}
6049a0bf528SMauro Carvalho Chehab 
6059a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
6069a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
6079a0bf528SMauro Carvalho Chehab 
6089a0bf528SMauro Carvalho Chehab 	return 0;
6099a0bf528SMauro Carvalho Chehab }
6109a0bf528SMauro Carvalho Chehab 
6119a0bf528SMauro Carvalho Chehab static int dib8000_sad_calib(struct dib8000_state *state)
6129a0bf528SMauro Carvalho Chehab {
613173a64cbSPatrick Boettcher 	u8 sad_sel = 3;
614173a64cbSPatrick Boettcher 
6159a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090) {
616173a64cbSPatrick Boettcher 		dib8000_write_word(state, 922, (sad_sel << 2));
617173a64cbSPatrick Boettcher 		dib8000_write_word(state, 923, 2048);
618173a64cbSPatrick Boettcher 
619173a64cbSPatrick Boettcher 		dib8000_write_word(state, 922, (sad_sel << 2) | 0x1);
620173a64cbSPatrick Boettcher 		dib8000_write_word(state, 922, (sad_sel << 2));
621173a64cbSPatrick Boettcher 	} else {
6229a0bf528SMauro Carvalho Chehab 		/* internal */
6239a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
624173a64cbSPatrick Boettcher 		dib8000_write_word(state, 924, 776);
6259a0bf528SMauro Carvalho Chehab 
6269a0bf528SMauro Carvalho Chehab 		/* do the calibration */
6279a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923, (1 << 0));
6289a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923, (0 << 0));
629173a64cbSPatrick Boettcher 	}
6309a0bf528SMauro Carvalho Chehab 
6319a0bf528SMauro Carvalho Chehab 	msleep(1);
6329a0bf528SMauro Carvalho Chehab 	return 0;
6339a0bf528SMauro Carvalho Chehab }
6349a0bf528SMauro Carvalho Chehab 
6359a0bf528SMauro Carvalho Chehab int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
6369a0bf528SMauro Carvalho Chehab {
6379a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
6389a0bf528SMauro Carvalho Chehab 	if (value > 4095)
6399a0bf528SMauro Carvalho Chehab 		value = 4095;
6409a0bf528SMauro Carvalho Chehab 	state->wbd_ref = value;
6419a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(state, 106, value);
6429a0bf528SMauro Carvalho Chehab }
6439a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_set_wbd_ref);
644173a64cbSPatrick Boettcher 
6459a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
6469a0bf528SMauro Carvalho Chehab {
6479a0bf528SMauro Carvalho Chehab 	dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
6489a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
6499a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23,
6509a0bf528SMauro Carvalho Chehab 				(u16) (((bw->internal * 1000) >> 16) & 0xffff));
6519a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24,
6529a0bf528SMauro Carvalho Chehab 				(u16) ((bw->internal * 1000) & 0xffff));
6539a0bf528SMauro Carvalho Chehab 	} else {
6549a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff));
6559a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24,
6569a0bf528SMauro Carvalho Chehab 				(u16) ((bw->internal  / 2 * 1000) & 0xffff));
6579a0bf528SMauro Carvalho Chehab 	}
6589a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
6599a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
6609a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
6619a0bf528SMauro Carvalho Chehab 
6629a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
6639a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 922, bw->sad_cfg);
6649a0bf528SMauro Carvalho Chehab }
6659a0bf528SMauro Carvalho Chehab 
6669a0bf528SMauro Carvalho Chehab static void dib8000_reset_pll(struct dib8000_state *state)
6679a0bf528SMauro Carvalho Chehab {
6689a0bf528SMauro Carvalho Chehab 	const struct dibx000_bandwidth_config *pll = state->cfg.pll;
6699a0bf528SMauro Carvalho Chehab 	u16 clk_cfg1, reg;
6709a0bf528SMauro Carvalho Chehab 
6719a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
6729a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 901,
6739a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv << 8) | (pll->pll_ratio << 0));
6749a0bf528SMauro Carvalho Chehab 
6759a0bf528SMauro Carvalho Chehab 		clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
6769a0bf528SMauro Carvalho Chehab 			(pll->bypclk_div << 5) | (pll->enable_refdiv << 4) |
6779a0bf528SMauro Carvalho Chehab 			(1 << 3) | (pll->pll_range << 1) |
6789a0bf528SMauro Carvalho Chehab 			(pll->pll_reset << 0);
6799a0bf528SMauro Carvalho Chehab 
6809a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 902, clk_cfg1);
6819a0bf528SMauro Carvalho Chehab 		clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
6829a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 902, clk_cfg1);
6839a0bf528SMauro Carvalho Chehab 
6849a0bf528SMauro Carvalho Chehab 		dprintk("clk_cfg1: 0x%04x", clk_cfg1);
6859a0bf528SMauro Carvalho Chehab 
6869a0bf528SMauro Carvalho Chehab 		/* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
6879a0bf528SMauro Carvalho Chehab 		if (state->cfg.pll->ADClkSrc == 0)
6889a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904,
6899a0bf528SMauro Carvalho Chehab 					(0 << 15) | (0 << 12) | (0 << 10) |
6909a0bf528SMauro Carvalho Chehab 					(pll->modulo << 8) |
6919a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
6929a0bf528SMauro Carvalho Chehab 		else if (state->cfg.refclksel != 0)
6939a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
6949a0bf528SMauro Carvalho Chehab 					((state->cfg.refclksel & 0x3) << 10) |
6959a0bf528SMauro Carvalho Chehab 					(pll->modulo << 8) |
6969a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
6979a0bf528SMauro Carvalho Chehab 		else
6989a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
6999a0bf528SMauro Carvalho Chehab 					(3 << 10) | (pll->modulo << 8) |
7009a0bf528SMauro Carvalho Chehab 					(pll->ADClkSrc << 7) | (0 << 1));
7019a0bf528SMauro Carvalho Chehab 	} else {
7029a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1856, (!pll->pll_reset<<13) |
7039a0bf528SMauro Carvalho Chehab 				(pll->pll_range<<12) | (pll->pll_ratio<<6) |
7049a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv));
7059a0bf528SMauro Carvalho Chehab 
7069a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 1857);
7079a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15));
7089a0bf528SMauro Carvalho Chehab 
7099a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */
7109a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1858, reg | 1);
7119a0bf528SMauro Carvalho Chehab 
7129a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 904, (pll->modulo << 8));
7139a0bf528SMauro Carvalho Chehab 	}
7149a0bf528SMauro Carvalho Chehab 
7159a0bf528SMauro Carvalho Chehab 	dib8000_reset_pll_common(state, pll);
7169a0bf528SMauro Carvalho Chehab }
7179a0bf528SMauro Carvalho Chehab 
7189a0bf528SMauro Carvalho Chehab int dib8000_update_pll(struct dvb_frontend *fe,
719173a64cbSPatrick Boettcher 		struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
7209a0bf528SMauro Carvalho Chehab {
7219a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
7229a0bf528SMauro Carvalho Chehab 	u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
723173a64cbSPatrick Boettcher 	u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ;
7249a0bf528SMauro Carvalho Chehab 	u32 internal, xtal;
7259a0bf528SMauro Carvalho Chehab 
7269a0bf528SMauro Carvalho Chehab 	/* get back old values */
7279a0bf528SMauro Carvalho Chehab 	prediv = reg_1856 & 0x3f;
7289a0bf528SMauro Carvalho Chehab 	loopdiv = (reg_1856 >> 6) & 0x3f;
7299a0bf528SMauro Carvalho Chehab 
730173a64cbSPatrick Boettcher 	if ((pll == NULL) || (pll->pll_prediv == prediv &&
731173a64cbSPatrick Boettcher 				pll->pll_ratio == loopdiv))
732173a64cbSPatrick Boettcher 		return -EINVAL;
733173a64cbSPatrick Boettcher 
7349a0bf528SMauro Carvalho Chehab 	dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
735173a64cbSPatrick Boettcher 	if (state->revision == 0x8090) {
7369a0bf528SMauro Carvalho Chehab 		reg_1856 &= 0xf000;
7379a0bf528SMauro Carvalho Chehab 		reg_1857 = dib8000_read_word(state, 1857);
7389a0bf528SMauro Carvalho Chehab 		/* disable PLL */
7399a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15));
7409a0bf528SMauro Carvalho Chehab 
7419a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1856, reg_1856 |
7429a0bf528SMauro Carvalho Chehab 				((pll->pll_ratio & 0x3f) << 6) |
7439a0bf528SMauro Carvalho Chehab 				(pll->pll_prediv & 0x3f));
7449a0bf528SMauro Carvalho Chehab 
7459a0bf528SMauro Carvalho Chehab 		/* write new system clk into P_sec_len */
7469a0bf528SMauro Carvalho Chehab 		internal = dib8000_read32(state, 23) / 1000;
7479a0bf528SMauro Carvalho Chehab 		dprintk("Old Internal = %d", internal);
7489a0bf528SMauro Carvalho Chehab 		xtal = 2 * (internal / loopdiv) * prediv;
7499a0bf528SMauro Carvalho Chehab 		internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio;
7509a0bf528SMauro Carvalho Chehab 		dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d", xtal, internal/1000, internal/2000, internal/8000);
7519a0bf528SMauro Carvalho Chehab 		dprintk("New Internal = %d", internal);
7529a0bf528SMauro Carvalho Chehab 
7539a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 23,
7549a0bf528SMauro Carvalho Chehab 				(u16) (((internal / 2) >> 16) & 0xffff));
7559a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff));
7569a0bf528SMauro Carvalho Chehab 		/* enable PLL */
7579a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1857, reg_1857 | (1 << 15));
7589a0bf528SMauro Carvalho Chehab 
7599a0bf528SMauro Carvalho Chehab 		while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1)
7609a0bf528SMauro Carvalho Chehab 			dprintk("Waiting for PLL to lock");
7619a0bf528SMauro Carvalho Chehab 
7629a0bf528SMauro Carvalho Chehab 		/* verify */
7639a0bf528SMauro Carvalho Chehab 		reg_1856 = dib8000_read_word(state, 1856);
7649a0bf528SMauro Carvalho Chehab 		dprintk("PLL Updated with prediv = %d and loopdiv = %d",
7659a0bf528SMauro Carvalho Chehab 				reg_1856&0x3f, (reg_1856>>6)&0x3f);
766173a64cbSPatrick Boettcher 	} else {
767173a64cbSPatrick Boettcher 		if (bw != state->current_demod_bw) {
768173a64cbSPatrick Boettcher 			/** Bandwidth change => force PLL update **/
769173a64cbSPatrick Boettcher 			dprintk("PLL: Bandwidth Change %d MHz -> %d MHz (prediv: %d->%d)", state->current_demod_bw / 1000, bw / 1000, oldprediv, state->cfg.pll->pll_prediv);
770173a64cbSPatrick Boettcher 
771173a64cbSPatrick Boettcher 			if (state->cfg.pll->pll_prediv != oldprediv) {
772173a64cbSPatrick Boettcher 				/** Full PLL change only if prediv is changed **/
773173a64cbSPatrick Boettcher 
774173a64cbSPatrick Boettcher 				/** full update => bypass and reconfigure **/
775173a64cbSPatrick Boettcher 				dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio);
776173a64cbSPatrick Boettcher 				dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */
777173a64cbSPatrick Boettcher 				dib8000_reset_pll(state);
778173a64cbSPatrick Boettcher 				dib8000_write_word(state, 898, 0x0004); /* sad */
779173a64cbSPatrick Boettcher 			} else
780173a64cbSPatrick Boettcher 				ratio = state->cfg.pll->pll_ratio;
781173a64cbSPatrick Boettcher 
782173a64cbSPatrick Boettcher 			state->current_demod_bw = bw;
783173a64cbSPatrick Boettcher 		}
784173a64cbSPatrick Boettcher 
785173a64cbSPatrick Boettcher 		if (ratio != 0) {
786173a64cbSPatrick Boettcher 			/** ratio update => only change ratio **/
787173a64cbSPatrick Boettcher 			dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio);
788173a64cbSPatrick Boettcher 			dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
789173a64cbSPatrick Boettcher 		}
790173a64cbSPatrick Boettcher }
7919a0bf528SMauro Carvalho Chehab 
7929a0bf528SMauro Carvalho Chehab 	return 0;
7939a0bf528SMauro Carvalho Chehab }
7949a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_update_pll);
7959a0bf528SMauro Carvalho Chehab 
7969a0bf528SMauro Carvalho Chehab 
7979a0bf528SMauro Carvalho Chehab static int dib8000_reset_gpio(struct dib8000_state *st)
7989a0bf528SMauro Carvalho Chehab {
7999a0bf528SMauro Carvalho Chehab 	/* reset the GPIOs */
8009a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
8019a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1030, st->cfg.gpio_val);
8029a0bf528SMauro Carvalho Chehab 
8039a0bf528SMauro Carvalho Chehab 	/* TODO 782 is P_gpio_od */
8049a0bf528SMauro Carvalho Chehab 
8059a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
8069a0bf528SMauro Carvalho Chehab 
8079a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
8089a0bf528SMauro Carvalho Chehab 	return 0;
8099a0bf528SMauro Carvalho Chehab }
8109a0bf528SMauro Carvalho Chehab 
8119a0bf528SMauro Carvalho Chehab static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
8129a0bf528SMauro Carvalho Chehab {
8139a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir = dib8000_read_word(st, 1029);
8149a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir &= ~(1 << num);	/* reset the direction bit */
8159a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
8169a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1029, st->cfg.gpio_dir);
8179a0bf528SMauro Carvalho Chehab 
8189a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val = dib8000_read_word(st, 1030);
8199a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val &= ~(1 << num);	/* reset the direction bit */
8209a0bf528SMauro Carvalho Chehab 	st->cfg.gpio_val |= (val & 0x01) << num;	/* set the new value */
8219a0bf528SMauro Carvalho Chehab 	dib8000_write_word(st, 1030, st->cfg.gpio_val);
8229a0bf528SMauro Carvalho Chehab 
8239a0bf528SMauro Carvalho Chehab 	dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val);
8249a0bf528SMauro Carvalho Chehab 
8259a0bf528SMauro Carvalho Chehab 	return 0;
8269a0bf528SMauro Carvalho Chehab }
8279a0bf528SMauro Carvalho Chehab 
8289a0bf528SMauro Carvalho Chehab int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
8299a0bf528SMauro Carvalho Chehab {
8309a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
8319a0bf528SMauro Carvalho Chehab 	return dib8000_cfg_gpio(state, num, dir, val);
8329a0bf528SMauro Carvalho Chehab }
8339a0bf528SMauro Carvalho Chehab 
8349a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_set_gpio);
8359a0bf528SMauro Carvalho Chehab static const u16 dib8000_defaults[] = {
8369a0bf528SMauro Carvalho Chehab 	/* auto search configuration - lock0 by default waiting
8379a0bf528SMauro Carvalho Chehab 	 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
8389a0bf528SMauro Carvalho Chehab 	3, 7,
8399a0bf528SMauro Carvalho Chehab 	0x0004,
8409a0bf528SMauro Carvalho Chehab 	0x0400,
8419a0bf528SMauro Carvalho Chehab 	0x0814,
8429a0bf528SMauro Carvalho Chehab 
8439a0bf528SMauro Carvalho Chehab 	12, 11,
8449a0bf528SMauro Carvalho Chehab 	0x001b,
8459a0bf528SMauro Carvalho Chehab 	0x7740,
8469a0bf528SMauro Carvalho Chehab 	0x005b,
8479a0bf528SMauro Carvalho Chehab 	0x8d80,
8489a0bf528SMauro Carvalho Chehab 	0x01c9,
8499a0bf528SMauro Carvalho Chehab 	0xc380,
8509a0bf528SMauro Carvalho Chehab 	0x0000,
8519a0bf528SMauro Carvalho Chehab 	0x0080,
8529a0bf528SMauro Carvalho Chehab 	0x0000,
8539a0bf528SMauro Carvalho Chehab 	0x0090,
8549a0bf528SMauro Carvalho Chehab 	0x0001,
8559a0bf528SMauro Carvalho Chehab 	0xd4c0,
8569a0bf528SMauro Carvalho Chehab 
8579a0bf528SMauro Carvalho Chehab 	/*1, 32,
8589a0bf528SMauro Carvalho Chehab 		0x6680 // P_corm_thres Lock algorithms configuration */
8599a0bf528SMauro Carvalho Chehab 
8609a0bf528SMauro Carvalho Chehab 	11, 80,			/* set ADC level to -16 */
8619a0bf528SMauro Carvalho Chehab 	(1 << 13) - 825 - 117,
8629a0bf528SMauro Carvalho Chehab 	(1 << 13) - 837 - 117,
8639a0bf528SMauro Carvalho Chehab 	(1 << 13) - 811 - 117,
8649a0bf528SMauro Carvalho Chehab 	(1 << 13) - 766 - 117,
8659a0bf528SMauro Carvalho Chehab 	(1 << 13) - 737 - 117,
8669a0bf528SMauro Carvalho Chehab 	(1 << 13) - 693 - 117,
8679a0bf528SMauro Carvalho Chehab 	(1 << 13) - 648 - 117,
8689a0bf528SMauro Carvalho Chehab 	(1 << 13) - 619 - 117,
8699a0bf528SMauro Carvalho Chehab 	(1 << 13) - 575 - 117,
8709a0bf528SMauro Carvalho Chehab 	(1 << 13) - 531 - 117,
8719a0bf528SMauro Carvalho Chehab 	(1 << 13) - 501 - 117,
8729a0bf528SMauro Carvalho Chehab 
8739a0bf528SMauro Carvalho Chehab 	4, 108,
8749a0bf528SMauro Carvalho Chehab 	0,
8759a0bf528SMauro Carvalho Chehab 	0,
8769a0bf528SMauro Carvalho Chehab 	0,
8779a0bf528SMauro Carvalho Chehab 	0,
8789a0bf528SMauro Carvalho Chehab 
8799a0bf528SMauro Carvalho Chehab 	1, 175,
8809a0bf528SMauro Carvalho Chehab 	0x0410,
8819a0bf528SMauro Carvalho Chehab 	1, 179,
8829a0bf528SMauro Carvalho Chehab 	8192,			// P_fft_nb_to_cut
8839a0bf528SMauro Carvalho Chehab 
8849a0bf528SMauro Carvalho Chehab 	6, 181,
8859a0bf528SMauro Carvalho Chehab 	0x2800,			// P_coff_corthres_ ( 2k 4k 8k ) 0x2800
8869a0bf528SMauro Carvalho Chehab 	0x2800,
8879a0bf528SMauro Carvalho Chehab 	0x2800,
8889a0bf528SMauro Carvalho Chehab 	0x2800,			// P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
8899a0bf528SMauro Carvalho Chehab 	0x2800,
8909a0bf528SMauro Carvalho Chehab 	0x2800,
8919a0bf528SMauro Carvalho Chehab 
8929a0bf528SMauro Carvalho Chehab 	2, 193,
8939a0bf528SMauro Carvalho Chehab 	0x0666,			// P_pha3_thres
8949a0bf528SMauro Carvalho Chehab 	0x0000,			// P_cti_use_cpe, P_cti_use_prog
8959a0bf528SMauro Carvalho Chehab 
8969a0bf528SMauro Carvalho Chehab 	2, 205,
8979a0bf528SMauro Carvalho Chehab 	0x200f,			// P_cspu_regul, P_cspu_win_cut
8989a0bf528SMauro Carvalho Chehab 	0x000f,			// P_des_shift_work
8999a0bf528SMauro Carvalho Chehab 
9009a0bf528SMauro Carvalho Chehab 	5, 215,
9019a0bf528SMauro Carvalho Chehab 	0x023d,			// P_adp_regul_cnt
9029a0bf528SMauro Carvalho Chehab 	0x00a4,			// P_adp_noise_cnt
9039a0bf528SMauro Carvalho Chehab 	0x00a4,			// P_adp_regul_ext
9049a0bf528SMauro Carvalho Chehab 	0x7ff0,			// P_adp_noise_ext
9059a0bf528SMauro Carvalho Chehab 	0x3ccc,			// P_adp_fil
9069a0bf528SMauro Carvalho Chehab 
9079a0bf528SMauro Carvalho Chehab 	1, 230,
9089a0bf528SMauro Carvalho Chehab 	0x0000,			// P_2d_byp_ti_num
9099a0bf528SMauro Carvalho Chehab 
9109a0bf528SMauro Carvalho Chehab 	1, 263,
9119a0bf528SMauro Carvalho Chehab 	0x800,			//P_equal_thres_wgn
9129a0bf528SMauro Carvalho Chehab 
9139a0bf528SMauro Carvalho Chehab 	1, 268,
9149a0bf528SMauro Carvalho Chehab 	(2 << 9) | 39,		// P_equal_ctrl_synchro, P_equal_speedmode
9159a0bf528SMauro Carvalho Chehab 
9169a0bf528SMauro Carvalho Chehab 	1, 270,
9179a0bf528SMauro Carvalho Chehab 	0x0001,			// P_div_lock0_wait
9189a0bf528SMauro Carvalho Chehab 	1, 285,
9199a0bf528SMauro Carvalho Chehab 	0x0020,			//p_fec_
9209a0bf528SMauro Carvalho Chehab 	1, 299,
9219a0bf528SMauro Carvalho Chehab 	0x0062,			/* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */
9229a0bf528SMauro Carvalho Chehab 
9239a0bf528SMauro Carvalho Chehab 	1, 338,
9249a0bf528SMauro Carvalho Chehab 	(1 << 12) |		// P_ctrl_corm_thres4pre_freq_inh=1
9259a0bf528SMauro Carvalho Chehab 		(1 << 10) |
9269a0bf528SMauro Carvalho Chehab 		(0 << 9) |		/* P_ctrl_pre_freq_inh=0 */
9279a0bf528SMauro Carvalho Chehab 		(3 << 5) |		/* P_ctrl_pre_freq_step=3 */
9289a0bf528SMauro Carvalho Chehab 		(1 << 0),		/* P_pre_freq_win_len=1 */
9299a0bf528SMauro Carvalho Chehab 
9309a0bf528SMauro Carvalho Chehab 	0,
9319a0bf528SMauro Carvalho Chehab };
9329a0bf528SMauro Carvalho Chehab 
9339a0bf528SMauro Carvalho Chehab static u16 dib8000_identify(struct i2c_device *client)
9349a0bf528SMauro Carvalho Chehab {
9359a0bf528SMauro Carvalho Chehab 	u16 value;
9369a0bf528SMauro Carvalho Chehab 
9379a0bf528SMauro Carvalho Chehab 	//because of glitches sometimes
9389a0bf528SMauro Carvalho Chehab 	value = dib8000_i2c_read16(client, 896);
9399a0bf528SMauro Carvalho Chehab 
9409a0bf528SMauro Carvalho Chehab 	if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
9419a0bf528SMauro Carvalho Chehab 		dprintk("wrong Vendor ID (read=0x%x)", value);
9429a0bf528SMauro Carvalho Chehab 		return 0;
9439a0bf528SMauro Carvalho Chehab 	}
9449a0bf528SMauro Carvalho Chehab 
9459a0bf528SMauro Carvalho Chehab 	value = dib8000_i2c_read16(client, 897);
9469a0bf528SMauro Carvalho Chehab 	if (value != 0x8000 && value != 0x8001 &&
9479a0bf528SMauro Carvalho Chehab 			value != 0x8002 && value != 0x8090) {
9489a0bf528SMauro Carvalho Chehab 		dprintk("wrong Device ID (%x)", value);
9499a0bf528SMauro Carvalho Chehab 		return 0;
9509a0bf528SMauro Carvalho Chehab 	}
9519a0bf528SMauro Carvalho Chehab 
9529a0bf528SMauro Carvalho Chehab 	switch (value) {
9539a0bf528SMauro Carvalho Chehab 	case 0x8000:
9549a0bf528SMauro Carvalho Chehab 		dprintk("found DiB8000A");
9559a0bf528SMauro Carvalho Chehab 		break;
9569a0bf528SMauro Carvalho Chehab 	case 0x8001:
9579a0bf528SMauro Carvalho Chehab 		dprintk("found DiB8000B");
9589a0bf528SMauro Carvalho Chehab 		break;
9599a0bf528SMauro Carvalho Chehab 	case 0x8002:
9609a0bf528SMauro Carvalho Chehab 		dprintk("found DiB8000C");
9619a0bf528SMauro Carvalho Chehab 		break;
9629a0bf528SMauro Carvalho Chehab 	case 0x8090:
9639a0bf528SMauro Carvalho Chehab 		dprintk("found DiB8096P");
9649a0bf528SMauro Carvalho Chehab 		break;
9659a0bf528SMauro Carvalho Chehab 	}
9669a0bf528SMauro Carvalho Chehab 	return value;
9679a0bf528SMauro Carvalho Chehab }
9689a0bf528SMauro Carvalho Chehab 
9699a0bf528SMauro Carvalho Chehab static int dib8000_reset(struct dvb_frontend *fe)
9709a0bf528SMauro Carvalho Chehab {
9719a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
9729a0bf528SMauro Carvalho Chehab 
9739a0bf528SMauro Carvalho Chehab 	if ((state->revision = dib8000_identify(&state->i2c)) == 0)
9749a0bf528SMauro Carvalho Chehab 		return -EINVAL;
9759a0bf528SMauro Carvalho Chehab 
9769a0bf528SMauro Carvalho Chehab 	/* sram lead in, rdy */
9779a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
9789a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1287, 0x0003);
9799a0bf528SMauro Carvalho Chehab 
9809a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8000)
9819a0bf528SMauro Carvalho Chehab 		dprintk("error : dib8000 MA not supported");
9829a0bf528SMauro Carvalho Chehab 
9839a0bf528SMauro Carvalho Chehab 	dibx000_reset_i2c_master(&state->i2c_master);
9849a0bf528SMauro Carvalho Chehab 
9859a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
9869a0bf528SMauro Carvalho Chehab 
9879a0bf528SMauro Carvalho Chehab 	/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
988173a64cbSPatrick Boettcher 	dib8000_set_adc_state(state, DIBX000_ADC_OFF);
9899a0bf528SMauro Carvalho Chehab 
9909a0bf528SMauro Carvalho Chehab 	/* restart all parts */
9919a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0xffff);
9929a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 771, 0xffff);
9939a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 772, 0xfffc);
9949a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
9959a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1280, 0x0045);
9969a0bf528SMauro Carvalho Chehab 	else
9979a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1280, 0x004d);
9989a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1281, 0x000c);
9999a0bf528SMauro Carvalho Chehab 
10009a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0000);
10019a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 771, 0x0000);
10029a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 772, 0x0000);
10039a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 898, 0x0004);	// sad
10049a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1280, 0x0000);
10059a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1281, 0x0000);
10069a0bf528SMauro Carvalho Chehab 
10079a0bf528SMauro Carvalho Chehab 	/* drives */
10089a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090) {
10099a0bf528SMauro Carvalho Chehab 		if (state->cfg.drives)
10109a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 906, state->cfg.drives);
10119a0bf528SMauro Carvalho Chehab 		else {
10129a0bf528SMauro Carvalho Chehab 			dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
10139a0bf528SMauro Carvalho Chehab 			/* min drive SDRAM - not optimal - adjust */
10149a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 906, 0x2d98);
10159a0bf528SMauro Carvalho Chehab 		}
10169a0bf528SMauro Carvalho Chehab 	}
10179a0bf528SMauro Carvalho Chehab 
10189a0bf528SMauro Carvalho Chehab 	dib8000_reset_pll(state);
10199a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
10209a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 898, 0x0004);
10219a0bf528SMauro Carvalho Chehab 
10229a0bf528SMauro Carvalho Chehab 	if (dib8000_reset_gpio(state) != 0)
10239a0bf528SMauro Carvalho Chehab 		dprintk("GPIO reset was not successful.");
10249a0bf528SMauro Carvalho Chehab 
10259a0bf528SMauro Carvalho Chehab 	if ((state->revision != 0x8090) &&
10269a0bf528SMauro Carvalho Chehab 			(dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
10279a0bf528SMauro Carvalho Chehab 		dprintk("OUTPUT_MODE could not be resetted.");
10289a0bf528SMauro Carvalho Chehab 
10299a0bf528SMauro Carvalho Chehab 	state->current_agc = NULL;
10309a0bf528SMauro Carvalho Chehab 
10319a0bf528SMauro Carvalho Chehab 	// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
10329a0bf528SMauro Carvalho Chehab 	/* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
10339a0bf528SMauro Carvalho Chehab 	if (state->cfg.pll->ifreq == 0)
10349a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 40, 0x0755);	/* P_iqc_corr_inh = 0 enable IQcorr block */
10359a0bf528SMauro Carvalho Chehab 	else
10369a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 40, 0x1f55);	/* P_iqc_corr_inh = 1 disable IQcorr block */
10379a0bf528SMauro Carvalho Chehab 
10389a0bf528SMauro Carvalho Chehab 	{
10399a0bf528SMauro Carvalho Chehab 		u16 l = 0, r;
10409a0bf528SMauro Carvalho Chehab 		const u16 *n;
10419a0bf528SMauro Carvalho Chehab 		n = dib8000_defaults;
10429a0bf528SMauro Carvalho Chehab 		l = *n++;
10439a0bf528SMauro Carvalho Chehab 		while (l) {
10449a0bf528SMauro Carvalho Chehab 			r = *n++;
10459a0bf528SMauro Carvalho Chehab 			do {
10469a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, r, *n++);
10479a0bf528SMauro Carvalho Chehab 				r++;
10489a0bf528SMauro Carvalho Chehab 			} while (--l);
10499a0bf528SMauro Carvalho Chehab 			l = *n++;
10509a0bf528SMauro Carvalho Chehab 		}
10519a0bf528SMauro Carvalho Chehab 	}
1052173a64cbSPatrick Boettcher 
10539a0bf528SMauro Carvalho Chehab 	state->isdbt_cfg_loaded = 0;
10549a0bf528SMauro Carvalho Chehab 
10559a0bf528SMauro Carvalho Chehab 	//div_cfg override for special configs
1056173a64cbSPatrick Boettcher 	if ((state->revision != 8090) && (state->cfg.div_cfg != 0))
10579a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 903, state->cfg.div_cfg);
10589a0bf528SMauro Carvalho Chehab 
10599a0bf528SMauro Carvalho Chehab 	/* unforce divstr regardless whether i2c enumeration was done or not */
10609a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
10619a0bf528SMauro Carvalho Chehab 
10629a0bf528SMauro Carvalho Chehab 	dib8000_set_bandwidth(fe, 6000);
10639a0bf528SMauro Carvalho Chehab 
10649a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
10659a0bf528SMauro Carvalho Chehab 	dib8000_sad_calib(state);
1066173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
10679a0bf528SMauro Carvalho Chehab 		dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
1068173a64cbSPatrick Boettcher 
1069173a64cbSPatrick Boettcher 	/* ber_rs_len = 3 */
1070173a64cbSPatrick Boettcher 	dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));
10719a0bf528SMauro Carvalho Chehab 
10729a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
10739a0bf528SMauro Carvalho Chehab 
10749a0bf528SMauro Carvalho Chehab 	return 0;
10759a0bf528SMauro Carvalho Chehab }
10769a0bf528SMauro Carvalho Chehab 
10779a0bf528SMauro Carvalho Chehab static void dib8000_restart_agc(struct dib8000_state *state)
10789a0bf528SMauro Carvalho Chehab {
10799a0bf528SMauro Carvalho Chehab 	// P_restart_iqc & P_restart_agc
10809a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0a00);
10819a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 770, 0x0000);
10829a0bf528SMauro Carvalho Chehab }
10839a0bf528SMauro Carvalho Chehab 
10849a0bf528SMauro Carvalho Chehab static int dib8000_update_lna(struct dib8000_state *state)
10859a0bf528SMauro Carvalho Chehab {
10869a0bf528SMauro Carvalho Chehab 	u16 dyn_gain;
10879a0bf528SMauro Carvalho Chehab 
10889a0bf528SMauro Carvalho Chehab 	if (state->cfg.update_lna) {
10899a0bf528SMauro Carvalho Chehab 		// read dyn_gain here (because it is demod-dependent and not tuner)
10909a0bf528SMauro Carvalho Chehab 		dyn_gain = dib8000_read_word(state, 390);
10919a0bf528SMauro Carvalho Chehab 
10929a0bf528SMauro Carvalho Chehab 		if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
10939a0bf528SMauro Carvalho Chehab 			dib8000_restart_agc(state);
10949a0bf528SMauro Carvalho Chehab 			return 1;
10959a0bf528SMauro Carvalho Chehab 		}
10969a0bf528SMauro Carvalho Chehab 	}
10979a0bf528SMauro Carvalho Chehab 	return 0;
10989a0bf528SMauro Carvalho Chehab }
10999a0bf528SMauro Carvalho Chehab 
11009a0bf528SMauro Carvalho Chehab static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
11019a0bf528SMauro Carvalho Chehab {
11029a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *agc = NULL;
11039a0bf528SMauro Carvalho Chehab 	int i;
11049a0bf528SMauro Carvalho Chehab 	u16 reg;
11059a0bf528SMauro Carvalho Chehab 
11069a0bf528SMauro Carvalho Chehab 	if (state->current_band == band && state->current_agc != NULL)
11079a0bf528SMauro Carvalho Chehab 		return 0;
11089a0bf528SMauro Carvalho Chehab 	state->current_band = band;
11099a0bf528SMauro Carvalho Chehab 
11109a0bf528SMauro Carvalho Chehab 	for (i = 0; i < state->cfg.agc_config_count; i++)
11119a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc[i].band_caps & band) {
11129a0bf528SMauro Carvalho Chehab 			agc = &state->cfg.agc[i];
11139a0bf528SMauro Carvalho Chehab 			break;
11149a0bf528SMauro Carvalho Chehab 		}
11159a0bf528SMauro Carvalho Chehab 
11169a0bf528SMauro Carvalho Chehab 	if (agc == NULL) {
11179a0bf528SMauro Carvalho Chehab 		dprintk("no valid AGC configuration found for band 0x%02x", band);
11189a0bf528SMauro Carvalho Chehab 		return -EINVAL;
11199a0bf528SMauro Carvalho Chehab 	}
11209a0bf528SMauro Carvalho Chehab 
11219a0bf528SMauro Carvalho Chehab 	state->current_agc = agc;
11229a0bf528SMauro Carvalho Chehab 
11239a0bf528SMauro Carvalho Chehab 	/* AGC */
11249a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 76, agc->setup);
11259a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 77, agc->inv_gain);
11269a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 78, agc->time_stabiliz);
11279a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
11289a0bf528SMauro Carvalho Chehab 
11299a0bf528SMauro Carvalho Chehab 	// Demod AGC loop configuration
11309a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
11319a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
11329a0bf528SMauro Carvalho Chehab 
11339a0bf528SMauro Carvalho Chehab 	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
11349a0bf528SMauro Carvalho Chehab 		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
11359a0bf528SMauro Carvalho Chehab 
11369a0bf528SMauro Carvalho Chehab 	/* AGC continued */
11379a0bf528SMauro Carvalho Chehab 	if (state->wbd_ref != 0)
11389a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 106, state->wbd_ref);
11399a0bf528SMauro Carvalho Chehab 	else			// use default
11409a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 106, agc->wbd_ref);
11419a0bf528SMauro Carvalho Chehab 
11429a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090) {
11439a0bf528SMauro Carvalho Chehab 		reg = dib8000_read_word(state, 922) & (0x3 << 2);
11449a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
11459a0bf528SMauro Carvalho Chehab 	}
11469a0bf528SMauro Carvalho Chehab 
11479a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
11489a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 108, agc->agc1_max);
11499a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 109, agc->agc1_min);
11509a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 110, agc->agc2_max);
11519a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 111, agc->agc2_min);
11529a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
11539a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
11549a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
11559a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
11569a0bf528SMauro Carvalho Chehab 
11579a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 75, agc->agc1_pt3);
11589a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
11599a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 923,
11609a0bf528SMauro Carvalho Chehab 				(dib8000_read_word(state, 923) & 0xffe3) |
11619a0bf528SMauro Carvalho Chehab 				(agc->wbd_inv << 4) | (agc->wbd_sel << 2));
11629a0bf528SMauro Carvalho Chehab 
11639a0bf528SMauro Carvalho Chehab 	return 0;
11649a0bf528SMauro Carvalho Chehab }
11659a0bf528SMauro Carvalho Chehab 
11669a0bf528SMauro Carvalho Chehab void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
11679a0bf528SMauro Carvalho Chehab {
11689a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
11699a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_ADC_ON);
11709a0bf528SMauro Carvalho Chehab 	dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
11719a0bf528SMauro Carvalho Chehab }
11729a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_pwm_agc_reset);
11739a0bf528SMauro Carvalho Chehab 
11749a0bf528SMauro Carvalho Chehab static int dib8000_agc_soft_split(struct dib8000_state *state)
11759a0bf528SMauro Carvalho Chehab {
11769a0bf528SMauro Carvalho Chehab 	u16 agc, split_offset;
11779a0bf528SMauro Carvalho Chehab 
11789a0bf528SMauro Carvalho Chehab 	if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
11799a0bf528SMauro Carvalho Chehab 		return FE_CALLBACK_TIME_NEVER;
11809a0bf528SMauro Carvalho Chehab 
11819a0bf528SMauro Carvalho Chehab 	// n_agc_global
11829a0bf528SMauro Carvalho Chehab 	agc = dib8000_read_word(state, 390);
11839a0bf528SMauro Carvalho Chehab 
11849a0bf528SMauro Carvalho Chehab 	if (agc > state->current_agc->split.min_thres)
11859a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.min;
11869a0bf528SMauro Carvalho Chehab 	else if (agc < state->current_agc->split.max_thres)
11879a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.max;
11889a0bf528SMauro Carvalho Chehab 	else
11899a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.max *
11909a0bf528SMauro Carvalho Chehab 			(agc - state->current_agc->split.min_thres) /
11919a0bf528SMauro Carvalho Chehab 			(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
11929a0bf528SMauro Carvalho Chehab 
11939a0bf528SMauro Carvalho Chehab 	dprintk("AGC split_offset: %d", split_offset);
11949a0bf528SMauro Carvalho Chehab 
11959a0bf528SMauro Carvalho Chehab 	// P_agc_force_split and P_agc_split_offset
11969a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
11979a0bf528SMauro Carvalho Chehab 	return 5000;
11989a0bf528SMauro Carvalho Chehab }
11999a0bf528SMauro Carvalho Chehab 
12009a0bf528SMauro Carvalho Chehab static int dib8000_agc_startup(struct dvb_frontend *fe)
12019a0bf528SMauro Carvalho Chehab {
12029a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
12039a0bf528SMauro Carvalho Chehab 	enum frontend_tune_state *tune_state = &state->tune_state;
12049a0bf528SMauro Carvalho Chehab 	int ret = 0;
12059a0bf528SMauro Carvalho Chehab 	u16 reg, upd_demod_gain_period = 0x8000;
12069a0bf528SMauro Carvalho Chehab 
12079a0bf528SMauro Carvalho Chehab 	switch (*tune_state) {
12089a0bf528SMauro Carvalho Chehab 	case CT_AGC_START:
12099a0bf528SMauro Carvalho Chehab 		// set power-up level: interf+analog+AGC
12109a0bf528SMauro Carvalho Chehab 
12119a0bf528SMauro Carvalho Chehab 		if (state->revision != 0x8090)
12129a0bf528SMauro Carvalho Chehab 			dib8000_set_adc_state(state, DIBX000_ADC_ON);
12139a0bf528SMauro Carvalho Chehab 		else {
12149a0bf528SMauro Carvalho Chehab 			dib8000_set_power_mode(state, DIB8000_POWER_ALL);
12159a0bf528SMauro Carvalho Chehab 
12169a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1947)&0xff00;
12179a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1946,
12189a0bf528SMauro Carvalho Chehab 					upd_demod_gain_period & 0xFFFF);
12199a0bf528SMauro Carvalho Chehab 			/* bit 14 = enDemodGain */
12209a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1947, reg | (1<<14) |
12219a0bf528SMauro Carvalho Chehab 					((upd_demod_gain_period >> 16) & 0xFF));
12229a0bf528SMauro Carvalho Chehab 
12239a0bf528SMauro Carvalho Chehab 			/* enable adc i & q */
12249a0bf528SMauro Carvalho Chehab 			reg = dib8000_read_word(state, 1920);
12259a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 1920, (reg | 0x3) &
12269a0bf528SMauro Carvalho Chehab 					(~(1 << 7)));
12279a0bf528SMauro Carvalho Chehab 		}
12289a0bf528SMauro Carvalho Chehab 
12299a0bf528SMauro Carvalho Chehab 		if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
12309a0bf528SMauro Carvalho Chehab 			*tune_state = CT_AGC_STOP;
12319a0bf528SMauro Carvalho Chehab 			state->status = FE_STATUS_TUNE_FAILED;
12329a0bf528SMauro Carvalho Chehab 			break;
12339a0bf528SMauro Carvalho Chehab 		}
12349a0bf528SMauro Carvalho Chehab 
12359a0bf528SMauro Carvalho Chehab 		ret = 70;
12369a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STEP_0;
12379a0bf528SMauro Carvalho Chehab 		break;
12389a0bf528SMauro Carvalho Chehab 
12399a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_0:
12409a0bf528SMauro Carvalho Chehab 		//AGC initialization
12419a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
12429a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(fe, 1);
12439a0bf528SMauro Carvalho Chehab 
12449a0bf528SMauro Carvalho Chehab 		dib8000_restart_agc(state);
12459a0bf528SMauro Carvalho Chehab 
12469a0bf528SMauro Carvalho Chehab 		// wait AGC rough lock time
12479a0bf528SMauro Carvalho Chehab 		ret = 50;
12489a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STEP_1;
12499a0bf528SMauro Carvalho Chehab 		break;
12509a0bf528SMauro Carvalho Chehab 
12519a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_1:
12529a0bf528SMauro Carvalho Chehab 		// wait AGC accurate lock time
12539a0bf528SMauro Carvalho Chehab 		ret = 70;
12549a0bf528SMauro Carvalho Chehab 
12559a0bf528SMauro Carvalho Chehab 		if (dib8000_update_lna(state))
12569a0bf528SMauro Carvalho Chehab 			// wait only AGC rough lock time
12579a0bf528SMauro Carvalho Chehab 			ret = 50;
12589a0bf528SMauro Carvalho Chehab 		else
12599a0bf528SMauro Carvalho Chehab 			*tune_state = CT_AGC_STEP_2;
12609a0bf528SMauro Carvalho Chehab 		break;
12619a0bf528SMauro Carvalho Chehab 
12629a0bf528SMauro Carvalho Chehab 	case CT_AGC_STEP_2:
12639a0bf528SMauro Carvalho Chehab 		dib8000_agc_soft_split(state);
12649a0bf528SMauro Carvalho Chehab 
12659a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
12669a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(fe, 0);
12679a0bf528SMauro Carvalho Chehab 
12689a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STOP;
12699a0bf528SMauro Carvalho Chehab 		break;
12709a0bf528SMauro Carvalho Chehab 	default:
12719a0bf528SMauro Carvalho Chehab 		ret = dib8000_agc_soft_split(state);
12729a0bf528SMauro Carvalho Chehab 		break;
12739a0bf528SMauro Carvalho Chehab 	}
12749a0bf528SMauro Carvalho Chehab 	return ret;
12759a0bf528SMauro Carvalho Chehab 
12769a0bf528SMauro Carvalho Chehab }
12779a0bf528SMauro Carvalho Chehab 
12789a0bf528SMauro Carvalho Chehab static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
12799a0bf528SMauro Carvalho Chehab {
12809a0bf528SMauro Carvalho Chehab 	u16 reg;
12819a0bf528SMauro Carvalho Chehab 
12829a0bf528SMauro Carvalho Chehab 	drive &= 0x7;
12839a0bf528SMauro Carvalho Chehab 
12849a0bf528SMauro Carvalho Chehab 	/* drive host bus 2, 3, 4 */
12859a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1798) &
12869a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
12879a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
12889a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1798, reg);
12899a0bf528SMauro Carvalho Chehab 
12909a0bf528SMauro Carvalho Chehab 	/* drive host bus 5,6 */
12919a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
12929a0bf528SMauro Carvalho Chehab 	reg |= (drive<<8) | (drive<<2);
12939a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1799, reg);
12949a0bf528SMauro Carvalho Chehab 
12959a0bf528SMauro Carvalho Chehab 	/* drive host bus 7, 8, 9 */
12969a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1800) &
12979a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
12989a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
12999a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1800, reg);
13009a0bf528SMauro Carvalho Chehab 
13019a0bf528SMauro Carvalho Chehab 	/* drive host bus 10, 11 */
13029a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
13039a0bf528SMauro Carvalho Chehab 	reg |= (drive<<8) | (drive<<2);
13049a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1801, reg);
13059a0bf528SMauro Carvalho Chehab 
13069a0bf528SMauro Carvalho Chehab 	/* drive host bus 12, 13, 14 */
13079a0bf528SMauro Carvalho Chehab 	reg = dib8000_read_word(state, 1802) &
13089a0bf528SMauro Carvalho Chehab 		~(0x7 | (0x7 << 6) | (0x7 << 12));
13099a0bf528SMauro Carvalho Chehab 	reg |= (drive<<12) | (drive<<6) | drive;
13109a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1802, reg);
13119a0bf528SMauro Carvalho Chehab }
13129a0bf528SMauro Carvalho Chehab 
13139a0bf528SMauro Carvalho Chehab static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
13149a0bf528SMauro Carvalho Chehab 		u32 insertExtSynchro, u32 syncSize)
13159a0bf528SMauro Carvalho Chehab {
13169a0bf528SMauro Carvalho Chehab 	u32 quantif = 3;
13179a0bf528SMauro Carvalho Chehab 	u32 nom = (insertExtSynchro * P_Kin+syncSize);
13189a0bf528SMauro Carvalho Chehab 	u32 denom = P_Kout;
13199a0bf528SMauro Carvalho Chehab 	u32 syncFreq = ((nom << quantif) / denom);
13209a0bf528SMauro Carvalho Chehab 
13219a0bf528SMauro Carvalho Chehab 	if ((syncFreq & ((1 << quantif) - 1)) != 0)
13229a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif) + 1;
13239a0bf528SMauro Carvalho Chehab 	else
13249a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif);
13259a0bf528SMauro Carvalho Chehab 
13269a0bf528SMauro Carvalho Chehab 	if (syncFreq != 0)
13279a0bf528SMauro Carvalho Chehab 		syncFreq = syncFreq - 1;
13289a0bf528SMauro Carvalho Chehab 
13299a0bf528SMauro Carvalho Chehab 	return syncFreq;
13309a0bf528SMauro Carvalho Chehab }
13319a0bf528SMauro Carvalho Chehab 
13329a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
13339a0bf528SMauro Carvalho Chehab 		u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
13349a0bf528SMauro Carvalho Chehab 		u32 syncWord, u32 syncSize)
13359a0bf528SMauro Carvalho Chehab {
13369a0bf528SMauro Carvalho Chehab 	dprintk("Configure DibStream Tx");
13379a0bf528SMauro Carvalho Chehab 
13389a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1615, 1);
13399a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1603, P_Kin);
13409a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1605, P_Kout);
13419a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1606, insertExtSynchro);
13429a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1608, synchroMode);
13439a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
13449a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1610, syncWord & 0xffff);
13459a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1612, syncSize);
13469a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1615, 0);
13479a0bf528SMauro Carvalho Chehab }
13489a0bf528SMauro Carvalho Chehab 
13499a0bf528SMauro Carvalho Chehab static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
13509a0bf528SMauro Carvalho Chehab 		u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
13519a0bf528SMauro Carvalho Chehab 		u32 syncWord, u32 syncSize, u32 dataOutRate)
13529a0bf528SMauro Carvalho Chehab {
13539a0bf528SMauro Carvalho Chehab 	u32 syncFreq;
13549a0bf528SMauro Carvalho Chehab 
13559a0bf528SMauro Carvalho Chehab 	dprintk("Configure DibStream Rx synchroMode = %d", synchroMode);
13569a0bf528SMauro Carvalho Chehab 
13579a0bf528SMauro Carvalho Chehab 	if ((P_Kin != 0) && (P_Kout != 0)) {
13589a0bf528SMauro Carvalho Chehab 		syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
13599a0bf528SMauro Carvalho Chehab 				insertExtSynchro, syncSize);
13609a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 1542, syncFreq);
13619a0bf528SMauro Carvalho Chehab 	}
13629a0bf528SMauro Carvalho Chehab 
13639a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1554, 1);
13649a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1536, P_Kin);
13659a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1537, P_Kout);
13669a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1539, synchroMode);
13679a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
13689a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1541, syncWord & 0xffff);
13699a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1543, syncSize);
13709a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1544, dataOutRate);
13719a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1554, 0);
13729a0bf528SMauro Carvalho Chehab }
13739a0bf528SMauro Carvalho Chehab 
13749a0bf528SMauro Carvalho Chehab static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
13759a0bf528SMauro Carvalho Chehab {
13769a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
13779a0bf528SMauro Carvalho Chehab 
13789a0bf528SMauro Carvalho Chehab 	reg_1287 = dib8000_read_word(state, 1287);
13799a0bf528SMauro Carvalho Chehab 
13809a0bf528SMauro Carvalho Chehab 	switch (onoff) {
13819a0bf528SMauro Carvalho Chehab 	case 1:
13829a0bf528SMauro Carvalho Chehab 			reg_1287 &= ~(1 << 8);
13839a0bf528SMauro Carvalho Chehab 			break;
13849a0bf528SMauro Carvalho Chehab 	case 0:
13859a0bf528SMauro Carvalho Chehab 			reg_1287 |= (1 << 8);
13869a0bf528SMauro Carvalho Chehab 			break;
13879a0bf528SMauro Carvalho Chehab 	}
13889a0bf528SMauro Carvalho Chehab 
13899a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1287, reg_1287);
13909a0bf528SMauro Carvalho Chehab }
13919a0bf528SMauro Carvalho Chehab 
13929a0bf528SMauro Carvalho Chehab static void dib8096p_configMpegMux(struct dib8000_state *state,
13939a0bf528SMauro Carvalho Chehab 		u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
13949a0bf528SMauro Carvalho Chehab {
13959a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
13969a0bf528SMauro Carvalho Chehab 
13979a0bf528SMauro Carvalho Chehab 	dprintk("Enable Mpeg mux");
13989a0bf528SMauro Carvalho Chehab 
13999a0bf528SMauro Carvalho Chehab 	dib8096p_enMpegMux(state, 0);
14009a0bf528SMauro Carvalho Chehab 
14019a0bf528SMauro Carvalho Chehab 	/* If the input mode is MPEG do not divide the serial clock */
14029a0bf528SMauro Carvalho Chehab 	if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
14039a0bf528SMauro Carvalho Chehab 		enSerialClkDiv2 = 0;
14049a0bf528SMauro Carvalho Chehab 
14059a0bf528SMauro Carvalho Chehab 	reg_1287 = ((pulseWidth & 0x1f) << 3) |
14069a0bf528SMauro Carvalho Chehab 		((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
14079a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1287, reg_1287);
14089a0bf528SMauro Carvalho Chehab 
14099a0bf528SMauro Carvalho Chehab 	dib8096p_enMpegMux(state, 1);
14109a0bf528SMauro Carvalho Chehab }
14119a0bf528SMauro Carvalho Chehab 
14129a0bf528SMauro Carvalho Chehab static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
14139a0bf528SMauro Carvalho Chehab {
14149a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
14159a0bf528SMauro Carvalho Chehab 
14169a0bf528SMauro Carvalho Chehab 	switch (mode) {
14179a0bf528SMauro Carvalho Chehab 	case MPEG_ON_DIBTX:
14189a0bf528SMauro Carvalho Chehab 			dprintk("SET MPEG ON DIBSTREAM TX");
14199a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
14209a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 9); break;
14219a0bf528SMauro Carvalho Chehab 	case DIV_ON_DIBTX:
14229a0bf528SMauro Carvalho Chehab 			dprintk("SET DIV_OUT ON DIBSTREAM TX");
14239a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
14249a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 8); break;
14259a0bf528SMauro Carvalho Chehab 	case ADC_ON_DIBTX:
14269a0bf528SMauro Carvalho Chehab 			dprintk("SET ADC_OUT ON DIBSTREAM TX");
14279a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
14289a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 7); break;
14299a0bf528SMauro Carvalho Chehab 	default:
14309a0bf528SMauro Carvalho Chehab 			break;
14319a0bf528SMauro Carvalho Chehab 	}
14329a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1288, reg_1288);
14339a0bf528SMauro Carvalho Chehab }
14349a0bf528SMauro Carvalho Chehab 
14359a0bf528SMauro Carvalho Chehab static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
14369a0bf528SMauro Carvalho Chehab {
14379a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
14389a0bf528SMauro Carvalho Chehab 
14399a0bf528SMauro Carvalho Chehab 	switch (mode) {
14409a0bf528SMauro Carvalho Chehab 	case DEMOUT_ON_HOSTBUS:
14419a0bf528SMauro Carvalho Chehab 			dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
14429a0bf528SMauro Carvalho Chehab 			dib8096p_enMpegMux(state, 0);
14439a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 6);
14449a0bf528SMauro Carvalho Chehab 			break;
14459a0bf528SMauro Carvalho Chehab 	case DIBTX_ON_HOSTBUS:
14469a0bf528SMauro Carvalho Chehab 			dprintk("SET DIBSTREAM TX ON HOST BUS");
14479a0bf528SMauro Carvalho Chehab 			dib8096p_enMpegMux(state, 0);
14489a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 5);
14499a0bf528SMauro Carvalho Chehab 			break;
14509a0bf528SMauro Carvalho Chehab 	case MPEG_ON_HOSTBUS:
14519a0bf528SMauro Carvalho Chehab 			dprintk("SET MPEG MUX ON HOST BUS");
14529a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1 << 4);
14539a0bf528SMauro Carvalho Chehab 			break;
14549a0bf528SMauro Carvalho Chehab 	default:
14559a0bf528SMauro Carvalho Chehab 			break;
14569a0bf528SMauro Carvalho Chehab 	}
14579a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1288, reg_1288);
14589a0bf528SMauro Carvalho Chehab }
14599a0bf528SMauro Carvalho Chehab 
14609a0bf528SMauro Carvalho Chehab static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
14619a0bf528SMauro Carvalho Chehab {
14629a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
14639a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
14649a0bf528SMauro Carvalho Chehab 
14659a0bf528SMauro Carvalho Chehab 	switch (onoff) {
14669a0bf528SMauro Carvalho Chehab 	case 0: /* only use the internal way - not the diversity input */
14679a0bf528SMauro Carvalho Chehab 			dprintk("%s mode OFF : by default Enable Mpeg INPUT",
14689a0bf528SMauro Carvalho Chehab 					__func__);
14699a0bf528SMauro Carvalho Chehab 			/* outputRate = 8 */
14709a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
14719a0bf528SMauro Carvalho Chehab 
14729a0bf528SMauro Carvalho Chehab 			/* Do not divide the serial clock of MPEG MUX in
14739a0bf528SMauro Carvalho Chehab 			   SERIAL MODE in case input mode MPEG is used */
14749a0bf528SMauro Carvalho Chehab 			reg_1287 = dib8000_read_word(state, 1287);
14759a0bf528SMauro Carvalho Chehab 			/* enSerialClkDiv2 == 1 ? */
14769a0bf528SMauro Carvalho Chehab 			if ((reg_1287 & 0x1) == 1) {
14779a0bf528SMauro Carvalho Chehab 				/* force enSerialClkDiv2 = 0 */
14789a0bf528SMauro Carvalho Chehab 				reg_1287 &= ~0x1;
14799a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, 1287, reg_1287);
14809a0bf528SMauro Carvalho Chehab 			}
14819a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 1;
14829a0bf528SMauro Carvalho Chehab 			break;
14839a0bf528SMauro Carvalho Chehab 	case 1: /* both ways */
14849a0bf528SMauro Carvalho Chehab 	case 2: /* only the diversity input */
14859a0bf528SMauro Carvalho Chehab 			dprintk("%s ON : Enable diversity INPUT", __func__);
14869a0bf528SMauro Carvalho Chehab 			dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
14879a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 0;
14889a0bf528SMauro Carvalho Chehab 			break;
14899a0bf528SMauro Carvalho Chehab 	}
14909a0bf528SMauro Carvalho Chehab 
14919a0bf528SMauro Carvalho Chehab 	dib8000_set_diversity_in(state->fe[0], onoff);
14929a0bf528SMauro Carvalho Chehab 	return 0;
14939a0bf528SMauro Carvalho Chehab }
14949a0bf528SMauro Carvalho Chehab 
14959a0bf528SMauro Carvalho Chehab static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
14969a0bf528SMauro Carvalho Chehab {
14979a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
14989a0bf528SMauro Carvalho Chehab 	u16 outreg, smo_mode, fifo_threshold;
14999a0bf528SMauro Carvalho Chehab 	u8 prefer_mpeg_mux_use = 1;
15009a0bf528SMauro Carvalho Chehab 	int ret = 0;
15019a0bf528SMauro Carvalho Chehab 
1502173a64cbSPatrick Boettcher 	state->output_mode = mode;
15039a0bf528SMauro Carvalho Chehab 	dib8096p_host_bus_drive(state, 1);
15049a0bf528SMauro Carvalho Chehab 
15059a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
15069a0bf528SMauro Carvalho Chehab 	smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
15079a0bf528SMauro Carvalho Chehab 	outreg   = dib8000_read_word(state, 1286) &
15089a0bf528SMauro Carvalho Chehab 		~((1 << 10) | (0x7 << 6) | (1 << 1));
15099a0bf528SMauro Carvalho Chehab 
15109a0bf528SMauro Carvalho Chehab 	switch (mode) {
15119a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:
15129a0bf528SMauro Carvalho Chehab 			outreg = 0;
15139a0bf528SMauro Carvalho Chehab 			break;
15149a0bf528SMauro Carvalho Chehab 
15159a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:
15169a0bf528SMauro Carvalho Chehab 			if (prefer_mpeg_mux_use) {
15179a0bf528SMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux");
15189a0bf528SMauro Carvalho Chehab 				dib8096p_configMpegMux(state, 3, 1, 1);
15199a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
15209a0bf528SMauro Carvalho Chehab 			} else {/* Use Smooth block */
15219a0bf528SMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc");
15229a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state,
15239a0bf528SMauro Carvalho Chehab 						DEMOUT_ON_HOSTBUS);
15249a0bf528SMauro Carvalho Chehab 				outreg |= (2 << 6) | (0 << 1);
15259a0bf528SMauro Carvalho Chehab 			}
15269a0bf528SMauro Carvalho Chehab 			break;
15279a0bf528SMauro Carvalho Chehab 
15289a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:
15299a0bf528SMauro Carvalho Chehab 			if (prefer_mpeg_mux_use) {
15309a0bf528SMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
15319a0bf528SMauro Carvalho Chehab 				dib8096p_configMpegMux(state, 2, 0, 0);
15329a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
15339a0bf528SMauro Carvalho Chehab 			} else { /* Use Smooth block */
15349a0bf528SMauro Carvalho Chehab 				dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block");
15359a0bf528SMauro Carvalho Chehab 				dib8096p_setHostBusMux(state,
15369a0bf528SMauro Carvalho Chehab 						DEMOUT_ON_HOSTBUS);
15379a0bf528SMauro Carvalho Chehab 				outreg |= (0 << 6);
15389a0bf528SMauro Carvalho Chehab 			}
15399a0bf528SMauro Carvalho Chehab 			break;
15409a0bf528SMauro Carvalho Chehab 
15419a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
15429a0bf528SMauro Carvalho Chehab 			dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block");
15439a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
15449a0bf528SMauro Carvalho Chehab 			outreg |= (1 << 6);
15459a0bf528SMauro Carvalho Chehab 			break;
15469a0bf528SMauro Carvalho Chehab 
15479a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:
15489a0bf528SMauro Carvalho Chehab 			/* Using Smooth block because not supported
15499a0bf528SMauro Carvalho Chehab 			   by new Mpeg Mux bloc */
15509a0bf528SMauro Carvalho Chehab 			dprintk("dib8096P setting output mode TS_FIFO using Smooth block");
15519a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
15529a0bf528SMauro Carvalho Chehab 			outreg |= (5 << 6);
15539a0bf528SMauro Carvalho Chehab 			smo_mode |= (3 << 1);
15549a0bf528SMauro Carvalho Chehab 			fifo_threshold = 512;
15559a0bf528SMauro Carvalho Chehab 			break;
15569a0bf528SMauro Carvalho Chehab 
15579a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
15589a0bf528SMauro Carvalho Chehab 			dprintk("dib8096P setting output mode MODE_DIVERSITY");
15599a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
15609a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
15619a0bf528SMauro Carvalho Chehab 			break;
15629a0bf528SMauro Carvalho Chehab 
15639a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
15649a0bf528SMauro Carvalho Chehab 			dprintk("dib8096P setting output mode MODE_ANALOG_ADC");
15659a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
15669a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
15679a0bf528SMauro Carvalho Chehab 			break;
15689a0bf528SMauro Carvalho Chehab 	}
15699a0bf528SMauro Carvalho Chehab 
15709a0bf528SMauro Carvalho Chehab 	if (mode != OUTMODE_HIGH_Z)
15719a0bf528SMauro Carvalho Chehab 		outreg |= (1<<10);
15729a0bf528SMauro Carvalho Chehab 
15739a0bf528SMauro Carvalho Chehab 	dprintk("output_mpeg2_in_188_bytes = %d",
15749a0bf528SMauro Carvalho Chehab 			state->cfg.output_mpeg2_in_188_bytes);
15759a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
15769a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
15779a0bf528SMauro Carvalho Chehab 
15789a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 299, smo_mode);
15799a0bf528SMauro Carvalho Chehab 	/* synchronous fread */
15809a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
15819a0bf528SMauro Carvalho Chehab 	ret |= dib8000_write_word(state, 1286, outreg);
15829a0bf528SMauro Carvalho Chehab 
15839a0bf528SMauro Carvalho Chehab 	return ret;
15849a0bf528SMauro Carvalho Chehab }
15859a0bf528SMauro Carvalho Chehab 
15869a0bf528SMauro Carvalho Chehab static int map_addr_to_serpar_number(struct i2c_msg *msg)
15879a0bf528SMauro Carvalho Chehab {
15889a0bf528SMauro Carvalho Chehab 	if (msg->buf[0] <= 15)
15899a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 1;
15909a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 17)
15919a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 15;
15929a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 16)
15939a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 17;
15949a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 19)
15959a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 16;
15969a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
15979a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 3;
15989a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 28)
15999a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 23;
16009a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 99)
16019a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 99;
16029a0bf528SMauro Carvalho Chehab 	else
16039a0bf528SMauro Carvalho Chehab 		return -EINVAL;
16049a0bf528SMauro Carvalho Chehab 	return 0;
16059a0bf528SMauro Carvalho Chehab }
16069a0bf528SMauro Carvalho Chehab 
16079a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
16089a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
16099a0bf528SMauro Carvalho Chehab {
16109a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
16119a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1;
16129a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
16139a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
16149a0bf528SMauro Carvalho Chehab 
16159a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
16169a0bf528SMauro Carvalho Chehab 		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
16179a0bf528SMauro Carvalho Chehab 		i--;
16189a0bf528SMauro Carvalho Chehab 		if (i == 0)
16199a0bf528SMauro Carvalho Chehab 			dprintk("Tuner ITF: write busy (overflow)");
16209a0bf528SMauro Carvalho Chehab 	}
16219a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
16229a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
16239a0bf528SMauro Carvalho Chehab 
16249a0bf528SMauro Carvalho Chehab 	return num;
16259a0bf528SMauro Carvalho Chehab }
16269a0bf528SMauro Carvalho Chehab 
16279a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
16289a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
16299a0bf528SMauro Carvalho Chehab {
16309a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
16319a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1, n_empty = 1;
16329a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
16339a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
16349a0bf528SMauro Carvalho Chehab 	u16 read_word;
16359a0bf528SMauro Carvalho Chehab 
16369a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
16379a0bf528SMauro Carvalho Chehab 		n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
16389a0bf528SMauro Carvalho Chehab 		i--;
16399a0bf528SMauro Carvalho Chehab 		if (i == 0)
16409a0bf528SMauro Carvalho Chehab 			dprintk("TunerITF: read busy (overflow)");
16419a0bf528SMauro Carvalho Chehab 	}
16429a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
16439a0bf528SMauro Carvalho Chehab 
16449a0bf528SMauro Carvalho Chehab 	i = 1000;
16459a0bf528SMauro Carvalho Chehab 	while (n_empty == 1 && i) {
16469a0bf528SMauro Carvalho Chehab 		n_empty = dib8000_read_word(state, 1984)&0x1;
16479a0bf528SMauro Carvalho Chehab 		i--;
16489a0bf528SMauro Carvalho Chehab 		if (i == 0)
16499a0bf528SMauro Carvalho Chehab 			dprintk("TunerITF: read busy (empty)");
16509a0bf528SMauro Carvalho Chehab 	}
16519a0bf528SMauro Carvalho Chehab 
16529a0bf528SMauro Carvalho Chehab 	read_word = dib8000_read_word(state, 1987);
16539a0bf528SMauro Carvalho Chehab 	msg[1].buf[0] = (read_word >> 8) & 0xff;
16549a0bf528SMauro Carvalho Chehab 	msg[1].buf[1] = (read_word) & 0xff;
16559a0bf528SMauro Carvalho Chehab 
16569a0bf528SMauro Carvalho Chehab 	return num;
16579a0bf528SMauro Carvalho Chehab }
16589a0bf528SMauro Carvalho Chehab 
16599a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
16609a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
16619a0bf528SMauro Carvalho Chehab {
16629a0bf528SMauro Carvalho Chehab 	if (map_addr_to_serpar_number(&msg[0]) == 0) {
16639a0bf528SMauro Carvalho Chehab 		if (num == 1) /* write */
16649a0bf528SMauro Carvalho Chehab 			return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
16659a0bf528SMauro Carvalho Chehab 		else /* read */
16669a0bf528SMauro Carvalho Chehab 			return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
16679a0bf528SMauro Carvalho Chehab 	}
16689a0bf528SMauro Carvalho Chehab 	return num;
16699a0bf528SMauro Carvalho Chehab }
16709a0bf528SMauro Carvalho Chehab 
16719a0bf528SMauro Carvalho Chehab static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
16729a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num, u16 apb_address)
16739a0bf528SMauro Carvalho Chehab {
16749a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
16759a0bf528SMauro Carvalho Chehab 	u16 word;
16769a0bf528SMauro Carvalho Chehab 
16779a0bf528SMauro Carvalho Chehab 	if (num == 1) {		/* write */
16789a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, apb_address,
16799a0bf528SMauro Carvalho Chehab 				((msg[0].buf[1] << 8) | (msg[0].buf[2])));
16809a0bf528SMauro Carvalho Chehab 	} else {
16819a0bf528SMauro Carvalho Chehab 		word = dib8000_read_word(state, apb_address);
16829a0bf528SMauro Carvalho Chehab 		msg[1].buf[0] = (word >> 8) & 0xff;
16839a0bf528SMauro Carvalho Chehab 		msg[1].buf[1] = (word) & 0xff;
16849a0bf528SMauro Carvalho Chehab 	}
16859a0bf528SMauro Carvalho Chehab 	return num;
16869a0bf528SMauro Carvalho Chehab }
16879a0bf528SMauro Carvalho Chehab 
16889a0bf528SMauro Carvalho Chehab static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
16899a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
16909a0bf528SMauro Carvalho Chehab {
16919a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
16929a0bf528SMauro Carvalho Chehab 	u16 apb_address = 0, word;
16939a0bf528SMauro Carvalho Chehab 	int i = 0;
16949a0bf528SMauro Carvalho Chehab 
16959a0bf528SMauro Carvalho Chehab 	switch (msg[0].buf[0]) {
16969a0bf528SMauro Carvalho Chehab 	case 0x12:
16979a0bf528SMauro Carvalho Chehab 			apb_address = 1920;
16989a0bf528SMauro Carvalho Chehab 			break;
16999a0bf528SMauro Carvalho Chehab 	case 0x14:
17009a0bf528SMauro Carvalho Chehab 			apb_address = 1921;
17019a0bf528SMauro Carvalho Chehab 			break;
17029a0bf528SMauro Carvalho Chehab 	case 0x24:
17039a0bf528SMauro Carvalho Chehab 			apb_address = 1922;
17049a0bf528SMauro Carvalho Chehab 			break;
17059a0bf528SMauro Carvalho Chehab 	case 0x1a:
17069a0bf528SMauro Carvalho Chehab 			apb_address = 1923;
17079a0bf528SMauro Carvalho Chehab 			break;
17089a0bf528SMauro Carvalho Chehab 	case 0x22:
17099a0bf528SMauro Carvalho Chehab 			apb_address = 1924;
17109a0bf528SMauro Carvalho Chehab 			break;
17119a0bf528SMauro Carvalho Chehab 	case 0x33:
17129a0bf528SMauro Carvalho Chehab 			apb_address = 1926;
17139a0bf528SMauro Carvalho Chehab 			break;
17149a0bf528SMauro Carvalho Chehab 	case 0x34:
17159a0bf528SMauro Carvalho Chehab 			apb_address = 1927;
17169a0bf528SMauro Carvalho Chehab 			break;
17179a0bf528SMauro Carvalho Chehab 	case 0x35:
17189a0bf528SMauro Carvalho Chehab 			apb_address = 1928;
17199a0bf528SMauro Carvalho Chehab 			break;
17209a0bf528SMauro Carvalho Chehab 	case 0x36:
17219a0bf528SMauro Carvalho Chehab 			apb_address = 1929;
17229a0bf528SMauro Carvalho Chehab 			break;
17239a0bf528SMauro Carvalho Chehab 	case 0x37:
17249a0bf528SMauro Carvalho Chehab 			apb_address = 1930;
17259a0bf528SMauro Carvalho Chehab 			break;
17269a0bf528SMauro Carvalho Chehab 	case 0x38:
17279a0bf528SMauro Carvalho Chehab 			apb_address = 1931;
17289a0bf528SMauro Carvalho Chehab 			break;
17299a0bf528SMauro Carvalho Chehab 	case 0x39:
17309a0bf528SMauro Carvalho Chehab 			apb_address = 1932;
17319a0bf528SMauro Carvalho Chehab 			break;
17329a0bf528SMauro Carvalho Chehab 	case 0x2a:
17339a0bf528SMauro Carvalho Chehab 			apb_address = 1935;
17349a0bf528SMauro Carvalho Chehab 			break;
17359a0bf528SMauro Carvalho Chehab 	case 0x2b:
17369a0bf528SMauro Carvalho Chehab 			apb_address = 1936;
17379a0bf528SMauro Carvalho Chehab 			break;
17389a0bf528SMauro Carvalho Chehab 	case 0x2c:
17399a0bf528SMauro Carvalho Chehab 			apb_address = 1937;
17409a0bf528SMauro Carvalho Chehab 			break;
17419a0bf528SMauro Carvalho Chehab 	case 0x2d:
17429a0bf528SMauro Carvalho Chehab 			apb_address = 1938;
17439a0bf528SMauro Carvalho Chehab 			break;
17449a0bf528SMauro Carvalho Chehab 	case 0x2e:
17459a0bf528SMauro Carvalho Chehab 			apb_address = 1939;
17469a0bf528SMauro Carvalho Chehab 			break;
17479a0bf528SMauro Carvalho Chehab 	case 0x2f:
17489a0bf528SMauro Carvalho Chehab 			apb_address = 1940;
17499a0bf528SMauro Carvalho Chehab 			break;
17509a0bf528SMauro Carvalho Chehab 	case 0x30:
17519a0bf528SMauro Carvalho Chehab 			apb_address = 1941;
17529a0bf528SMauro Carvalho Chehab 			break;
17539a0bf528SMauro Carvalho Chehab 	case 0x31:
17549a0bf528SMauro Carvalho Chehab 			apb_address = 1942;
17559a0bf528SMauro Carvalho Chehab 			break;
17569a0bf528SMauro Carvalho Chehab 	case 0x32:
17579a0bf528SMauro Carvalho Chehab 			apb_address = 1943;
17589a0bf528SMauro Carvalho Chehab 			break;
17599a0bf528SMauro Carvalho Chehab 	case 0x3e:
17609a0bf528SMauro Carvalho Chehab 			apb_address = 1944;
17619a0bf528SMauro Carvalho Chehab 			break;
17629a0bf528SMauro Carvalho Chehab 	case 0x3f:
17639a0bf528SMauro Carvalho Chehab 			apb_address = 1945;
17649a0bf528SMauro Carvalho Chehab 			break;
17659a0bf528SMauro Carvalho Chehab 	case 0x40:
17669a0bf528SMauro Carvalho Chehab 			apb_address = 1948;
17679a0bf528SMauro Carvalho Chehab 			break;
17689a0bf528SMauro Carvalho Chehab 	case 0x25:
17699a0bf528SMauro Carvalho Chehab 			apb_address = 936;
17709a0bf528SMauro Carvalho Chehab 			break;
17719a0bf528SMauro Carvalho Chehab 	case 0x26:
17729a0bf528SMauro Carvalho Chehab 			apb_address = 937;
17739a0bf528SMauro Carvalho Chehab 			break;
17749a0bf528SMauro Carvalho Chehab 	case 0x27:
17759a0bf528SMauro Carvalho Chehab 			apb_address = 938;
17769a0bf528SMauro Carvalho Chehab 			break;
17779a0bf528SMauro Carvalho Chehab 	case 0x28:
17789a0bf528SMauro Carvalho Chehab 			apb_address = 939;
17799a0bf528SMauro Carvalho Chehab 			break;
17809a0bf528SMauro Carvalho Chehab 	case 0x1d:
17819a0bf528SMauro Carvalho Chehab 			/* get sad sel request */
17829a0bf528SMauro Carvalho Chehab 			i = ((dib8000_read_word(state, 921) >> 12)&0x3);
17839a0bf528SMauro Carvalho Chehab 			word = dib8000_read_word(state, 924+i);
17849a0bf528SMauro Carvalho Chehab 			msg[1].buf[0] = (word >> 8) & 0xff;
17859a0bf528SMauro Carvalho Chehab 			msg[1].buf[1] = (word) & 0xff;
17869a0bf528SMauro Carvalho Chehab 			return num;
17879a0bf528SMauro Carvalho Chehab 	case 0x1f:
17889a0bf528SMauro Carvalho Chehab 			if (num == 1) {	/* write */
17899a0bf528SMauro Carvalho Chehab 				word = (u16) ((msg[0].buf[1] << 8) |
17909a0bf528SMauro Carvalho Chehab 						msg[0].buf[2]);
17919a0bf528SMauro Carvalho Chehab 				/* in the VGAMODE Sel are located on bit 0/1 */
17929a0bf528SMauro Carvalho Chehab 				word &= 0x3;
17939a0bf528SMauro Carvalho Chehab 				word = (dib8000_read_word(state, 921) &
17949a0bf528SMauro Carvalho Chehab 						~(3<<12)) | (word<<12);
17959a0bf528SMauro Carvalho Chehab 				/* Set the proper input */
17969a0bf528SMauro Carvalho Chehab 				dib8000_write_word(state, 921, word);
17979a0bf528SMauro Carvalho Chehab 				return num;
17989a0bf528SMauro Carvalho Chehab 			}
17999a0bf528SMauro Carvalho Chehab 	}
18009a0bf528SMauro Carvalho Chehab 
18019a0bf528SMauro Carvalho Chehab 	if (apb_address != 0) /* R/W acces via APB */
18029a0bf528SMauro Carvalho Chehab 		return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
18039a0bf528SMauro Carvalho Chehab 	else  /* R/W access via SERPAR  */
18049a0bf528SMauro Carvalho Chehab 		return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
18059a0bf528SMauro Carvalho Chehab 
18069a0bf528SMauro Carvalho Chehab 	return 0;
18079a0bf528SMauro Carvalho Chehab }
18089a0bf528SMauro Carvalho Chehab 
18099a0bf528SMauro Carvalho Chehab static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
18109a0bf528SMauro Carvalho Chehab {
18119a0bf528SMauro Carvalho Chehab 	return I2C_FUNC_I2C;
18129a0bf528SMauro Carvalho Chehab }
18139a0bf528SMauro Carvalho Chehab 
18149a0bf528SMauro Carvalho Chehab static struct i2c_algorithm dib8096p_tuner_xfer_algo = {
18159a0bf528SMauro Carvalho Chehab 	.master_xfer = dib8096p_tuner_xfer,
18169a0bf528SMauro Carvalho Chehab 	.functionality = dib8096p_i2c_func,
18179a0bf528SMauro Carvalho Chehab };
18189a0bf528SMauro Carvalho Chehab 
18199a0bf528SMauro Carvalho Chehab struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
18209a0bf528SMauro Carvalho Chehab {
18219a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
18229a0bf528SMauro Carvalho Chehab 	return &st->dib8096p_tuner_adap;
18239a0bf528SMauro Carvalho Chehab }
18249a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8096p_get_i2c_tuner);
18259a0bf528SMauro Carvalho Chehab 
18269a0bf528SMauro Carvalho Chehab int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
18279a0bf528SMauro Carvalho Chehab {
18289a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
18299a0bf528SMauro Carvalho Chehab 	u16 en_cur_state;
18309a0bf528SMauro Carvalho Chehab 
18319a0bf528SMauro Carvalho Chehab 	dprintk("sleep dib8096p: %d", onoff);
18329a0bf528SMauro Carvalho Chehab 
18339a0bf528SMauro Carvalho Chehab 	en_cur_state = dib8000_read_word(state, 1922);
18349a0bf528SMauro Carvalho Chehab 
18359a0bf528SMauro Carvalho Chehab 	/* LNAs and MIX are ON and therefore it is a valid configuration */
18369a0bf528SMauro Carvalho Chehab 	if (en_cur_state > 0xff)
18379a0bf528SMauro Carvalho Chehab 		state->tuner_enable = en_cur_state ;
18389a0bf528SMauro Carvalho Chehab 
18399a0bf528SMauro Carvalho Chehab 	if (onoff)
18409a0bf528SMauro Carvalho Chehab 		en_cur_state &= 0x00ff;
18419a0bf528SMauro Carvalho Chehab 	else {
18429a0bf528SMauro Carvalho Chehab 		if (state->tuner_enable != 0)
18439a0bf528SMauro Carvalho Chehab 			en_cur_state = state->tuner_enable;
18449a0bf528SMauro Carvalho Chehab 	}
18459a0bf528SMauro Carvalho Chehab 
18469a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 1922, en_cur_state);
18479a0bf528SMauro Carvalho Chehab 
18489a0bf528SMauro Carvalho Chehab 	return 0;
18499a0bf528SMauro Carvalho Chehab }
18509a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8096p_tuner_sleep);
18519a0bf528SMauro Carvalho Chehab 
18529a0bf528SMauro Carvalho Chehab static const s32 lut_1000ln_mant[] =
18539a0bf528SMauro Carvalho Chehab {
18549a0bf528SMauro Carvalho Chehab 	908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
18559a0bf528SMauro Carvalho Chehab };
18569a0bf528SMauro Carvalho Chehab 
18579a0bf528SMauro Carvalho Chehab s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
18589a0bf528SMauro Carvalho Chehab {
18599a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
18609a0bf528SMauro Carvalho Chehab 	u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
18619a0bf528SMauro Carvalho Chehab 	s32 val;
18629a0bf528SMauro Carvalho Chehab 
18639a0bf528SMauro Carvalho Chehab 	val = dib8000_read32(state, 384);
18649a0bf528SMauro Carvalho Chehab 	if (mode) {
18659a0bf528SMauro Carvalho Chehab 		tmp_val = val;
18669a0bf528SMauro Carvalho Chehab 		while (tmp_val >>= 1)
18679a0bf528SMauro Carvalho Chehab 			exp++;
18689a0bf528SMauro Carvalho Chehab 		mant = (val * 1000 / (1<<exp));
18699a0bf528SMauro Carvalho Chehab 		ix = (u8)((mant-1000)/100); /* index of the LUT */
18709a0bf528SMauro Carvalho Chehab 		val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
18719a0bf528SMauro Carvalho Chehab 		val = (val*256)/1000;
18729a0bf528SMauro Carvalho Chehab 	}
18739a0bf528SMauro Carvalho Chehab 	return val;
18749a0bf528SMauro Carvalho Chehab }
18759a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_get_adc_power);
18769a0bf528SMauro Carvalho Chehab 
18779a0bf528SMauro Carvalho Chehab int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
18789a0bf528SMauro Carvalho Chehab {
18799a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
18809a0bf528SMauro Carvalho Chehab 	int val = 0;
18819a0bf528SMauro Carvalho Chehab 
18829a0bf528SMauro Carvalho Chehab 	switch (IQ) {
18839a0bf528SMauro Carvalho Chehab 	case 1:
18849a0bf528SMauro Carvalho Chehab 			val = dib8000_read_word(state, 403);
18859a0bf528SMauro Carvalho Chehab 			break;
18869a0bf528SMauro Carvalho Chehab 	case 0:
18879a0bf528SMauro Carvalho Chehab 			val = dib8000_read_word(state, 404);
18889a0bf528SMauro Carvalho Chehab 			break;
18899a0bf528SMauro Carvalho Chehab 	}
18909a0bf528SMauro Carvalho Chehab 	if (val  & 0x200)
18919a0bf528SMauro Carvalho Chehab 		val -= 1024;
18929a0bf528SMauro Carvalho Chehab 
18939a0bf528SMauro Carvalho Chehab 	return val;
18949a0bf528SMauro Carvalho Chehab }
18959a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8090p_get_dc_power);
18969a0bf528SMauro Carvalho Chehab 
18979a0bf528SMauro Carvalho Chehab static void dib8000_update_timf(struct dib8000_state *state)
18989a0bf528SMauro Carvalho Chehab {
18999a0bf528SMauro Carvalho Chehab 	u32 timf = state->timf = dib8000_read32(state, 435);
19009a0bf528SMauro Carvalho Chehab 
19019a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 29, (u16) (timf >> 16));
19029a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 30, (u16) (timf & 0xffff));
19039a0bf528SMauro Carvalho Chehab 	dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
19049a0bf528SMauro Carvalho Chehab }
19059a0bf528SMauro Carvalho Chehab 
19069a0bf528SMauro Carvalho Chehab u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
19079a0bf528SMauro Carvalho Chehab {
19089a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
19099a0bf528SMauro Carvalho Chehab 
19109a0bf528SMauro Carvalho Chehab 	switch (op) {
19119a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_SET:
19129a0bf528SMauro Carvalho Chehab 			state->timf = timf;
19139a0bf528SMauro Carvalho Chehab 			break;
19149a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_UPDATE:
19159a0bf528SMauro Carvalho Chehab 			dib8000_update_timf(state);
19169a0bf528SMauro Carvalho Chehab 			break;
19179a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_GET:
19189a0bf528SMauro Carvalho Chehab 			break;
19199a0bf528SMauro Carvalho Chehab 	}
19209a0bf528SMauro Carvalho Chehab 	dib8000_set_bandwidth(state->fe[0], 6000);
19219a0bf528SMauro Carvalho Chehab 
19229a0bf528SMauro Carvalho Chehab 	return state->timf;
19239a0bf528SMauro Carvalho Chehab }
19249a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_ctrl_timf);
19259a0bf528SMauro Carvalho Chehab 
19269a0bf528SMauro Carvalho Chehab static const u16 adc_target_16dB[11] = {
19279a0bf528SMauro Carvalho Chehab 	(1 << 13) - 825 - 117,
19289a0bf528SMauro Carvalho Chehab 	(1 << 13) - 837 - 117,
19299a0bf528SMauro Carvalho Chehab 	(1 << 13) - 811 - 117,
19309a0bf528SMauro Carvalho Chehab 	(1 << 13) - 766 - 117,
19319a0bf528SMauro Carvalho Chehab 	(1 << 13) - 737 - 117,
19329a0bf528SMauro Carvalho Chehab 	(1 << 13) - 693 - 117,
19339a0bf528SMauro Carvalho Chehab 	(1 << 13) - 648 - 117,
19349a0bf528SMauro Carvalho Chehab 	(1 << 13) - 619 - 117,
19359a0bf528SMauro Carvalho Chehab 	(1 << 13) - 575 - 117,
19369a0bf528SMauro Carvalho Chehab 	(1 << 13) - 531 - 117,
19379a0bf528SMauro Carvalho Chehab 	(1 << 13) - 501 - 117
19389a0bf528SMauro Carvalho Chehab };
19399a0bf528SMauro Carvalho Chehab static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
19409a0bf528SMauro Carvalho Chehab 
1941173a64cbSPatrick Boettcher static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
19429a0bf528SMauro Carvalho Chehab {
1943173a64cbSPatrick Boettcher 	u8  cr, constellation, time_intlv;
19449a0bf528SMauro Carvalho Chehab 
1945173a64cbSPatrick Boettcher 	switch (state->fe[0]->dtv_property_cache.layer[layer_index].modulation) {
19469a0bf528SMauro Carvalho Chehab 	case DQPSK:
19479a0bf528SMauro Carvalho Chehab 			constellation = 0;
19489a0bf528SMauro Carvalho Chehab 			break;
19499a0bf528SMauro Carvalho Chehab 	case  QPSK:
19509a0bf528SMauro Carvalho Chehab 			constellation = 1;
19519a0bf528SMauro Carvalho Chehab 			break;
19529a0bf528SMauro Carvalho Chehab 	case QAM_16:
19539a0bf528SMauro Carvalho Chehab 			constellation = 2;
19549a0bf528SMauro Carvalho Chehab 			break;
19559a0bf528SMauro Carvalho Chehab 	case QAM_64:
19569a0bf528SMauro Carvalho Chehab 	default:
19579a0bf528SMauro Carvalho Chehab 			constellation = 3;
19589a0bf528SMauro Carvalho Chehab 			break;
19599a0bf528SMauro Carvalho Chehab 	}
19609a0bf528SMauro Carvalho Chehab 
1961173a64cbSPatrick Boettcher 	switch (state->fe[0]->dtv_property_cache.layer[layer_index].fec) {
19629a0bf528SMauro Carvalho Chehab 	case FEC_1_2:
1963173a64cbSPatrick Boettcher 			cr = 1;
19649a0bf528SMauro Carvalho Chehab 			break;
19659a0bf528SMauro Carvalho Chehab 	case FEC_2_3:
1966173a64cbSPatrick Boettcher 			cr = 2;
19679a0bf528SMauro Carvalho Chehab 			break;
19689a0bf528SMauro Carvalho Chehab 	case FEC_3_4:
1969173a64cbSPatrick Boettcher 			cr = 3;
19709a0bf528SMauro Carvalho Chehab 			break;
19719a0bf528SMauro Carvalho Chehab 	case FEC_5_6:
1972173a64cbSPatrick Boettcher 			cr = 5;
19739a0bf528SMauro Carvalho Chehab 			break;
19749a0bf528SMauro Carvalho Chehab 	case FEC_7_8:
19759a0bf528SMauro Carvalho Chehab 	default:
1976173a64cbSPatrick Boettcher 			cr = 7;
19779a0bf528SMauro Carvalho Chehab 			break;
19789a0bf528SMauro Carvalho Chehab 	}
19799a0bf528SMauro Carvalho Chehab 
1980173a64cbSPatrick Boettcher 	if ((state->fe[0]->dtv_property_cache.layer[layer_index].interleaving > 0) && ((state->fe[0]->dtv_property_cache.layer[layer_index].interleaving <= 3) || (state->fe[0]->dtv_property_cache.layer[layer_index].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)))
1981173a64cbSPatrick Boettcher 		time_intlv = state->fe[0]->dtv_property_cache.layer[layer_index].interleaving;
19829a0bf528SMauro Carvalho Chehab 	else
1983173a64cbSPatrick Boettcher 		time_intlv = 0;
1984173a64cbSPatrick Boettcher 
1985173a64cbSPatrick Boettcher 	dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
1986173a64cbSPatrick Boettcher 	if (state->fe[0]->dtv_property_cache.layer[layer_index].segment_count > 0) {
19879a0bf528SMauro Carvalho Chehab 		switch (max_constellation) {
19889a0bf528SMauro Carvalho Chehab 		case DQPSK:
19899a0bf528SMauro Carvalho Chehab 		case QPSK:
1990173a64cbSPatrick Boettcher 				if (state->fe[0]->dtv_property_cache.layer[layer_index].modulation == QAM_16 || state->fe[0]->dtv_property_cache.layer[layer_index].modulation == QAM_64)
1991173a64cbSPatrick Boettcher 					max_constellation = state->fe[0]->dtv_property_cache.layer[layer_index].modulation;
19929a0bf528SMauro Carvalho Chehab 				break;
19939a0bf528SMauro Carvalho Chehab 		case QAM_16:
1994173a64cbSPatrick Boettcher 				if (state->fe[0]->dtv_property_cache.layer[layer_index].modulation == QAM_64)
1995173a64cbSPatrick Boettcher 					max_constellation = state->fe[0]->dtv_property_cache.layer[layer_index].modulation;
19969a0bf528SMauro Carvalho Chehab 				break;
19979a0bf528SMauro Carvalho Chehab 		}
19989a0bf528SMauro Carvalho Chehab 	}
1999173a64cbSPatrick Boettcher 
2000173a64cbSPatrick Boettcher 	return  max_constellation;
20019a0bf528SMauro Carvalho Chehab }
20029a0bf528SMauro Carvalho Chehab 
2003173a64cbSPatrick 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 */
2004173a64cbSPatrick 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 */
2005173a64cbSPatrick 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 */
2006173a64cbSPatrick Boettcher static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation)
2007173a64cbSPatrick Boettcher {
2008173a64cbSPatrick Boettcher 	u16 i, ana_gain = 0;
2009173a64cbSPatrick Boettcher 	const u16 *adp;
20109a0bf528SMauro Carvalho Chehab 
2011173a64cbSPatrick Boettcher 	/* channel estimation fine configuration */
2012173a64cbSPatrick Boettcher 	switch (max_constellation) {
2013173a64cbSPatrick Boettcher 	case QAM_64:
2014173a64cbSPatrick Boettcher 			ana_gain = 0x7;
2015173a64cbSPatrick Boettcher 			adp = &adp_Q64[0];
2016173a64cbSPatrick Boettcher 			break;
2017173a64cbSPatrick Boettcher 	case QAM_16:
2018173a64cbSPatrick Boettcher 			ana_gain = 0x7;
2019173a64cbSPatrick Boettcher 			adp = &adp_Q16[0];
2020173a64cbSPatrick Boettcher 			break;
2021173a64cbSPatrick Boettcher 	default:
2022173a64cbSPatrick Boettcher 			ana_gain = 0;
2023173a64cbSPatrick Boettcher 			adp = &adp_Qdefault[0];
2024173a64cbSPatrick Boettcher 			break;
20259a0bf528SMauro Carvalho Chehab 	}
20269a0bf528SMauro Carvalho Chehab 
2027173a64cbSPatrick Boettcher 	for (i = 0; i < 4; i++)
2028173a64cbSPatrick Boettcher 		dib8000_write_word(state, 215 + i, adp[i]);
20299a0bf528SMauro Carvalho Chehab 
2030173a64cbSPatrick Boettcher 	return ana_gain;
2031173a64cbSPatrick Boettcher }
20329a0bf528SMauro Carvalho Chehab 
2033173a64cbSPatrick Boettcher static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain)
2034173a64cbSPatrick Boettcher {
2035173a64cbSPatrick Boettcher 	u16 i;
20369a0bf528SMauro Carvalho Chehab 
2037173a64cbSPatrick Boettcher 	dib8000_write_word(state, 116, ana_gain);
20389a0bf528SMauro Carvalho Chehab 
2039173a64cbSPatrick Boettcher 	/* update ADC target depending on ana_gain */
2040173a64cbSPatrick Boettcher 	if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */
2041173a64cbSPatrick Boettcher 		for (i = 0; i < 10; i++)
2042173a64cbSPatrick Boettcher 			dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
2043173a64cbSPatrick Boettcher 	} else { /* set -22dB ADC target for ana_gain=0 */
2044173a64cbSPatrick Boettcher 		for (i = 0; i < 10; i++)
2045173a64cbSPatrick Boettcher 			dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
2046173a64cbSPatrick Boettcher 	}
2047173a64cbSPatrick Boettcher }
20489a0bf528SMauro Carvalho Chehab 
2049173a64cbSPatrick Boettcher static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
2050173a64cbSPatrick Boettcher {
2051173a64cbSPatrick Boettcher 	u16 mode = 0;
20529a0bf528SMauro Carvalho Chehab 
2053173a64cbSPatrick Boettcher 	if (state->isdbt_cfg_loaded == 0)
2054173a64cbSPatrick Boettcher 		for (mode = 0; mode < 24; mode++)
2055173a64cbSPatrick Boettcher 			dib8000_write_word(state, 117 + mode, ana_fe[mode]);
2056173a64cbSPatrick Boettcher }
20579a0bf528SMauro Carvalho Chehab 
2058173a64cbSPatrick Boettcher static const u16 lut_prbs_2k[14] = {
2059173a64cbSPatrick Boettcher 	0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213
2060173a64cbSPatrick Boettcher };
2061173a64cbSPatrick Boettcher static const u16 lut_prbs_4k[14] = {
2062173a64cbSPatrick Boettcher 	0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E
2063173a64cbSPatrick Boettcher };
2064173a64cbSPatrick Boettcher static const u16 lut_prbs_8k[14] = {
2065173a64cbSPatrick Boettcher 	0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684
2066173a64cbSPatrick Boettcher };
2067173a64cbSPatrick Boettcher 
2068173a64cbSPatrick Boettcher static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
2069173a64cbSPatrick Boettcher {
2070173a64cbSPatrick Boettcher 	int sub_channel_prbs_group = 0;
2071173a64cbSPatrick Boettcher 
2072173a64cbSPatrick Boettcher 	sub_channel_prbs_group = (subchannel / 3) + 1;
2073173a64cbSPatrick Boettcher 	dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]);
2074173a64cbSPatrick Boettcher 
20759a0bf528SMauro Carvalho Chehab 	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
20769a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
2077173a64cbSPatrick Boettcher 			return lut_prbs_2k[sub_channel_prbs_group];
20789a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
2079173a64cbSPatrick Boettcher 			return lut_prbs_4k[sub_channel_prbs_group];
20809a0bf528SMauro Carvalho Chehab 	default:
2081173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2082173a64cbSPatrick Boettcher 			return lut_prbs_8k[sub_channel_prbs_group];
20839a0bf528SMauro Carvalho Chehab 	}
20849a0bf528SMauro Carvalho Chehab }
20859a0bf528SMauro Carvalho Chehab 
2086173a64cbSPatrick Boettcher static void dib8000_set_13seg_channel(struct dib8000_state *state)
2087173a64cbSPatrick Boettcher {
2088173a64cbSPatrick Boettcher 	u16 i;
2089173a64cbSPatrick Boettcher 	u16 coff_pow = 0x2800;
20909a0bf528SMauro Carvalho Chehab 
2091173a64cbSPatrick Boettcher 	state->seg_mask = 0x1fff; /* All 13 segments enabled */
20929a0bf528SMauro Carvalho Chehab 
2093173a64cbSPatrick Boettcher 	/* ---- COFF ---- Carloff, the most robust --- */
2094173a64cbSPatrick Boettcher 	if (state->isdbt_cfg_loaded == 0) {  /* if not Sound Broadcasting mode : put default values for 13 segments */
20959a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 180, (16 << 6) | 9);
20969a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
20979a0bf528SMauro Carvalho Chehab 		coff_pow = 0x2800;
20989a0bf528SMauro Carvalho Chehab 		for (i = 0; i < 6; i++)
20999a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 181+i, coff_pow);
21009a0bf528SMauro Carvalho Chehab 
2101173a64cbSPatrick Boettcher 		/* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */
2102173a64cbSPatrick 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 */
21039a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
21049a0bf528SMauro Carvalho Chehab 
2105173a64cbSPatrick Boettcher 		/* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */
21069a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
2107173a64cbSPatrick Boettcher 		/* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */
21089a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
21099a0bf528SMauro Carvalho Chehab 
2110173a64cbSPatrick Boettcher 		dib8000_write_word(state, 228, 0);  /* default value */
2111173a64cbSPatrick Boettcher 		dib8000_write_word(state, 265, 31); /* default value */
2112173a64cbSPatrick Boettcher 		dib8000_write_word(state, 205, 0x200f); /* init value */
2113173a64cbSPatrick Boettcher 	}
2114173a64cbSPatrick Boettcher 
2115173a64cbSPatrick Boettcher 	/*
2116173a64cbSPatrick Boettcher 	 * make the cpil_coff_lock more robust but slower p_coff_winlen
21179a0bf528SMauro Carvalho Chehab 	 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
21189a0bf528SMauro Carvalho Chehab 	 */
21199a0bf528SMauro Carvalho Chehab 
2120173a64cbSPatrick Boettcher 	if (state->cfg.pll->ifreq == 0)
2121173a64cbSPatrick Boettcher 		dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
21229a0bf528SMauro Carvalho Chehab 
2123173a64cbSPatrick Boettcher 	dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg);
2124173a64cbSPatrick Boettcher }
21259a0bf528SMauro Carvalho Chehab 
2126173a64cbSPatrick Boettcher static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs)
2127173a64cbSPatrick Boettcher {
2128173a64cbSPatrick Boettcher 	u16 reg_1;
21299a0bf528SMauro Carvalho Chehab 
2130173a64cbSPatrick Boettcher 	reg_1 = dib8000_read_word(state, 1);
2131173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */
2132173a64cbSPatrick Boettcher }
21339a0bf528SMauro Carvalho Chehab 
2134173a64cbSPatrick Boettcher static void dib8000_small_fine_tune(struct dib8000_state *state)
2135173a64cbSPatrick Boettcher {
2136173a64cbSPatrick Boettcher 	u16 i;
2137173a64cbSPatrick Boettcher 	const s16 *ncoeff;
21389a0bf528SMauro Carvalho Chehab 
2139173a64cbSPatrick Boettcher 	dib8000_write_word(state, 352, state->seg_diff_mask);
2140173a64cbSPatrick Boettcher 	dib8000_write_word(state, 353, state->seg_mask);
21419a0bf528SMauro Carvalho Chehab 
2142173a64cbSPatrick 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 */
2143173a64cbSPatrick Boettcher 	dib8000_write_word(state, 351, (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 9) | (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5);
2144173a64cbSPatrick Boettcher 
2145173a64cbSPatrick Boettcher 	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
2146173a64cbSPatrick Boettcher 		/* ---- SMALL ---- */
21479a0bf528SMauro Carvalho Chehab 		switch (state->fe[0]->dtv_property_cache.transmission_mode) {
2148173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_2K:
2149173a64cbSPatrick Boettcher 				if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* 1-seg */
2150173a64cbSPatrick Boettcher 					if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) /* DQPSK */
2151173a64cbSPatrick Boettcher 						ncoeff = coeff_2k_sb_1seg_dqpsk;
2152173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2153173a64cbSPatrick Boettcher 						ncoeff = coeff_2k_sb_1seg;
2154173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2155173a64cbSPatrick Boettcher 					if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2156173a64cbSPatrick Boettcher 						if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
2157173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
2158173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2159173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg_0dqpsk;
2160173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2161173a64cbSPatrick Boettcher 						if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
2162173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg_1dqpsk;
2163173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2164173a64cbSPatrick Boettcher 							ncoeff = coeff_2k_sb_3seg;
2165173a64cbSPatrick Boettcher 					}
2166173a64cbSPatrick Boettcher 				}
21679a0bf528SMauro Carvalho Chehab 				break;
21689a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_4K:
2169173a64cbSPatrick Boettcher 				if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* 1-seg */
2170173a64cbSPatrick Boettcher 					if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) /* DQPSK */
2171173a64cbSPatrick Boettcher 						ncoeff = coeff_4k_sb_1seg_dqpsk;
2172173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2173173a64cbSPatrick Boettcher 						ncoeff = coeff_4k_sb_1seg;
2174173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2175173a64cbSPatrick Boettcher 					if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2176173a64cbSPatrick Boettcher 						if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
2177173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
2178173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2179173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_0dqpsk;
2180173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2181173a64cbSPatrick Boettcher 						if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
2182173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg_1dqpsk;
2183173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2184173a64cbSPatrick Boettcher 							ncoeff = coeff_4k_sb_3seg;
2185173a64cbSPatrick Boettcher 					}
2186173a64cbSPatrick Boettcher 				}
21879a0bf528SMauro Carvalho Chehab 				break;
2188173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_AUTO:
2189173a64cbSPatrick Boettcher 		case TRANSMISSION_MODE_8K:
21909a0bf528SMauro Carvalho Chehab 		default:
2191173a64cbSPatrick Boettcher 				if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* 1-seg */
2192173a64cbSPatrick Boettcher 					if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) /* DQPSK */
2193173a64cbSPatrick Boettcher 						ncoeff = coeff_8k_sb_1seg_dqpsk;
2194173a64cbSPatrick Boettcher 					else /* QPSK or QAM */
2195173a64cbSPatrick Boettcher 						ncoeff = coeff_8k_sb_1seg;
2196173a64cbSPatrick Boettcher 				} else { /* 3-segments */
2197173a64cbSPatrick Boettcher 					if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2198173a64cbSPatrick Boettcher 						if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
2199173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
2200173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2201173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_0dqpsk;
2202173a64cbSPatrick Boettcher 					} else { /* QPSK or QAM on central segment */
2203173a64cbSPatrick Boettcher 						if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
2204173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg_1dqpsk;
2205173a64cbSPatrick Boettcher 						else /* QPSK or QAM on external segments */
2206173a64cbSPatrick Boettcher 							ncoeff = coeff_8k_sb_3seg;
2207173a64cbSPatrick Boettcher 					}
2208173a64cbSPatrick Boettcher 				}
22099a0bf528SMauro Carvalho Chehab 				break;
22109a0bf528SMauro Carvalho Chehab 		}
2211173a64cbSPatrick Boettcher 
2212173a64cbSPatrick Boettcher 		for (i = 0; i < 8; i++)
2213173a64cbSPatrick Boettcher 			dib8000_write_word(state, 343 + i, ncoeff[i]);
2214173a64cbSPatrick Boettcher 	}
2215173a64cbSPatrick Boettcher }
2216173a64cbSPatrick Boettcher 
2217173a64cbSPatrick Boettcher static const u16 coff_thres_1seg[3] = {300, 150, 80};
2218173a64cbSPatrick Boettcher static const u16 coff_thres_3seg[3] = {350, 300, 250};
2219173a64cbSPatrick Boettcher static void dib8000_set_sb_channel(struct dib8000_state *state)
2220173a64cbSPatrick Boettcher {
2221173a64cbSPatrick Boettcher 	const u16 *coff;
2222173a64cbSPatrick Boettcher 	u16 i;
2223173a64cbSPatrick Boettcher 
2224173a64cbSPatrick Boettcher 	if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K || state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) {
2225173a64cbSPatrick Boettcher 		dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */
2226173a64cbSPatrick Boettcher 		dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */
2227173a64cbSPatrick Boettcher 	} else {
2228173a64cbSPatrick Boettcher 		dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */
2229173a64cbSPatrick Boettcher 		dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */
2230173a64cbSPatrick Boettcher 	}
2231173a64cbSPatrick Boettcher 
2232173a64cbSPatrick Boettcher 	if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) /* 3-segments */
2233173a64cbSPatrick Boettcher 		state->seg_mask = 0x00E0;
2234173a64cbSPatrick Boettcher 	else /* 1-segment */
2235173a64cbSPatrick Boettcher 		state->seg_mask = 0x0040;
2236173a64cbSPatrick Boettcher 
2237173a64cbSPatrick Boettcher 	dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2238173a64cbSPatrick Boettcher 
2239173a64cbSPatrick Boettcher 	/* ---- COFF ---- Carloff, the most robust --- */
2240173a64cbSPatrick 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 */
2241173a64cbSPatrick Boettcher 	dib8000_write_word(state, 187, (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2) | 0x3);
2242173a64cbSPatrick Boettcher 
2243173a64cbSPatrick Boettcher 	dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */
2244173a64cbSPatrick 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 */
2245173a64cbSPatrick Boettcher 
2246173a64cbSPatrick Boettcher 	/* Sound Broadcasting mode 1 seg */
2247173a64cbSPatrick Boettcher 	if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
2248173a64cbSPatrick 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) */
2249173a64cbSPatrick Boettcher 		if (state->mode == 3)
2250173a64cbSPatrick Boettcher 			dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14));
22519a0bf528SMauro Carvalho Chehab 		else
2252173a64cbSPatrick Boettcher 			dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14));
2253173a64cbSPatrick Boettcher 
2254173a64cbSPatrick 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 */
2255173a64cbSPatrick Boettcher 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
2256173a64cbSPatrick Boettcher 		coff = &coff_thres_1seg[0];
2257173a64cbSPatrick Boettcher 	} else {   /* Sound Broadcasting mode 3 seg */
2258173a64cbSPatrick Boettcher 		dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
2259173a64cbSPatrick 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 */
2260173a64cbSPatrick Boettcher 		dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
2261173a64cbSPatrick Boettcher 		coff = &coff_thres_3seg[0];
2262173a64cbSPatrick Boettcher 	}
2263173a64cbSPatrick Boettcher 
2264173a64cbSPatrick Boettcher 	dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */
2265173a64cbSPatrick Boettcher 	dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */
2266173a64cbSPatrick Boettcher 
2267173a64cbSPatrick Boettcher 	if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0 && state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K)
2268173a64cbSPatrick Boettcher 		dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */
2269173a64cbSPatrick Boettcher 
2270173a64cbSPatrick Boettcher 	/* Write COFF thres */
2271173a64cbSPatrick Boettcher 	for (i = 0 ; i < 3; i++) {
2272173a64cbSPatrick Boettcher 		dib8000_write_word(state, 181+i, coff[i]);
2273173a64cbSPatrick Boettcher 		dib8000_write_word(state, 184+i, coff[i]);
2274173a64cbSPatrick Boettcher 	}
2275173a64cbSPatrick Boettcher 
2276173a64cbSPatrick Boettcher 	/*
2277173a64cbSPatrick Boettcher 	 * make the cpil_coff_lock more robust but slower p_coff_winlen
2278173a64cbSPatrick Boettcher 	 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2279173a64cbSPatrick Boettcher 	 */
2280173a64cbSPatrick Boettcher 
2281173a64cbSPatrick Boettcher 	dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */
2282173a64cbSPatrick Boettcher 
2283173a64cbSPatrick Boettcher 	if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
2284173a64cbSPatrick Boettcher 		dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */
2285173a64cbSPatrick Boettcher 	else
2286173a64cbSPatrick Boettcher 		dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2287173a64cbSPatrick Boettcher }
2288173a64cbSPatrick Boettcher 
2289173a64cbSPatrick Boettcher static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
2290173a64cbSPatrick Boettcher {
2291173a64cbSPatrick Boettcher 	u16 p_cfr_left_edge  = 0, p_cfr_right_edge = 0;
2292173a64cbSPatrick Boettcher 	u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ;
2293173a64cbSPatrick Boettcher 	u16 max_constellation = DQPSK;
2294173a64cbSPatrick Boettcher 	int init_prbs;
2295173a64cbSPatrick Boettcher 
2296173a64cbSPatrick Boettcher 	/* P_mode */
2297173a64cbSPatrick Boettcher 	dib8000_write_word(state, 10, (seq << 4));
2298173a64cbSPatrick Boettcher 
2299173a64cbSPatrick Boettcher 	/* init mode */
2300173a64cbSPatrick Boettcher 	state->mode = fft_to_mode(state);
2301173a64cbSPatrick Boettcher 
2302173a64cbSPatrick Boettcher 	/* set guard */
2303173a64cbSPatrick Boettcher 	tmp = dib8000_read_word(state, 1);
2304173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1, (tmp&0xfffc) | (state->fe[0]->dtv_property_cache.guard_interval & 0x3));
2305173a64cbSPatrick Boettcher 
2306173a64cbSPatrick Boettcher 	dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) | ((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache.isdbt_sb_mode & 1) << 4));
2307173a64cbSPatrick Boettcher 
2308173a64cbSPatrick Boettcher 	/* signal optimization parameter */
2309173a64cbSPatrick Boettcher 	if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) {
2310173a64cbSPatrick Boettcher 		state->seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0];
2311173a64cbSPatrick Boettcher 		for (i = 1; i < 3; i++)
2312173a64cbSPatrick Boettcher 			nbseg_diff += (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
2313173a64cbSPatrick Boettcher 		for (i = 0; i < nbseg_diff; i++)
2314173a64cbSPatrick Boettcher 			state->seg_diff_mask |= 1 << permu_seg[i+1];
2315173a64cbSPatrick Boettcher 	} else {
2316173a64cbSPatrick Boettcher 		for (i = 0; i < 3; i++)
2317173a64cbSPatrick Boettcher 			nbseg_diff += (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
2318173a64cbSPatrick Boettcher 		for (i = 0; i < nbseg_diff; i++)
2319173a64cbSPatrick Boettcher 			state->seg_diff_mask |= 1 << permu_seg[i];
2320173a64cbSPatrick Boettcher 	}
2321173a64cbSPatrick Boettcher 
2322173a64cbSPatrick Boettcher 	if (state->seg_diff_mask)
2323173a64cbSPatrick Boettcher 		dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2324173a64cbSPatrick Boettcher 	else
2325173a64cbSPatrick Boettcher 		dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */
2326173a64cbSPatrick Boettcher 
2327173a64cbSPatrick Boettcher 	for (i = 0; i < 3; i++)
2328173a64cbSPatrick Boettcher 		max_constellation = dib8000_set_layer(state, i, max_constellation);
2329173a64cbSPatrick Boettcher 	if (autosearching == 0) {
2330173a64cbSPatrick Boettcher 		state->layer_b_nb_seg = state->fe[0]->dtv_property_cache.layer[1].segment_count;
2331173a64cbSPatrick Boettcher 		state->layer_c_nb_seg = state->fe[0]->dtv_property_cache.layer[2].segment_count;
2332173a64cbSPatrick Boettcher 	}
2333173a64cbSPatrick Boettcher 
2334173a64cbSPatrick Boettcher 	/* WRITE: Mode & Diff mask */
2335173a64cbSPatrick Boettcher 	dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask);
2336173a64cbSPatrick Boettcher 
2337173a64cbSPatrick Boettcher 	state->differential_constellation = (state->seg_diff_mask != 0);
23389a0bf528SMauro Carvalho Chehab 
23399a0bf528SMauro Carvalho Chehab 	/* channel estimation fine configuration */
2340173a64cbSPatrick Boettcher 	ana_gain = dib8000_adp_fine_tune(state, max_constellation);
23419a0bf528SMauro Carvalho Chehab 
2342173a64cbSPatrick Boettcher 	/* update ana_gain depending on max constellation */
2343173a64cbSPatrick Boettcher 	dib8000_update_ana_gain(state, ana_gain);
23449a0bf528SMauro Carvalho Chehab 
2345173a64cbSPatrick Boettcher 	/* ---- ANA_FE ---- */
2346173a64cbSPatrick Boettcher 	if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) /* 3-segments */
2347173a64cbSPatrick Boettcher 		dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg);
2348173a64cbSPatrick Boettcher 	else
2349173a64cbSPatrick Boettcher 		dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */
2350173a64cbSPatrick Boettcher 
2351173a64cbSPatrick Boettcher 	/* TSB or ISDBT ? apply it now */
23529a0bf528SMauro Carvalho Chehab 	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
2353173a64cbSPatrick Boettcher 		dib8000_set_sb_channel(state);
2354173a64cbSPatrick Boettcher 		if (state->fe[0]->dtv_property_cache.isdbt_sb_subchannel != -1)
2355173a64cbSPatrick Boettcher 			init_prbs = dib8000_get_init_prbs(state, state->fe[0]->dtv_property_cache.isdbt_sb_subchannel);
2356173a64cbSPatrick Boettcher 		else
2357173a64cbSPatrick Boettcher 			init_prbs = 0;
2358173a64cbSPatrick Boettcher 	} else {
2359173a64cbSPatrick Boettcher 		dib8000_set_13seg_channel(state);
2360173a64cbSPatrick Boettcher 		init_prbs = 0xfff;
2361173a64cbSPatrick Boettcher 	}
23629a0bf528SMauro Carvalho Chehab 
2363173a64cbSPatrick Boettcher 	/* SMALL */
2364173a64cbSPatrick Boettcher 	dib8000_small_fine_tune(state);
23659a0bf528SMauro Carvalho Chehab 
2366173a64cbSPatrick Boettcher 	dib8000_set_subchannel_prbs(state, init_prbs);
2367173a64cbSPatrick Boettcher 
2368173a64cbSPatrick Boettcher 	/* ---- CHAN_BLK ---- */
23699a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 13; i++) {
2370173a64cbSPatrick Boettcher 		if ((((~state->seg_diff_mask) >> i) & 1) == 1) {
2371173a64cbSPatrick Boettcher 			p_cfr_left_edge  += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0));
2372173a64cbSPatrick Boettcher 			p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0));
23739a0bf528SMauro Carvalho Chehab 		}
23749a0bf528SMauro Carvalho Chehab 	}
2375173a64cbSPatrick Boettcher 	dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */
2376173a64cbSPatrick Boettcher 	dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */
2377173a64cbSPatrick Boettcher 	/* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */
23789a0bf528SMauro Carvalho Chehab 
2379173a64cbSPatrick Boettcher 	dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */
2380173a64cbSPatrick Boettcher 	dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */
2381173a64cbSPatrick Boettcher 	dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */
2382173a64cbSPatrick Boettcher 
2383173a64cbSPatrick Boettcher 	if (!autosearching)
2384173a64cbSPatrick Boettcher 		dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
2385173a64cbSPatrick Boettcher 	else
2386173a64cbSPatrick Boettcher 		dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */
2387173a64cbSPatrick Boettcher 
2388173a64cbSPatrick Boettcher 	dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */
2389173a64cbSPatrick Boettcher 	dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */
2390173a64cbSPatrick Boettcher 
2391173a64cbSPatrick Boettcher 	dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2392173a64cbSPatrick Boettcher 
2393173a64cbSPatrick Boettcher 	/* ---- TMCC ---- */
23949a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 3; i++)
2395173a64cbSPatrick Boettcher 		tmcc_pow += (((state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe[0]->dtv_property_cache.layer[i].segment_count) ;
2396173a64cbSPatrick Boettcher 
2397173a64cbSPatrick Boettcher 	/* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */
2398173a64cbSPatrick Boettcher 	/* Threshold is set at 1/4 of max power. */
23999a0bf528SMauro Carvalho Chehab 	tmcc_pow *= (1 << (9-2));
2400173a64cbSPatrick Boettcher 	dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */
2401173a64cbSPatrick Boettcher 	dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */
2402173a64cbSPatrick Boettcher 	dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */
2403173a64cbSPatrick Boettcher 	/*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */
24049a0bf528SMauro Carvalho Chehab 
2405173a64cbSPatrick Boettcher 	/* ---- PHA3 ---- */
24069a0bf528SMauro Carvalho Chehab 	if (state->isdbt_cfg_loaded == 0)
24079a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */
24089a0bf528SMauro Carvalho Chehab 
24099a0bf528SMauro Carvalho Chehab 	state->isdbt_cfg_loaded = 0;
2410173a64cbSPatrick Boettcher }
24119a0bf528SMauro Carvalho Chehab 
2412173a64cbSPatrick Boettcher u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal, u32 wait0_ms, u32 wait1_ms, u32 wait2_ms)
2413173a64cbSPatrick Boettcher {
2414173a64cbSPatrick Boettcher 	u32 value;
2415173a64cbSPatrick Boettcher 	u16 reg = 11; /* P_search_end0 start addr */
2416173a64cbSPatrick Boettcher 
2417173a64cbSPatrick Boettcher 	for (reg = 11; reg < 16; reg += 2) {
2418173a64cbSPatrick Boettcher 		if (reg == 11) {
2419173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
2420173a64cbSPatrick Boettcher 				value = internal * wait1_ms; /* P_search_end0 wait time */
2421173a64cbSPatrick Boettcher 			else
2422173a64cbSPatrick Boettcher 				value = internal * wait0_ms; /* P_search_end0 wait time */
2423173a64cbSPatrick Boettcher 		} else if (reg == 13)
2424173a64cbSPatrick Boettcher 			value = internal * wait1_ms; /* P_search_end0 wait time */
2425173a64cbSPatrick Boettcher 		else if (reg == 15)
2426173a64cbSPatrick Boettcher 			value = internal * wait2_ms; /* P_search_end0 wait time */
2427173a64cbSPatrick Boettcher 		dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff));
2428173a64cbSPatrick Boettcher 		dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff));
2429173a64cbSPatrick Boettcher 	}
2430173a64cbSPatrick Boettcher 	return value;
24319a0bf528SMauro Carvalho Chehab }
24329a0bf528SMauro Carvalho Chehab 
24339a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_start(struct dvb_frontend *fe)
24349a0bf528SMauro Carvalho Chehab {
24359a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
2436173a64cbSPatrick Boettcher 	u8 slist = 0;
2437173a64cbSPatrick Boettcher 	u32 value, internal = state->cfg.pll->internal;
24389a0bf528SMauro Carvalho Chehab 
2439173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
2440173a64cbSPatrick Boettcher 		internal = dib8000_read32(state, 23) / 1000;
24419a0bf528SMauro Carvalho Chehab 
2442173a64cbSPatrick Boettcher 	if (state->autosearch_state == AS_SEARCHING_FFT) {
2443173a64cbSPatrick Boettcher 		dib8000_write_word(state,  37, 0x0065); /* P_ctrl_pha_off_max default values */
2444173a64cbSPatrick Boettcher 		dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
2445173a64cbSPatrick Boettcher 
2446173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */
2447173a64cbSPatrick Boettcher 		dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */
2448173a64cbSPatrick Boettcher 		dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */
2449173a64cbSPatrick Boettcher 		dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */
2450173a64cbSPatrick Boettcher 		dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */
2451173a64cbSPatrick Boettcher 		dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */
2452173a64cbSPatrick Boettcher 
2453173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2454173a64cbSPatrick Boettcher 			value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2455173a64cbSPatrick Boettcher 		else
2456173a64cbSPatrick Boettcher 			value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2457173a64cbSPatrick Boettcher 
2458173a64cbSPatrick Boettcher 		dib8000_write_word(state, 17, 0);
2459173a64cbSPatrick Boettcher 		dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */
2460173a64cbSPatrick Boettcher 		dib8000_write_word(state, 19, 0);
2461173a64cbSPatrick Boettcher 		dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */
2462173a64cbSPatrick Boettcher 		dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */
2463173a64cbSPatrick Boettcher 		dib8000_write_word(state, 22, value & 0xffff);
2464173a64cbSPatrick Boettcher 
2465173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2466173a64cbSPatrick Boettcher 			dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */
2467173a64cbSPatrick Boettcher 		else
2468173a64cbSPatrick Boettcher 			dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */
2469173a64cbSPatrick Boettcher 		dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */
2470173a64cbSPatrick Boettcher 
2471173a64cbSPatrick Boettcher 		/* P_search_param_select = (1 | 1<<4 | 1 << 8) */
2472173a64cbSPatrick Boettcher 		dib8000_write_word(state, 356, 0);
2473173a64cbSPatrick Boettcher 		dib8000_write_word(state, 357, 0x111);
2474173a64cbSPatrick Boettcher 
2475173a64cbSPatrick Boettcher 		dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
2476173a64cbSPatrick Boettcher 		dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
2477173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */
2478173a64cbSPatrick Boettcher 	} else if (state->autosearch_state == AS_SEARCHING_GUARD) {
2479173a64cbSPatrick Boettcher 		state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
2480173a64cbSPatrick Boettcher 		state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
24819a0bf528SMauro Carvalho Chehab 		state->fe[0]->dtv_property_cache.inversion = 0;
24829a0bf528SMauro Carvalho Chehab 		state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64;
24839a0bf528SMauro Carvalho Chehab 		state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3;
24849a0bf528SMauro Carvalho Chehab 		state->fe[0]->dtv_property_cache.layer[0].interleaving = 0;
2485173a64cbSPatrick Boettcher 		state->fe[0]->dtv_property_cache.layer[0].segment_count = 13;
24869a0bf528SMauro Carvalho Chehab 
2487173a64cbSPatrick Boettcher 		slist = 16;
2488173a64cbSPatrick Boettcher 		state->fe[0]->dtv_property_cache.transmission_mode = state->found_nfft;
2489173a64cbSPatrick Boettcher 
2490173a64cbSPatrick Boettcher 		dib8000_set_isdbt_common_channel(state, slist, 1);
2491173a64cbSPatrick Boettcher 
2492173a64cbSPatrick Boettcher 		/* set lock_mask values */
2493173a64cbSPatrick Boettcher 		dib8000_write_word(state, 6, 0x4);
2494173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2495173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */
2496173a64cbSPatrick Boettcher 		else
2497173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, 0x8);
2498173a64cbSPatrick Boettcher 		dib8000_write_word(state, 8, 0x1000);
2499173a64cbSPatrick Boettcher 
2500173a64cbSPatrick Boettcher 		/* set lock_mask wait time values */
2501173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2502173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2503173a64cbSPatrick Boettcher 		else
2504173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2505173a64cbSPatrick Boettcher 
2506173a64cbSPatrick Boettcher 		dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */
2507173a64cbSPatrick Boettcher 
2508173a64cbSPatrick Boettcher 		/* P_search_param_select = 0xf; look for the 4 different guard intervals */
2509173a64cbSPatrick Boettcher 		dib8000_write_word(state, 356, 0);
2510173a64cbSPatrick Boettcher 		dib8000_write_word(state, 357, 0xf);
2511173a64cbSPatrick Boettcher 
2512173a64cbSPatrick Boettcher 		value = dib8000_read_word(state, 0);
2513173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2514173a64cbSPatrick Boettcher 		dib8000_read_word(state, 1284);  /* reset the INT. n_irq_pending */
2515173a64cbSPatrick Boettcher 		dib8000_write_word(state, 0, (u16)value);
2516173a64cbSPatrick Boettcher 	} else {
2517173a64cbSPatrick Boettcher 		state->fe[0]->dtv_property_cache.inversion = 0;
2518173a64cbSPatrick Boettcher 		state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64;
2519173a64cbSPatrick Boettcher 		state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3;
2520173a64cbSPatrick Boettcher 		state->fe[0]->dtv_property_cache.layer[0].interleaving = 0;
2521173a64cbSPatrick Boettcher 		state->fe[0]->dtv_property_cache.layer[0].segment_count = 13;
2522173a64cbSPatrick Boettcher 		if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode)
2523173a64cbSPatrick Boettcher 			state->fe[0]->dtv_property_cache.layer[0].segment_count = 13;
2524173a64cbSPatrick Boettcher 
2525173a64cbSPatrick Boettcher 		/* choose the right list, in sb, always do everything */
25269a0bf528SMauro Carvalho Chehab 		if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
25279a0bf528SMauro Carvalho Chehab 			slist = 7;
25289a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
25299a0bf528SMauro Carvalho Chehab 		} else {
25309a0bf528SMauro Carvalho Chehab 			if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) {
25319a0bf528SMauro Carvalho Chehab 				if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
2532173a64cbSPatrick Boettcher 					state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
2533173a64cbSPatrick Boettcher 					state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
25349a0bf528SMauro Carvalho Chehab 					slist = 7;
2535173a64cbSPatrick Boettcher 					dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));  /* P_mode = 1 to have autosearch start ok with mode2 */
2536173a64cbSPatrick Boettcher 				} else {
2537173a64cbSPatrick Boettcher 					state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
25389a0bf528SMauro Carvalho Chehab 					slist = 3;
2539173a64cbSPatrick Boettcher 				}
25409a0bf528SMauro Carvalho Chehab 			} else {
25419a0bf528SMauro Carvalho Chehab 				if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
2542173a64cbSPatrick Boettcher 					state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
25439a0bf528SMauro Carvalho Chehab 					slist = 2;
2544173a64cbSPatrick Boettcher 					dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));  /* P_mode = 1 */
25459a0bf528SMauro Carvalho Chehab 				} else
25469a0bf528SMauro Carvalho Chehab 					slist = 0;
25479a0bf528SMauro Carvalho Chehab 			}
2548173a64cbSPatrick Boettcher 		}
2549173a64cbSPatrick Boettcher 		dprintk("Using list for autosearch : %d", slist);
25509a0bf528SMauro Carvalho Chehab 
2551173a64cbSPatrick Boettcher 		dib8000_set_isdbt_common_channel(state, slist, 1);
25529a0bf528SMauro Carvalho Chehab 
2553173a64cbSPatrick Boettcher 		/* set lock_mask values */
25549a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 6, 0x4);
2555173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2556173a64cbSPatrick Boettcher 			dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10));
2557173a64cbSPatrick Boettcher 		else
25589a0bf528SMauro Carvalho Chehab 			dib8000_write_word(state, 7, 0x8);
25599a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 8, 0x1000);
25609a0bf528SMauro Carvalho Chehab 
2561173a64cbSPatrick Boettcher 		/* set lock_mask wait time values */
2562173a64cbSPatrick Boettcher 		if (state->revision == 0x8090)
2563173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2564173a64cbSPatrick Boettcher 		else
2565173a64cbSPatrick Boettcher 			dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
25669a0bf528SMauro Carvalho Chehab 
25679a0bf528SMauro Carvalho Chehab 		value = dib8000_read_word(state, 0);
25689a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2569173a64cbSPatrick Boettcher 		dib8000_read_word(state, 1284);  /* reset the INT. n_irq_pending */
25709a0bf528SMauro Carvalho Chehab 		dib8000_write_word(state, 0, (u16)value);
25719a0bf528SMauro Carvalho Chehab 	}
25729a0bf528SMauro Carvalho Chehab 	return 0;
25739a0bf528SMauro Carvalho Chehab }
25749a0bf528SMauro Carvalho Chehab 
25759a0bf528SMauro Carvalho Chehab static int dib8000_autosearch_irq(struct dvb_frontend *fe)
25769a0bf528SMauro Carvalho Chehab {
25779a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
25789a0bf528SMauro Carvalho Chehab 	u16 irq_pending = dib8000_read_word(state, 1284);
25799a0bf528SMauro Carvalho Chehab 
2580173a64cbSPatrick Boettcher 	if (state->autosearch_state == AS_SEARCHING_FFT) {
2581173a64cbSPatrick Boettcher 		if (irq_pending & 0x1) {
2582173a64cbSPatrick Boettcher 			dprintk("dib8000_autosearch_irq: max correlation result available");
2583173a64cbSPatrick Boettcher 			return 3;
2584173a64cbSPatrick Boettcher 		}
2585173a64cbSPatrick Boettcher 	} else {
2586173a64cbSPatrick Boettcher 		if (irq_pending & 0x1) {	/* failed */
25879a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_autosearch_irq failed");
25889a0bf528SMauro Carvalho Chehab 			return 1;
25899a0bf528SMauro Carvalho Chehab 		}
25909a0bf528SMauro Carvalho Chehab 
2591173a64cbSPatrick Boettcher 		if (irq_pending & 0x2) {	/* succeeded */
25929a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_autosearch_irq succeeded");
25939a0bf528SMauro Carvalho Chehab 			return 2;
25949a0bf528SMauro Carvalho Chehab 		}
2595173a64cbSPatrick Boettcher 	}
25969a0bf528SMauro Carvalho Chehab 
25979a0bf528SMauro Carvalho Chehab 	return 0;		// still pending
25989a0bf528SMauro Carvalho Chehab }
25999a0bf528SMauro Carvalho Chehab 
2600173a64cbSPatrick Boettcher static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
2601173a64cbSPatrick Boettcher {
2602173a64cbSPatrick Boettcher 	u16 tmp;
2603173a64cbSPatrick Boettcher 
2604173a64cbSPatrick Boettcher 	tmp = dib8000_read_word(state, 771);
2605173a64cbSPatrick Boettcher 	if (onoff) /* start P_restart_chd : channel_decoder */
2606173a64cbSPatrick Boettcher 		dib8000_write_word(state, 771, tmp & 0xfffd);
2607173a64cbSPatrick Boettcher 	else /* stop P_restart_chd : channel_decoder */
2608173a64cbSPatrick Boettcher 		dib8000_write_word(state, 771, tmp | (1<<1));
2609173a64cbSPatrick Boettcher }
2610173a64cbSPatrick Boettcher 
2611173a64cbSPatrick Boettcher static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
2612173a64cbSPatrick Boettcher {
2613173a64cbSPatrick Boettcher 	s16 unit_khz_dds_val;
2614173a64cbSPatrick Boettcher 	u32 abs_offset_khz = ABS(offset_khz);
2615173a64cbSPatrick Boettcher 	u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
2616173a64cbSPatrick Boettcher 	u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
2617173a64cbSPatrick Boettcher 	u8 ratio;
2618173a64cbSPatrick Boettcher 
2619173a64cbSPatrick Boettcher 	if (state->revision == 0x8090) {
2620173a64cbSPatrick Boettcher 		ratio = 4;
2621173a64cbSPatrick Boettcher 		unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000);
2622173a64cbSPatrick Boettcher 		if (offset_khz < 0)
2623173a64cbSPatrick Boettcher 			dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
2624173a64cbSPatrick Boettcher 		else
2625173a64cbSPatrick Boettcher 			dds = (abs_offset_khz * unit_khz_dds_val);
2626173a64cbSPatrick Boettcher 
2627173a64cbSPatrick Boettcher 		if (invert)
2628173a64cbSPatrick Boettcher 			dds = (1<<26) - dds;
2629173a64cbSPatrick Boettcher 	} else {
2630173a64cbSPatrick Boettcher 		ratio = 2;
2631173a64cbSPatrick Boettcher 		unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
2632173a64cbSPatrick Boettcher 
2633173a64cbSPatrick Boettcher 		if (offset_khz < 0)
2634173a64cbSPatrick Boettcher 			unit_khz_dds_val *= -1;
2635173a64cbSPatrick Boettcher 
2636173a64cbSPatrick Boettcher 		/* IF tuner */
2637173a64cbSPatrick Boettcher 		if (invert)
2638173a64cbSPatrick Boettcher 			dds -= abs_offset_khz * unit_khz_dds_val;
2639173a64cbSPatrick Boettcher 		else
2640173a64cbSPatrick Boettcher 			dds += abs_offset_khz * unit_khz_dds_val;
2641173a64cbSPatrick Boettcher 	}
2642173a64cbSPatrick Boettcher 
2643173a64cbSPatrick Boettcher 	dprintk("setting a DDS frequency offset of %c%dkHz", invert ? '-' : ' ', dds / unit_khz_dds_val);
2644173a64cbSPatrick Boettcher 
2645173a64cbSPatrick Boettcher 	if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) {
2646173a64cbSPatrick Boettcher 		/* Max dds offset is the half of the demod freq */
2647173a64cbSPatrick Boettcher 		dib8000_write_word(state, 26, invert);
2648173a64cbSPatrick Boettcher 		dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff);
2649173a64cbSPatrick Boettcher 		dib8000_write_word(state, 28, (u16)(dds & 0xffff));
2650173a64cbSPatrick Boettcher 	}
2651173a64cbSPatrick Boettcher }
2652173a64cbSPatrick Boettcher 
2653173a64cbSPatrick Boettcher static void dib8000_set_frequency_offset(struct dib8000_state *state)
2654173a64cbSPatrick Boettcher {
2655173a64cbSPatrick Boettcher 	int i;
2656173a64cbSPatrick Boettcher 	u32 current_rf;
2657173a64cbSPatrick Boettcher 	int total_dds_offset_khz;
2658173a64cbSPatrick Boettcher 
2659173a64cbSPatrick Boettcher 	if (state->fe[0]->ops.tuner_ops.get_frequency)
2660173a64cbSPatrick Boettcher 		state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], &current_rf);
2661173a64cbSPatrick Boettcher 	else
2662173a64cbSPatrick Boettcher 		current_rf = state->fe[0]->dtv_property_cache.frequency;
2663173a64cbSPatrick Boettcher 	current_rf /= 1000;
2664173a64cbSPatrick Boettcher 	total_dds_offset_khz = (int)current_rf - (int)state->fe[0]->dtv_property_cache.frequency / 1000;
2665173a64cbSPatrick Boettcher 
2666173a64cbSPatrick Boettcher 	if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
2667173a64cbSPatrick Boettcher 		state->subchannel = state->fe[0]->dtv_property_cache.isdbt_sb_subchannel;
2668173a64cbSPatrick Boettcher 
2669173a64cbSPatrick Boettcher 		i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */
2670173a64cbSPatrick Boettcher 		dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion ^ i);
2671173a64cbSPatrick Boettcher 
2672173a64cbSPatrick Boettcher 		if (state->cfg.pll->ifreq == 0) { /* low if tuner */
2673173a64cbSPatrick Boettcher 			if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0)
2674173a64cbSPatrick Boettcher 				dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
2675173a64cbSPatrick Boettcher 		} else {
2676173a64cbSPatrick Boettcher 			if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0)
2677173a64cbSPatrick Boettcher 				total_dds_offset_khz *= -1;
2678173a64cbSPatrick Boettcher 		}
2679173a64cbSPatrick Boettcher 	}
2680173a64cbSPatrick Boettcher 
2681173a64cbSPatrick Boettcher 	dprintk("%dkhz tuner offset (frequency = %dHz & current_rf = %dHz) total_dds_offset_hz = %d", state->fe[0]->dtv_property_cache.frequency - current_rf, state->fe[0]->dtv_property_cache.frequency, current_rf, total_dds_offset_khz);
2682173a64cbSPatrick Boettcher 
2683173a64cbSPatrick Boettcher 	/* apply dds offset now */
2684173a64cbSPatrick Boettcher 	dib8000_set_dds(state, total_dds_offset_khz);
2685173a64cbSPatrick Boettcher }
2686173a64cbSPatrick Boettcher 
2687173a64cbSPatrick Boettcher static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 };
2688173a64cbSPatrick Boettcher u32 dib8000_get_symbol_duration(struct dib8000_state *state)
2689173a64cbSPatrick Boettcher {
2690173a64cbSPatrick Boettcher 	u16 i;
2691173a64cbSPatrick Boettcher 
2692173a64cbSPatrick Boettcher 	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
2693173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_2K:
2694173a64cbSPatrick Boettcher 			i = 0;
2695173a64cbSPatrick Boettcher 			break;
2696173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_4K:
2697173a64cbSPatrick Boettcher 			i = 2;
2698173a64cbSPatrick Boettcher 			break;
2699173a64cbSPatrick Boettcher 	default:
2700173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_AUTO:
2701173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2702173a64cbSPatrick Boettcher 			i = 1;
2703173a64cbSPatrick Boettcher 			break;
2704173a64cbSPatrick Boettcher 	}
2705173a64cbSPatrick Boettcher 
2706173a64cbSPatrick Boettcher 	return (LUT_isdbt_symbol_duration[i] / (state->fe[0]->dtv_property_cache.bandwidth_hz / 1000)) + 1;
2707173a64cbSPatrick Boettcher }
2708173a64cbSPatrick Boettcher 
2709173a64cbSPatrick Boettcher static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step)
2710173a64cbSPatrick Boettcher {
2711173a64cbSPatrick Boettcher 	u16 reg_32 = 0, reg_37 = 0;
2712173a64cbSPatrick Boettcher 
2713173a64cbSPatrick Boettcher 	switch (loop_step) {
2714173a64cbSPatrick Boettcher 	case LOOP_TUNE_1:
2715173a64cbSPatrick Boettcher 			if (state->fe[0]->dtv_property_cache.isdbt_sb_mode)  {
2716173a64cbSPatrick Boettcher 				if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
2717173a64cbSPatrick Boettcher 					reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */
2718173a64cbSPatrick 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)  */
2719173a64cbSPatrick Boettcher 				} else { /* Sound Broadcasting mode 3 seg */
2720173a64cbSPatrick Boettcher 					reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */
2721173a64cbSPatrick 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)  */
2722173a64cbSPatrick Boettcher 				}
2723173a64cbSPatrick Boettcher 			} else { /* 13-seg start conf offset loop parameters */
2724173a64cbSPatrick Boettcher 				reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
2725173a64cbSPatrick 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  */
2726173a64cbSPatrick Boettcher 			}
2727173a64cbSPatrick Boettcher 			break;
2728173a64cbSPatrick Boettcher 	case LOOP_TUNE_2:
2729173a64cbSPatrick Boettcher 			if (state->fe[0]->dtv_property_cache.isdbt_sb_mode)  {
2730173a64cbSPatrick Boettcher 				if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {  /* Sound Broadcasting mode 1 seg */
2731173a64cbSPatrick Boettcher 					reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/
2732173a64cbSPatrick Boettcher 					reg_37 = (12-state->mode) | ((5 + state->mode) << 5);
2733173a64cbSPatrick Boettcher 				} else {  /* Sound Broadcasting mode 3 seg */
2734173a64cbSPatrick Boettcher 					reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */
2735173a64cbSPatrick Boettcher 					reg_37 = (11-state->mode) | ((5 + state->mode) << 5);
2736173a64cbSPatrick Boettcher 				}
2737173a64cbSPatrick Boettcher 			} else {  /* 13 seg */
2738173a64cbSPatrick Boettcher 				reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */
2739173a64cbSPatrick Boettcher 				reg_37 = ((5+state->mode) << 5) | (10 - state->mode);
2740173a64cbSPatrick Boettcher 			}
2741173a64cbSPatrick Boettcher 			break;
2742173a64cbSPatrick Boettcher 	}
2743173a64cbSPatrick Boettcher 	dib8000_write_word(state, 32, reg_32);
2744173a64cbSPatrick Boettcher 	dib8000_write_word(state, 37, reg_37);
2745173a64cbSPatrick Boettcher }
2746173a64cbSPatrick Boettcher 
2747173a64cbSPatrick Boettcher static void dib8000_demod_restart(struct dib8000_state *state)
2748173a64cbSPatrick Boettcher {
2749173a64cbSPatrick Boettcher 	dib8000_write_word(state, 770, 0x4000);
2750173a64cbSPatrick Boettcher 	dib8000_write_word(state, 770, 0x0000);
2751173a64cbSPatrick Boettcher 	return;
2752173a64cbSPatrick Boettcher }
2753173a64cbSPatrick Boettcher 
2754173a64cbSPatrick Boettcher static void dib8000_set_sync_wait(struct dib8000_state *state)
2755173a64cbSPatrick Boettcher {
2756173a64cbSPatrick Boettcher 	u16 sync_wait = 64;
2757173a64cbSPatrick Boettcher 
2758173a64cbSPatrick Boettcher 	/* P_dvsy_sync_wait - reuse mode */
2759173a64cbSPatrick Boettcher 	switch (state->fe[0]->dtv_property_cache.transmission_mode) {
2760173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_8K:
2761173a64cbSPatrick Boettcher 			sync_wait = 256;
2762173a64cbSPatrick Boettcher 			break;
2763173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_4K:
2764173a64cbSPatrick Boettcher 			sync_wait = 128;
2765173a64cbSPatrick Boettcher 			break;
2766173a64cbSPatrick Boettcher 	default:
2767173a64cbSPatrick Boettcher 	case TRANSMISSION_MODE_2K:
2768173a64cbSPatrick Boettcher 			sync_wait =  64;
2769173a64cbSPatrick Boettcher 			break;
2770173a64cbSPatrick Boettcher 	}
2771173a64cbSPatrick Boettcher 
2772173a64cbSPatrick Boettcher 	if (state->cfg.diversity_delay == 0)
2773173a64cbSPatrick Boettcher 		sync_wait = (sync_wait * (1 << (state->fe[0]->dtv_property_cache.guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */
2774173a64cbSPatrick Boettcher 	else
2775173a64cbSPatrick Boettcher 		sync_wait = (sync_wait * (1 << (state->fe[0]->dtv_property_cache.guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */
2776173a64cbSPatrick Boettcher 
2777173a64cbSPatrick Boettcher 	dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
2778173a64cbSPatrick Boettcher }
2779173a64cbSPatrick Boettcher 
2780173a64cbSPatrick Boettcher static u32 dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
2781173a64cbSPatrick Boettcher {
2782173a64cbSPatrick Boettcher 	if (mode == SYMBOL_DEPENDENT_ON)
2783173a64cbSPatrick Boettcher 		return systime() + (delay * state->symbol_duration);
2784173a64cbSPatrick Boettcher 	else
2785173a64cbSPatrick Boettcher 		return systime() + delay;
2786173a64cbSPatrick Boettcher }
2787173a64cbSPatrick Boettcher 
2788173a64cbSPatrick Boettcher static s32 dib8000_get_status(struct dvb_frontend *fe)
2789173a64cbSPatrick Boettcher {
2790173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2791173a64cbSPatrick Boettcher 	return state->status;
2792173a64cbSPatrick Boettcher }
2793173a64cbSPatrick Boettcher 
2794173a64cbSPatrick Boettcher enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
2795173a64cbSPatrick Boettcher {
2796173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2797173a64cbSPatrick Boettcher 	return state->tune_state;
2798173a64cbSPatrick Boettcher }
2799173a64cbSPatrick Boettcher EXPORT_SYMBOL(dib8000_get_tune_state);
2800173a64cbSPatrick Boettcher 
2801173a64cbSPatrick Boettcher int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2802173a64cbSPatrick Boettcher {
2803173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2804173a64cbSPatrick Boettcher 
2805173a64cbSPatrick Boettcher 	state->tune_state = tune_state;
2806173a64cbSPatrick Boettcher 	return 0;
2807173a64cbSPatrick Boettcher }
2808173a64cbSPatrick Boettcher EXPORT_SYMBOL(dib8000_set_tune_state);
2809173a64cbSPatrick Boettcher 
2810173a64cbSPatrick Boettcher static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
2811173a64cbSPatrick Boettcher {
2812173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2813173a64cbSPatrick Boettcher 
2814173a64cbSPatrick Boettcher 	state->status = FE_STATUS_TUNE_PENDING;
2815173a64cbSPatrick Boettcher 	state->tune_state = CT_DEMOD_START;
2816173a64cbSPatrick Boettcher 	return 0;
2817173a64cbSPatrick Boettcher }
2818173a64cbSPatrick Boettcher 
2819173a64cbSPatrick Boettcher static u16 dib8000_read_lock(struct dvb_frontend *fe)
2820173a64cbSPatrick Boettcher {
2821173a64cbSPatrick Boettcher 	struct dib8000_state *state = fe->demodulator_priv;
2822173a64cbSPatrick Boettcher 
2823173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
2824173a64cbSPatrick Boettcher 		return dib8000_read_word(state, 570);
2825173a64cbSPatrick Boettcher 	return dib8000_read_word(state, 568);
2826173a64cbSPatrick Boettcher }
2827173a64cbSPatrick Boettcher 
2828173a64cbSPatrick Boettcher static int dib8090p_init_sdram(struct dib8000_state *state)
2829173a64cbSPatrick Boettcher {
2830173a64cbSPatrick Boettcher 	u16 reg = 0;
2831173a64cbSPatrick Boettcher 	dprintk("init sdram");
2832173a64cbSPatrick Boettcher 
2833173a64cbSPatrick Boettcher 	reg = dib8000_read_word(state, 274) & 0xfff0;
2834173a64cbSPatrick Boettcher 	dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */
2835173a64cbSPatrick Boettcher 
2836173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1803, (7 << 2));
2837173a64cbSPatrick Boettcher 
2838173a64cbSPatrick Boettcher 	reg = dib8000_read_word(state, 1280);
2839173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1280,  reg | (1 << 2)); /* force restart P_restart_sdram */
2840173a64cbSPatrick Boettcher 	dib8000_write_word(state, 1280,  reg); /* release restart P_restart_sdram */
2841173a64cbSPatrick Boettcher 
2842173a64cbSPatrick Boettcher 	return 0;
2843173a64cbSPatrick Boettcher }
2844173a64cbSPatrick Boettcher 
28459a0bf528SMauro Carvalho Chehab static int dib8000_tune(struct dvb_frontend *fe)
28469a0bf528SMauro Carvalho Chehab {
28479a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
2848173a64cbSPatrick Boettcher 	enum frontend_tune_state *tune_state = &state->tune_state;
28499a0bf528SMauro Carvalho Chehab 
2850173a64cbSPatrick Boettcher 	u16 locks, deeper_interleaver = 0, i;
2851173a64cbSPatrick Boettcher 	int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
28529a0bf528SMauro Carvalho Chehab 
2853173a64cbSPatrick Boettcher 	u32 *timeout = &state->timeout;
2854173a64cbSPatrick Boettcher 	u32 now = systime();
2855173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
2856173a64cbSPatrick Boettcher 	u16 agc1, agc2;
2857173a64cbSPatrick Boettcher #endif
28589a0bf528SMauro Carvalho Chehab 
2859173a64cbSPatrick Boettcher 	u32 corm[4] = {0, 0, 0, 0};
2860173a64cbSPatrick Boettcher 	u8 find_index, max_value;
28619a0bf528SMauro Carvalho Chehab 
2862173a64cbSPatrick Boettcher #if 0
2863173a64cbSPatrick Boettcher 	if (*tune_state < CT_DEMOD_STOP)
2864173a64cbSPatrick Boettcher 		dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u systime = %u", state->channel_parameters_set, *tune_state, state->autosearch_state, now);
2865173a64cbSPatrick Boettcher #endif
28669a0bf528SMauro Carvalho Chehab 
2867173a64cbSPatrick Boettcher 	switch (*tune_state) {
2868173a64cbSPatrick Boettcher 	case CT_DEMOD_START: /* 30 */
2869173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
2870173a64cbSPatrick Boettcher 				dib8090p_init_sdram(state);
2871173a64cbSPatrick Boettcher 			state->status = FE_STATUS_TUNE_PENDING;
2872173a64cbSPatrick Boettcher 			if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) ||
2873173a64cbSPatrick Boettcher 					(state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) ||
2874173a64cbSPatrick Boettcher 					(state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) ||
2875173a64cbSPatrick Boettcher 					(state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) ||
2876173a64cbSPatrick Boettcher 					(((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) &&
2877173a64cbSPatrick Boettcher 					 (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) &&
2878173a64cbSPatrick Boettcher 					 (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) &&
2879173a64cbSPatrick Boettcher 					 ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) ||
2880173a64cbSPatrick Boettcher 					  (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) ||
2881173a64cbSPatrick Boettcher 					(((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) &&
2882173a64cbSPatrick Boettcher 					 (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) &&
2883173a64cbSPatrick Boettcher 					 (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) &&
2884173a64cbSPatrick Boettcher 					 ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) ||
2885173a64cbSPatrick Boettcher 					  (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) ||
2886173a64cbSPatrick Boettcher 					(((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) &&
2887173a64cbSPatrick Boettcher 					 (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) &&
2888173a64cbSPatrick Boettcher 					 (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) &&
2889173a64cbSPatrick Boettcher 					 ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) ||
2890173a64cbSPatrick Boettcher 					  (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) ||
2891173a64cbSPatrick Boettcher 					(((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) ||
2892173a64cbSPatrick Boettcher 					  ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) &&
2893173a64cbSPatrick Boettcher 					 ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) ||
2894173a64cbSPatrick Boettcher 					  ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) &&
2895173a64cbSPatrick Boettcher 					 ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0))))
2896173a64cbSPatrick Boettcher 				state->channel_parameters_set = 0; /* auto search */
28979a0bf528SMauro Carvalho Chehab 			else
2898173a64cbSPatrick Boettcher 				state->channel_parameters_set = 1; /* channel parameters are known */
28999a0bf528SMauro Carvalho Chehab 
2900173a64cbSPatrick Boettcher 			dib8000_viterbi_state(state, 0); /* force chan dec in restart */
29019a0bf528SMauro Carvalho Chehab 
2902173a64cbSPatrick Boettcher 			/* Layer monit */
2903173a64cbSPatrick Boettcher 			dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
2904173a64cbSPatrick Boettcher 
2905173a64cbSPatrick Boettcher 			dib8000_set_frequency_offset(state);
2906173a64cbSPatrick Boettcher 			dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000);
2907173a64cbSPatrick Boettcher 
2908173a64cbSPatrick Boettcher 			if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
2909173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
2910173a64cbSPatrick Boettcher 				if (state->revision != 0x8090) {
2911173a64cbSPatrick Boettcher 					state->agc1_max = dib8000_read_word(state, 108);
2912173a64cbSPatrick Boettcher 					state->agc1_min = dib8000_read_word(state, 109);
2913173a64cbSPatrick Boettcher 					state->agc2_max = dib8000_read_word(state, 110);
2914173a64cbSPatrick Boettcher 					state->agc2_min = dib8000_read_word(state, 111);
2915173a64cbSPatrick Boettcher 					agc1 = dib8000_read_word(state, 388);
2916173a64cbSPatrick Boettcher 					agc2 = dib8000_read_word(state, 389);
2917173a64cbSPatrick Boettcher 					dib8000_write_word(state, 108, agc1);
2918173a64cbSPatrick Boettcher 					dib8000_write_word(state, 109, agc1);
2919173a64cbSPatrick Boettcher 					dib8000_write_word(state, 110, agc2);
2920173a64cbSPatrick Boettcher 					dib8000_write_word(state, 111, agc2);
2921173a64cbSPatrick Boettcher 				}
2922173a64cbSPatrick Boettcher #endif
2923173a64cbSPatrick Boettcher 				state->autosearch_state = AS_SEARCHING_FFT;
2924173a64cbSPatrick Boettcher 				state->found_nfft = TRANSMISSION_MODE_AUTO;
2925173a64cbSPatrick Boettcher 				state->found_guard = GUARD_INTERVAL_AUTO;
2926173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_SEARCH_NEXT;
2927173a64cbSPatrick Boettcher 			} else { /* we already know the channel struct so TUNE only ! */
2928173a64cbSPatrick Boettcher 				state->autosearch_state = AS_DONE;
2929173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_3;
2930173a64cbSPatrick Boettcher 			}
2931173a64cbSPatrick Boettcher 			state->symbol_duration = dib8000_get_symbol_duration(state);
2932173a64cbSPatrick Boettcher 			break;
2933173a64cbSPatrick Boettcher 
2934173a64cbSPatrick Boettcher 	case CT_DEMOD_SEARCH_NEXT: /* 51 */
2935173a64cbSPatrick Boettcher 			dib8000_autosearch_start(fe);
2936173a64cbSPatrick Boettcher 			if (state->revision == 0x8090)
2937173a64cbSPatrick Boettcher 				ret = 50;
2938173a64cbSPatrick Boettcher 			else
2939173a64cbSPatrick Boettcher 				ret = 15;
2940173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_1;
2941173a64cbSPatrick Boettcher 			break;
2942173a64cbSPatrick Boettcher 
2943173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_1: /* 31 */
2944173a64cbSPatrick Boettcher 			switch (dib8000_autosearch_irq(fe)) {
2945173a64cbSPatrick Boettcher 			case 1: /* fail */
2946173a64cbSPatrick Boettcher 					state->status = FE_STATUS_TUNE_FAILED;
2947173a64cbSPatrick Boettcher 					state->autosearch_state = AS_DONE;
2948173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STOP; /* else we are done here */
2949173a64cbSPatrick Boettcher 					break;
2950173a64cbSPatrick Boettcher 			case 2: /* Succes */
2951173a64cbSPatrick Boettcher 					state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
2952173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_3;
2953173a64cbSPatrick Boettcher 					if (state->autosearch_state == AS_SEARCHING_GUARD)
2954173a64cbSPatrick Boettcher 						*tune_state = CT_DEMOD_STEP_2;
2955173a64cbSPatrick Boettcher 					else
2956173a64cbSPatrick Boettcher 						state->autosearch_state = AS_DONE;
2957173a64cbSPatrick Boettcher 					break;
2958173a64cbSPatrick Boettcher 			case 3: /* Autosearch FFT max correlation endded */
2959173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_2;
2960173a64cbSPatrick Boettcher 					break;
2961173a64cbSPatrick Boettcher 			}
2962173a64cbSPatrick Boettcher 			break;
2963173a64cbSPatrick Boettcher 
2964173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_2:
2965173a64cbSPatrick Boettcher 			switch (state->autosearch_state) {
2966173a64cbSPatrick Boettcher 			case AS_SEARCHING_FFT:
2967173a64cbSPatrick Boettcher 					/* searching for the correct FFT */
2968173a64cbSPatrick Boettcher 				if (state->revision == 0x8090) {
2969173a64cbSPatrick Boettcher 					corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
2970173a64cbSPatrick Boettcher 					corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
2971173a64cbSPatrick Boettcher 					corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
2972173a64cbSPatrick Boettcher 				} else {
2973173a64cbSPatrick Boettcher 					corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
2974173a64cbSPatrick Boettcher 					corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
2975173a64cbSPatrick Boettcher 					corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
2976173a64cbSPatrick Boettcher 				}
2977173a64cbSPatrick Boettcher 					/* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */
2978173a64cbSPatrick Boettcher 
2979173a64cbSPatrick Boettcher 					max_value = 0;
2980173a64cbSPatrick Boettcher 					for (find_index = 1 ; find_index < 3 ; find_index++) {
2981173a64cbSPatrick Boettcher 						if (corm[max_value] < corm[find_index])
2982173a64cbSPatrick Boettcher 							max_value = find_index ;
29839a0bf528SMauro Carvalho Chehab 					}
29849a0bf528SMauro Carvalho Chehab 
2985173a64cbSPatrick Boettcher 					switch (max_value) {
2986173a64cbSPatrick Boettcher 					case 0:
2987173a64cbSPatrick Boettcher 							state->found_nfft = TRANSMISSION_MODE_2K;
2988173a64cbSPatrick Boettcher 							break;
2989173a64cbSPatrick Boettcher 					case 1:
2990173a64cbSPatrick Boettcher 							state->found_nfft = TRANSMISSION_MODE_4K;
2991173a64cbSPatrick Boettcher 							break;
2992173a64cbSPatrick Boettcher 					case 2:
2993173a64cbSPatrick Boettcher 					default:
2994173a64cbSPatrick Boettcher 							state->found_nfft = TRANSMISSION_MODE_8K;
2995173a64cbSPatrick Boettcher 							break;
2996173a64cbSPatrick Boettcher 					}
2997173a64cbSPatrick Boettcher 					/* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */
2998173a64cbSPatrick Boettcher 
2999173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_SEARCH_NEXT;
3000173a64cbSPatrick Boettcher 					state->autosearch_state = AS_SEARCHING_GUARD;
3001173a64cbSPatrick Boettcher 					if (state->revision == 0x8090)
3002173a64cbSPatrick Boettcher 						ret = 50;
3003173a64cbSPatrick Boettcher 					else
3004173a64cbSPatrick Boettcher 						ret = 10;
3005173a64cbSPatrick Boettcher 					break;
3006173a64cbSPatrick Boettcher 			case AS_SEARCHING_GUARD:
3007173a64cbSPatrick Boettcher 					/* searching for the correct guard interval */
3008173a64cbSPatrick Boettcher 					if (state->revision == 0x8090)
3009173a64cbSPatrick Boettcher 						state->found_guard = dib8000_read_word(state, 572) & 0x3;
3010173a64cbSPatrick Boettcher 					else
3011173a64cbSPatrick Boettcher 						state->found_guard = dib8000_read_word(state, 570) & 0x3;
3012173a64cbSPatrick Boettcher 					/* dprintk("guard interval found=%i", state->found_guard); */
3013173a64cbSPatrick Boettcher 
3014173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_3;
3015173a64cbSPatrick Boettcher 					break;
3016173a64cbSPatrick Boettcher 			default:
3017173a64cbSPatrick Boettcher 					/* the demod should never be in this state */
3018173a64cbSPatrick Boettcher 					state->status = FE_STATUS_TUNE_FAILED;
3019173a64cbSPatrick Boettcher 					state->autosearch_state = AS_DONE;
3020173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STOP; /* else we are done here */
3021173a64cbSPatrick Boettcher 					break;
3022173a64cbSPatrick Boettcher 			}
3023173a64cbSPatrick Boettcher 			break;
3024173a64cbSPatrick Boettcher 
3025173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_3: /* 33 */
3026173a64cbSPatrick Boettcher 			state->symbol_duration = dib8000_get_symbol_duration(state);
3027173a64cbSPatrick Boettcher 			dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
3028173a64cbSPatrick Boettcher 			dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
3029173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_4;
3030173a64cbSPatrick Boettcher 			break;
3031173a64cbSPatrick Boettcher 
3032173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_4: /* (34) */
3033173a64cbSPatrick Boettcher 			dib8000_demod_restart(state);
3034173a64cbSPatrick Boettcher 
3035173a64cbSPatrick Boettcher 			dib8000_set_sync_wait(state);
3036173a64cbSPatrick Boettcher 			dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
3037173a64cbSPatrick Boettcher 
3038173a64cbSPatrick Boettcher 			locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
3039173a64cbSPatrick Boettcher 			/* coff should lock over P_coff_winlen ofdm symbols : give 3 times this lenght to lock */
3040173a64cbSPatrick Boettcher 			*timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
3041173a64cbSPatrick Boettcher 			*tune_state = CT_DEMOD_STEP_5;
3042173a64cbSPatrick Boettcher 			break;
3043173a64cbSPatrick Boettcher 
3044173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_5: /* (35) */
3045173a64cbSPatrick Boettcher 			locks = dib8000_read_lock(fe);
3046173a64cbSPatrick Boettcher 			if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
3047173a64cbSPatrick Boettcher 				dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
3048173a64cbSPatrick Boettcher 				if (!state->differential_constellation) {
3049173a64cbSPatrick Boettcher 					/* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
3050173a64cbSPatrick Boettcher 					*timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
3051173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_7;
3052173a64cbSPatrick Boettcher 				} else {
3053173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_8;
3054173a64cbSPatrick Boettcher 				}
3055173a64cbSPatrick Boettcher 			} else if (now > *timeout) {
3056173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3057173a64cbSPatrick Boettcher 			}
3058173a64cbSPatrick Boettcher 			break;
3059173a64cbSPatrick Boettcher 
3060173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_6: /* (36)  if there is an input (diversity) */
3061173a64cbSPatrick Boettcher 			if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
3062173a64cbSPatrick Boettcher 				/* if there is a diversity fe in input and this fe is has not already failled : wait here until this this fe has succedeed or failled */
3063173a64cbSPatrick Boettcher 				if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
3064173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
3065173a64cbSPatrick Boettcher 				else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */
3066173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3067173a64cbSPatrick Boettcher 					dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3068173a64cbSPatrick Boettcher 					dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3069173a64cbSPatrick Boettcher 					state->status = FE_STATUS_TUNE_FAILED;
3070173a64cbSPatrick Boettcher 				}
3071173a64cbSPatrick Boettcher 			} else {
3072173a64cbSPatrick Boettcher 				dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3073173a64cbSPatrick Boettcher 				dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3074173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3075173a64cbSPatrick Boettcher 				state->status = FE_STATUS_TUNE_FAILED;
3076173a64cbSPatrick Boettcher 			}
3077173a64cbSPatrick Boettcher 			break;
3078173a64cbSPatrick Boettcher 
3079173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_7: /* 37 */
3080173a64cbSPatrick Boettcher 			locks = dib8000_read_lock(fe);
3081173a64cbSPatrick Boettcher 			if (locks & (1<<10)) { /* lmod4_lock */
3082173a64cbSPatrick Boettcher 				ret = 14; /* wait for 14 symbols */
3083173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_8;
3084173a64cbSPatrick Boettcher 			} else if (now > *timeout)
3085173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3086173a64cbSPatrick Boettcher 			break;
3087173a64cbSPatrick Boettcher 
3088173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_8: /* 38 */
3089173a64cbSPatrick Boettcher 			dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3090173a64cbSPatrick Boettcher 			dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3091173a64cbSPatrick Boettcher 
3092173a64cbSPatrick Boettcher 			/* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
3093173a64cbSPatrick Boettcher 			if (state->fe[0]->dtv_property_cache.isdbt_sb_mode && state->fe[0]->dtv_property_cache.isdbt_sb_subchannel == -1 && !state->differential_constellation) {
3094173a64cbSPatrick Boettcher 				state->subchannel = 0;
3095173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_11;
3096173a64cbSPatrick Boettcher 			} else {
3097173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_9;
3098173a64cbSPatrick Boettcher 				state->status = FE_STATUS_LOCKED;
3099173a64cbSPatrick Boettcher 			}
3100173a64cbSPatrick Boettcher 			break;
3101173a64cbSPatrick Boettcher 
3102173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_9: /* 39 */
3103173a64cbSPatrick Boettcher 			if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
3104173a64cbSPatrick Boettcher 				/* defines timeout for mpeg lock depending on interleaver lenght of longest layer */
3105173a64cbSPatrick Boettcher 				for (i = 0; i < 3; i++) {
3106173a64cbSPatrick Boettcher 					if (state->fe[0]->dtv_property_cache.layer[i].interleaving >= deeper_interleaver) {
3107173a64cbSPatrick Boettcher 						dprintk("layer%i: time interleaver = %d ", i, state->fe[0]->dtv_property_cache.layer[i].interleaving);
3108173a64cbSPatrick Boettcher 						if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) { /* valid layer */
3109173a64cbSPatrick Boettcher 							deeper_interleaver = state->fe[0]->dtv_property_cache.layer[0].interleaving;
3110173a64cbSPatrick Boettcher 							state->longest_intlv_layer = i;
3111173a64cbSPatrick Boettcher 						}
3112173a64cbSPatrick Boettcher 					}
3113173a64cbSPatrick Boettcher 				}
3114173a64cbSPatrick Boettcher 
3115173a64cbSPatrick Boettcher 				if (deeper_interleaver == 0)
3116173a64cbSPatrick Boettcher 					locks = 2; /* locks is the tmp local variable name */
3117173a64cbSPatrick Boettcher 				else if (deeper_interleaver == 3)
3118173a64cbSPatrick Boettcher 					locks = 8;
3119173a64cbSPatrick Boettcher 				else
3120173a64cbSPatrick Boettcher 					locks = 2 * deeper_interleaver;
3121173a64cbSPatrick Boettcher 
3122173a64cbSPatrick Boettcher 				if (state->diversity_onoff != 0) /* because of diversity sync */
3123173a64cbSPatrick Boettcher 					locks *= 2;
3124173a64cbSPatrick Boettcher 
3125173a64cbSPatrick Boettcher 				*timeout = now + (2000 * locks); /* give the mpeg lock 800ms if sram is present */
3126173a64cbSPatrick Boettcher 				dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %d", deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
3127173a64cbSPatrick Boettcher 
3128173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_10;
3129173a64cbSPatrick Boettcher 			} else
3130173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP;
3131173a64cbSPatrick Boettcher 			break;
3132173a64cbSPatrick Boettcher 
3133173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_10: /* 40 */
3134173a64cbSPatrick Boettcher 			locks = dib8000_read_lock(fe);
3135173a64cbSPatrick Boettcher 			if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
3136173a64cbSPatrick Boettcher 				dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
3137173a64cbSPatrick Boettcher 				if (state->fe[0]->dtv_property_cache.isdbt_sb_mode && state->fe[0]->dtv_property_cache.isdbt_sb_subchannel == -1 && !state->differential_constellation)
3138173a64cbSPatrick Boettcher 					/* signal to the upper layer, that there was a channel found and the parameters can be read */
3139173a64cbSPatrick Boettcher 					state->status = FE_STATUS_DEMOD_SUCCESS;
3140173a64cbSPatrick Boettcher 				else
3141173a64cbSPatrick Boettcher 					state->status = FE_STATUS_DATA_LOCKED;
3142173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP;
3143173a64cbSPatrick Boettcher 			} else if (now > *timeout) {
3144173a64cbSPatrick Boettcher 				if (state->fe[0]->dtv_property_cache.isdbt_sb_mode && state->fe[0]->dtv_property_cache.isdbt_sb_subchannel == -1 && !state->differential_constellation) { /* continue to try init prbs autosearch */
3145173a64cbSPatrick Boettcher 					state->subchannel += 3;
3146173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STEP_11;
3147173a64cbSPatrick 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 */
3148173a64cbSPatrick Boettcher 					if (locks & (0x7<<5)) {
3149173a64cbSPatrick Boettcher 						dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
3150173a64cbSPatrick Boettcher 						state->status = FE_STATUS_DATA_LOCKED;
3151173a64cbSPatrick Boettcher 					} else
3152173a64cbSPatrick Boettcher 						state->status = FE_STATUS_TUNE_FAILED;
3153173a64cbSPatrick Boettcher 					*tune_state = CT_DEMOD_STOP;
3154173a64cbSPatrick Boettcher 				}
3155173a64cbSPatrick Boettcher 			}
3156173a64cbSPatrick Boettcher 			break;
3157173a64cbSPatrick Boettcher 
3158173a64cbSPatrick Boettcher 	case CT_DEMOD_STEP_11:  /* 41 : init prbs autosearch */
3159173a64cbSPatrick Boettcher 			if (state->subchannel <= 41) {
3160173a64cbSPatrick Boettcher 				dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
3161173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STEP_9;
3162173a64cbSPatrick Boettcher 			} else {
3163173a64cbSPatrick Boettcher 				*tune_state = CT_DEMOD_STOP;
3164173a64cbSPatrick Boettcher 				state->status = FE_STATUS_TUNE_FAILED;
3165173a64cbSPatrick Boettcher 			}
3166173a64cbSPatrick Boettcher 			break;
3167173a64cbSPatrick Boettcher 
3168173a64cbSPatrick Boettcher 	default:
3169173a64cbSPatrick Boettcher 			break;
3170173a64cbSPatrick Boettcher 	}
3171173a64cbSPatrick Boettcher 
3172173a64cbSPatrick Boettcher 	/* tuning is finished - cleanup the demod */
3173173a64cbSPatrick Boettcher 	switch (*tune_state) {
3174173a64cbSPatrick Boettcher 	case CT_DEMOD_STOP: /* (42) */
3175173a64cbSPatrick Boettcher #ifdef DIB8000_AGC_FREEZE
3176173a64cbSPatrick Boettcher 			if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
3177173a64cbSPatrick Boettcher 				dib8000_write_word(state, 108, state->agc1_max);
3178173a64cbSPatrick Boettcher 				dib8000_write_word(state, 109, state->agc1_min);
3179173a64cbSPatrick Boettcher 				dib8000_write_word(state, 110, state->agc2_max);
3180173a64cbSPatrick Boettcher 				dib8000_write_word(state, 111, state->agc2_min);
3181173a64cbSPatrick Boettcher 				state->agc1_max = 0;
3182173a64cbSPatrick Boettcher 				state->agc1_min = 0;
3183173a64cbSPatrick Boettcher 				state->agc2_max = 0;
3184173a64cbSPatrick Boettcher 				state->agc2_min = 0;
3185173a64cbSPatrick Boettcher 			}
3186173a64cbSPatrick Boettcher #endif
3187173a64cbSPatrick Boettcher 			ret = FE_CALLBACK_TIME_NEVER;
3188173a64cbSPatrick Boettcher 			break;
3189173a64cbSPatrick Boettcher 	default:
3190173a64cbSPatrick Boettcher 			break;
3191173a64cbSPatrick Boettcher 	}
3192173a64cbSPatrick Boettcher 
3193173a64cbSPatrick Boettcher 	if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
3194173a64cbSPatrick Boettcher 		return ret * state->symbol_duration;
3195173a64cbSPatrick Boettcher 	if ((ret > 0) && (ret < state->symbol_duration))
3196173a64cbSPatrick Boettcher 		return state->symbol_duration; /* at least one symbol */
31979a0bf528SMauro Carvalho Chehab 	return ret;
31989a0bf528SMauro Carvalho Chehab }
31999a0bf528SMauro Carvalho Chehab 
32009a0bf528SMauro Carvalho Chehab static int dib8000_wakeup(struct dvb_frontend *fe)
32019a0bf528SMauro Carvalho Chehab {
32029a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
32039a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
32049a0bf528SMauro Carvalho Chehab 	int ret;
32059a0bf528SMauro Carvalho Chehab 
32069a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_ALL);
32079a0bf528SMauro Carvalho Chehab 	dib8000_set_adc_state(state, DIBX000_ADC_ON);
32089a0bf528SMauro Carvalho Chehab 	if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
32099a0bf528SMauro Carvalho Chehab 		dprintk("could not start Slow ADC");
32109a0bf528SMauro Carvalho Chehab 
3211173a64cbSPatrick Boettcher 	if (state->revision == 0x8090)
32129a0bf528SMauro Carvalho Chehab 		dib8000_sad_calib(state);
32139a0bf528SMauro Carvalho Chehab 
32149a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
32159a0bf528SMauro Carvalho Chehab 		ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
32169a0bf528SMauro Carvalho Chehab 		if (ret < 0)
32179a0bf528SMauro Carvalho Chehab 			return ret;
32189a0bf528SMauro Carvalho Chehab 	}
32199a0bf528SMauro Carvalho Chehab 
32209a0bf528SMauro Carvalho Chehab 	return 0;
32219a0bf528SMauro Carvalho Chehab }
32229a0bf528SMauro Carvalho Chehab 
32239a0bf528SMauro Carvalho Chehab static int dib8000_sleep(struct dvb_frontend *fe)
32249a0bf528SMauro Carvalho Chehab {
32259a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
32269a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
32279a0bf528SMauro Carvalho Chehab 	int ret;
32289a0bf528SMauro Carvalho Chehab 
32299a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
32309a0bf528SMauro Carvalho Chehab 		ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
32319a0bf528SMauro Carvalho Chehab 		if (ret < 0)
32329a0bf528SMauro Carvalho Chehab 			return ret;
32339a0bf528SMauro Carvalho Chehab 	}
32349a0bf528SMauro Carvalho Chehab 
32359a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
32369a0bf528SMauro Carvalho Chehab 		dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
32379a0bf528SMauro Carvalho Chehab 	dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
32389a0bf528SMauro Carvalho Chehab 	return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
32399a0bf528SMauro Carvalho Chehab }
32409a0bf528SMauro Carvalho Chehab 
32419a0bf528SMauro Carvalho Chehab static int dib8000_get_frontend(struct dvb_frontend *fe)
32429a0bf528SMauro Carvalho Chehab {
32439a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
32449a0bf528SMauro Carvalho Chehab 	u16 i, val = 0;
32459a0bf528SMauro Carvalho Chehab 	fe_status_t stat;
32469a0bf528SMauro Carvalho Chehab 	u8 index_frontend, sub_index_frontend;
32479a0bf528SMauro Carvalho Chehab 
32489a0bf528SMauro Carvalho Chehab 	fe->dtv_property_cache.bandwidth_hz = 6000000;
32499a0bf528SMauro Carvalho Chehab 
32509a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
32519a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
32529a0bf528SMauro Carvalho Chehab 		if (stat&FE_HAS_SYNC) {
32539a0bf528SMauro Carvalho Chehab 			dprintk("TMCC lock on the slave%i", index_frontend);
32549a0bf528SMauro Carvalho Chehab 			/* synchronize the cache with the other frontends */
32559a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
32569a0bf528SMauro Carvalho Chehab 			for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {
32579a0bf528SMauro Carvalho Chehab 				if (sub_index_frontend != index_frontend) {
32589a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
32599a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
32609a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
32619a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
32629a0bf528SMauro Carvalho Chehab 					state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
32639a0bf528SMauro Carvalho Chehab 					for (i = 0; i < 3; i++) {
32649a0bf528SMauro 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;
32659a0bf528SMauro Carvalho Chehab 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
32669a0bf528SMauro Carvalho Chehab 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
32679a0bf528SMauro Carvalho Chehab 						state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
32689a0bf528SMauro Carvalho Chehab 					}
32699a0bf528SMauro Carvalho Chehab 				}
32709a0bf528SMauro Carvalho Chehab 			}
32719a0bf528SMauro Carvalho Chehab 			return 0;
32729a0bf528SMauro Carvalho Chehab 		}
32739a0bf528SMauro Carvalho Chehab 	}
32749a0bf528SMauro Carvalho Chehab 
32759a0bf528SMauro Carvalho Chehab 	fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
32769a0bf528SMauro Carvalho Chehab 
32779a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
32789a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 572);
32799a0bf528SMauro Carvalho Chehab 	else
32809a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 570);
32819a0bf528SMauro Carvalho Chehab 	fe->dtv_property_cache.inversion = (val & 0x40) >> 6;
32829a0bf528SMauro Carvalho Chehab 	switch ((val & 0x30) >> 4) {
32839a0bf528SMauro Carvalho Chehab 	case 1:
32849a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
32859a0bf528SMauro Carvalho Chehab 		break;
32869a0bf528SMauro Carvalho Chehab 	case 3:
32879a0bf528SMauro Carvalho Chehab 	default:
32889a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
32899a0bf528SMauro Carvalho Chehab 		break;
32909a0bf528SMauro Carvalho Chehab 	}
32919a0bf528SMauro Carvalho Chehab 
32929a0bf528SMauro Carvalho Chehab 	switch (val & 0x3) {
32939a0bf528SMauro Carvalho Chehab 	case 0:
32949a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
32959a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend GI = 1/32 ");
32969a0bf528SMauro Carvalho Chehab 		break;
32979a0bf528SMauro Carvalho Chehab 	case 1:
32989a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
32999a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend GI = 1/16 ");
33009a0bf528SMauro Carvalho Chehab 		break;
33019a0bf528SMauro Carvalho Chehab 	case 2:
33029a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend GI = 1/8 ");
33039a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
33049a0bf528SMauro Carvalho Chehab 		break;
33059a0bf528SMauro Carvalho Chehab 	case 3:
33069a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend GI = 1/4 ");
33079a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
33089a0bf528SMauro Carvalho Chehab 		break;
33099a0bf528SMauro Carvalho Chehab 	}
33109a0bf528SMauro Carvalho Chehab 
33119a0bf528SMauro Carvalho Chehab 	val = dib8000_read_word(state, 505);
33129a0bf528SMauro Carvalho Chehab 	fe->dtv_property_cache.isdbt_partial_reception = val & 1;
33139a0bf528SMauro Carvalho Chehab 	dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
33149a0bf528SMauro Carvalho Chehab 
33159a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 3; i++) {
33169a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 493 + i);
33179a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;
33189a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);
33199a0bf528SMauro Carvalho Chehab 
33209a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 499 + i);
33219a0bf528SMauro Carvalho Chehab 		fe->dtv_property_cache.layer[i].interleaving = val & 0x3;
33229a0bf528SMauro Carvalho Chehab 		dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving);
33239a0bf528SMauro Carvalho Chehab 
33249a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 481 + i);
33259a0bf528SMauro Carvalho Chehab 		switch (val & 0x7) {
33269a0bf528SMauro Carvalho Chehab 		case 1:
33279a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_1_2;
33289a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i);
33299a0bf528SMauro Carvalho Chehab 			break;
33309a0bf528SMauro Carvalho Chehab 		case 2:
33319a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_2_3;
33329a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i);
33339a0bf528SMauro Carvalho Chehab 			break;
33349a0bf528SMauro Carvalho Chehab 		case 3:
33359a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_3_4;
33369a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i);
33379a0bf528SMauro Carvalho Chehab 			break;
33389a0bf528SMauro Carvalho Chehab 		case 5:
33399a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_5_6;
33409a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i);
33419a0bf528SMauro Carvalho Chehab 			break;
33429a0bf528SMauro Carvalho Chehab 		default:
33439a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].fec = FEC_7_8;
33449a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i);
33459a0bf528SMauro Carvalho Chehab 			break;
33469a0bf528SMauro Carvalho Chehab 		}
33479a0bf528SMauro Carvalho Chehab 
33489a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 487 + i);
33499a0bf528SMauro Carvalho Chehab 		switch (val & 0x3) {
33509a0bf528SMauro Carvalho Chehab 		case 0:
33519a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d DQPSK ", i);
33529a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].modulation = DQPSK;
33539a0bf528SMauro Carvalho Chehab 			break;
33549a0bf528SMauro Carvalho Chehab 		case 1:
33559a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].modulation = QPSK;
33569a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d QPSK ", i);
33579a0bf528SMauro Carvalho Chehab 			break;
33589a0bf528SMauro Carvalho Chehab 		case 2:
33599a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].modulation = QAM_16;
33609a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d QAM16 ", i);
33619a0bf528SMauro Carvalho Chehab 			break;
33629a0bf528SMauro Carvalho Chehab 		case 3:
33639a0bf528SMauro Carvalho Chehab 		default:
33649a0bf528SMauro Carvalho Chehab 			dprintk("dib8000_get_frontend : Layer %d QAM64 ", i);
33659a0bf528SMauro Carvalho Chehab 			fe->dtv_property_cache.layer[i].modulation = QAM_64;
33669a0bf528SMauro Carvalho Chehab 			break;
33679a0bf528SMauro Carvalho Chehab 		}
33689a0bf528SMauro Carvalho Chehab 	}
33699a0bf528SMauro Carvalho Chehab 
33709a0bf528SMauro Carvalho Chehab 	/* synchronize the cache with the other frontends */
33719a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
33729a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode;
33739a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
33749a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
33759a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
33769a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception;
33779a0bf528SMauro Carvalho Chehab 		for (i = 0; i < 3; i++) {
33789a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count;
33799a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving;
33809a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec;
33819a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation;
33829a0bf528SMauro Carvalho Chehab 		}
33839a0bf528SMauro Carvalho Chehab 	}
33849a0bf528SMauro Carvalho Chehab 	return 0;
33859a0bf528SMauro Carvalho Chehab }
33869a0bf528SMauro Carvalho Chehab 
33879a0bf528SMauro Carvalho Chehab static int dib8000_set_frontend(struct dvb_frontend *fe)
33889a0bf528SMauro Carvalho Chehab {
33899a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
3390173a64cbSPatrick Boettcher 	int l, i, active, time, ret, time_slave = FE_CALLBACK_TIME_NEVER;
3391173a64cbSPatrick Boettcher 	u8 exit_condition, index_frontend;
3392173a64cbSPatrick Boettcher 	u32 delay, callback_time;
33939a0bf528SMauro Carvalho Chehab 
33949a0bf528SMauro Carvalho Chehab 	if (state->fe[0]->dtv_property_cache.frequency == 0) {
33959a0bf528SMauro Carvalho Chehab 		dprintk("dib8000: must at least specify frequency ");
33969a0bf528SMauro Carvalho Chehab 		return 0;
33979a0bf528SMauro Carvalho Chehab 	}
33989a0bf528SMauro Carvalho Chehab 
33999a0bf528SMauro Carvalho Chehab 	if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) {
34009a0bf528SMauro Carvalho Chehab 		dprintk("dib8000: no bandwidth specified, set to default ");
34019a0bf528SMauro Carvalho Chehab 		state->fe[0]->dtv_property_cache.bandwidth_hz = 6000000;
34029a0bf528SMauro Carvalho Chehab 	}
34039a0bf528SMauro Carvalho Chehab 
34049a0bf528SMauro Carvalho Chehab 	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
34059a0bf528SMauro Carvalho Chehab 		/* synchronization of the cache */
34069a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
34079a0bf528SMauro Carvalho Chehab 		memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
34089a0bf528SMauro Carvalho Chehab 
3409173a64cbSPatrick Boettcher 		/* set output mode and diversity input */
3410173a64cbSPatrick Boettcher 		if (state->revision != 0x8090) {
3411173a64cbSPatrick Boettcher 			dib8000_set_diversity_in(state->fe[index_frontend], 1);
3412173a64cbSPatrick Boettcher 			if (index_frontend != 0)
34139a0bf528SMauro Carvalho Chehab 				dib8000_set_output_mode(state->fe[index_frontend],
3414173a64cbSPatrick Boettcher 						OUTMODE_DIVERSITY);
34159a0bf528SMauro Carvalho Chehab 			else
3416173a64cbSPatrick Boettcher 				dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3417173a64cbSPatrick Boettcher 		} else {
3418173a64cbSPatrick Boettcher 			dib8096p_set_diversity_in(state->fe[index_frontend], 1);
3419173a64cbSPatrick Boettcher 			if (index_frontend != 0)
34209a0bf528SMauro Carvalho Chehab 				dib8096p_set_output_mode(state->fe[index_frontend],
3421173a64cbSPatrick Boettcher 						OUTMODE_DIVERSITY);
3422173a64cbSPatrick Boettcher 			else
3423173a64cbSPatrick Boettcher 				dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3424173a64cbSPatrick Boettcher 		}
3425173a64cbSPatrick Boettcher 
3426173a64cbSPatrick Boettcher 		/* tune the tuner */
34279a0bf528SMauro Carvalho Chehab 		if (state->fe[index_frontend]->ops.tuner_ops.set_params)
34289a0bf528SMauro Carvalho Chehab 			state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
34299a0bf528SMauro Carvalho Chehab 
34309a0bf528SMauro Carvalho Chehab 		dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
34319a0bf528SMauro Carvalho Chehab 	}
34329a0bf528SMauro Carvalho Chehab 
3433173a64cbSPatrick Boettcher 	/* turn off the diversity of the last chip */
3434173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
3435173a64cbSPatrick Boettcher 		dib8000_set_diversity_in(state->fe[index_frontend - 1], 0);
3436173a64cbSPatrick Boettcher 	else
3437173a64cbSPatrick Boettcher 		dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0);
3438173a64cbSPatrick Boettcher 
34399a0bf528SMauro Carvalho Chehab 	/* start up the AGC */
34409a0bf528SMauro Carvalho Chehab 	do {
34419a0bf528SMauro Carvalho Chehab 		time = dib8000_agc_startup(state->fe[0]);
34429a0bf528SMauro Carvalho Chehab 		for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
34439a0bf528SMauro Carvalho Chehab 			time_slave = dib8000_agc_startup(state->fe[index_frontend]);
34449a0bf528SMauro Carvalho Chehab 			if (time == FE_CALLBACK_TIME_NEVER)
34459a0bf528SMauro Carvalho Chehab 				time = time_slave;
34469a0bf528SMauro Carvalho Chehab 			else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time))
34479a0bf528SMauro Carvalho Chehab 				time = time_slave;
34489a0bf528SMauro Carvalho Chehab 		}
34499a0bf528SMauro Carvalho Chehab 		if (time != FE_CALLBACK_TIME_NEVER)
34509a0bf528SMauro Carvalho Chehab 			msleep(time / 10);
34519a0bf528SMauro Carvalho Chehab 		else
34529a0bf528SMauro Carvalho Chehab 			break;
34539a0bf528SMauro Carvalho Chehab 		exit_condition = 1;
34549a0bf528SMauro Carvalho Chehab 		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
34559a0bf528SMauro Carvalho Chehab 			if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
34569a0bf528SMauro Carvalho Chehab 				exit_condition = 0;
34579a0bf528SMauro Carvalho Chehab 				break;
34589a0bf528SMauro Carvalho Chehab 			}
34599a0bf528SMauro Carvalho Chehab 		}
34609a0bf528SMauro Carvalho Chehab 	} while (exit_condition == 0);
34619a0bf528SMauro Carvalho Chehab 
34629a0bf528SMauro Carvalho Chehab 	for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
34639a0bf528SMauro Carvalho Chehab 		dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
34649a0bf528SMauro Carvalho Chehab 
3465173a64cbSPatrick Boettcher 	active = 1;
34669a0bf528SMauro Carvalho Chehab 	do {
3467173a64cbSPatrick Boettcher 		callback_time = FE_CALLBACK_TIME_NEVER;
34689a0bf528SMauro Carvalho Chehab 		for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3469173a64cbSPatrick Boettcher 			delay = dib8000_tune(state->fe[index_frontend]);
3470173a64cbSPatrick Boettcher 			if (delay != FE_CALLBACK_TIME_NEVER)
3471173a64cbSPatrick Boettcher 				delay += systime();
3472173a64cbSPatrick Boettcher 
3473173a64cbSPatrick Boettcher 			/* we are in autosearch */
3474173a64cbSPatrick Boettcher 			if (state->channel_parameters_set == 0) { /* searching */
3475173a64cbSPatrick Boettcher 				if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) {
3476173a64cbSPatrick Boettcher 					dprintk("autosearch succeeded on fe%i", index_frontend);
3477173a64cbSPatrick Boettcher 					dib8000_get_frontend(state->fe[index_frontend]); /* we read the channel parameters from the frontend which was successful */
3478173a64cbSPatrick Boettcher 					state->channel_parameters_set = 1;
3479173a64cbSPatrick Boettcher 
3480173a64cbSPatrick Boettcher 					for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
3481173a64cbSPatrick Boettcher 						if (l != index_frontend) { /* and for all frontend except the successful one */
3482173a64cbSPatrick Boettcher 							dib8000_tune_restart_from_demod(state->fe[l]);
3483173a64cbSPatrick Boettcher 
3484173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3485173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3486173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3487173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3488173a64cbSPatrick Boettcher 							state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3489173a64cbSPatrick Boettcher 							for (i = 0; i < 3; i++) {
3490173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3491173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3492173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3493173a64cbSPatrick Boettcher 								state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3494173a64cbSPatrick Boettcher 							}
3495173a64cbSPatrick Boettcher 
34969a0bf528SMauro Carvalho Chehab 						}
34979a0bf528SMauro Carvalho Chehab 					}
34989a0bf528SMauro Carvalho Chehab 				}
3499173a64cbSPatrick Boettcher 			}
3500173a64cbSPatrick Boettcher 			if (delay < callback_time)
3501173a64cbSPatrick Boettcher 				callback_time = delay;
3502173a64cbSPatrick Boettcher 		}
3503173a64cbSPatrick Boettcher 		/* tuning is done when the master frontend is done (failed or success) */
3504173a64cbSPatrick Boettcher 		if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
3505173a64cbSPatrick Boettcher 				dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED ||
3506173a64cbSPatrick Boettcher 				dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) {
3507173a64cbSPatrick Boettcher 			active = 0;
3508173a64cbSPatrick Boettcher 			/* we need to wait for all frontends to be finished */
3509173a64cbSPatrick Boettcher 			for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3510173a64cbSPatrick Boettcher 				if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP)
3511173a64cbSPatrick Boettcher 					active = 1;
3512173a64cbSPatrick Boettcher 			}
3513173a64cbSPatrick Boettcher 			if (active == 0)
3514173a64cbSPatrick Boettcher 				dprintk("tuning done with status %d", dib8000_get_status(state->fe[0]));
35159a0bf528SMauro Carvalho Chehab 		}
35169a0bf528SMauro Carvalho Chehab 
3517173a64cbSPatrick Boettcher 		if ((active == 1) && (callback_time == FE_CALLBACK_TIME_NEVER)) {
3518173a64cbSPatrick Boettcher 			dprintk("strange callback time something went wrong");
3519173a64cbSPatrick Boettcher 			active = 0;
35209a0bf528SMauro Carvalho Chehab 		}
35219a0bf528SMauro Carvalho Chehab 
3522173a64cbSPatrick Boettcher 		while ((active == 1) && (systime() < callback_time))
3523173a64cbSPatrick Boettcher 			msleep(100);
3524173a64cbSPatrick Boettcher 	} while (active);
35259a0bf528SMauro Carvalho Chehab 
3526173a64cbSPatrick Boettcher 	/* set output mode */
3527173a64cbSPatrick Boettcher 	if (state->revision != 0x8090)
35289a0bf528SMauro Carvalho Chehab 		dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
3529173a64cbSPatrick Boettcher 	else {
35309a0bf528SMauro Carvalho Chehab 		dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
35319a0bf528SMauro Carvalho Chehab 		if (state->cfg.enMpegOutput == 0) {
35329a0bf528SMauro Carvalho Chehab 			dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
35339a0bf528SMauro Carvalho Chehab 			dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
35349a0bf528SMauro Carvalho Chehab 		}
35359a0bf528SMauro Carvalho Chehab 	}
35369a0bf528SMauro Carvalho Chehab 
35379a0bf528SMauro Carvalho Chehab 	return ret;
35389a0bf528SMauro Carvalho Chehab }
35399a0bf528SMauro Carvalho Chehab 
35409a0bf528SMauro Carvalho Chehab static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
35419a0bf528SMauro Carvalho Chehab {
35429a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
35439a0bf528SMauro Carvalho Chehab 	u16 lock_slave = 0, lock;
35449a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
35459a0bf528SMauro Carvalho Chehab 
3546173a64cbSPatrick Boettcher 	lock = dib8000_read_lock(fe);
35479a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
35489a0bf528SMauro Carvalho Chehab 		lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
35499a0bf528SMauro Carvalho Chehab 
35509a0bf528SMauro Carvalho Chehab 	*stat = 0;
35519a0bf528SMauro Carvalho Chehab 
35529a0bf528SMauro Carvalho Chehab 	if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
35539a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SIGNAL;
35549a0bf528SMauro Carvalho Chehab 
35559a0bf528SMauro Carvalho Chehab 	if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
35569a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_CARRIER;
35579a0bf528SMauro Carvalho Chehab 
35589a0bf528SMauro Carvalho Chehab 	if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
35599a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SYNC;
35609a0bf528SMauro Carvalho Chehab 
35619a0bf528SMauro Carvalho Chehab 	if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
35629a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_LOCK;
35639a0bf528SMauro Carvalho Chehab 
35649a0bf528SMauro Carvalho Chehab 	if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
35659a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
35669a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
35679a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
35689a0bf528SMauro Carvalho Chehab 
35699a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
35709a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
35719a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
35729a0bf528SMauro Carvalho Chehab 
35739a0bf528SMauro Carvalho Chehab 		lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
35749a0bf528SMauro Carvalho Chehab 		if (lock & 0x01)
35759a0bf528SMauro Carvalho Chehab 			*stat |= FE_HAS_VITERBI;
35769a0bf528SMauro Carvalho Chehab 	}
35779a0bf528SMauro Carvalho Chehab 
35789a0bf528SMauro Carvalho Chehab 	return 0;
35799a0bf528SMauro Carvalho Chehab }
35809a0bf528SMauro Carvalho Chehab 
35819a0bf528SMauro Carvalho Chehab static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
35829a0bf528SMauro Carvalho Chehab {
35839a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
35849a0bf528SMauro Carvalho Chehab 
35859a0bf528SMauro Carvalho Chehab 	/* 13 segments */
35869a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
35879a0bf528SMauro Carvalho Chehab 		*ber = (dib8000_read_word(state, 562) << 16) |
35889a0bf528SMauro Carvalho Chehab 			dib8000_read_word(state, 563);
35899a0bf528SMauro Carvalho Chehab 	else
35909a0bf528SMauro Carvalho Chehab 		*ber = (dib8000_read_word(state, 560) << 16) |
35919a0bf528SMauro Carvalho Chehab 			dib8000_read_word(state, 561);
35929a0bf528SMauro Carvalho Chehab 	return 0;
35939a0bf528SMauro Carvalho Chehab }
35949a0bf528SMauro Carvalho Chehab 
35959a0bf528SMauro Carvalho Chehab static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
35969a0bf528SMauro Carvalho Chehab {
35979a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
35989a0bf528SMauro Carvalho Chehab 
35999a0bf528SMauro Carvalho Chehab 	/* packet error on 13 seg */
36009a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x8090)
36019a0bf528SMauro Carvalho Chehab 		*unc = dib8000_read_word(state, 567);
36029a0bf528SMauro Carvalho Chehab 	else
36039a0bf528SMauro Carvalho Chehab 		*unc = dib8000_read_word(state, 565);
36049a0bf528SMauro Carvalho Chehab 	return 0;
36059a0bf528SMauro Carvalho Chehab }
36069a0bf528SMauro Carvalho Chehab 
36079a0bf528SMauro Carvalho Chehab static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
36089a0bf528SMauro Carvalho Chehab {
36099a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
36109a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
36119a0bf528SMauro Carvalho Chehab 	u16 val;
36129a0bf528SMauro Carvalho Chehab 
36139a0bf528SMauro Carvalho Chehab 	*strength = 0;
36149a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
36159a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
36169a0bf528SMauro Carvalho Chehab 		if (val > 65535 - *strength)
36179a0bf528SMauro Carvalho Chehab 			*strength = 65535;
36189a0bf528SMauro Carvalho Chehab 		else
36199a0bf528SMauro Carvalho Chehab 			*strength += val;
36209a0bf528SMauro Carvalho Chehab 	}
36219a0bf528SMauro Carvalho Chehab 
36229a0bf528SMauro Carvalho Chehab 	val = 65535 - dib8000_read_word(state, 390);
36239a0bf528SMauro Carvalho Chehab 	if (val > 65535 - *strength)
36249a0bf528SMauro Carvalho Chehab 		*strength = 65535;
36259a0bf528SMauro Carvalho Chehab 	else
36269a0bf528SMauro Carvalho Chehab 		*strength += val;
36279a0bf528SMauro Carvalho Chehab 	return 0;
36289a0bf528SMauro Carvalho Chehab }
36299a0bf528SMauro Carvalho Chehab 
36309a0bf528SMauro Carvalho Chehab static u32 dib8000_get_snr(struct dvb_frontend *fe)
36319a0bf528SMauro Carvalho Chehab {
36329a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
36339a0bf528SMauro Carvalho Chehab 	u32 n, s, exp;
36349a0bf528SMauro Carvalho Chehab 	u16 val;
36359a0bf528SMauro Carvalho Chehab 
36369a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
36379a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 542);
36389a0bf528SMauro Carvalho Chehab 	else
36399a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 544);
36409a0bf528SMauro Carvalho Chehab 	n = (val >> 6) & 0xff;
36419a0bf528SMauro Carvalho Chehab 	exp = (val & 0x3f);
36429a0bf528SMauro Carvalho Chehab 	if ((exp & 0x20) != 0)
36439a0bf528SMauro Carvalho Chehab 		exp -= 0x40;
36449a0bf528SMauro Carvalho Chehab 	n <<= exp+16;
36459a0bf528SMauro Carvalho Chehab 
36469a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x8090)
36479a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 543);
36489a0bf528SMauro Carvalho Chehab 	else
36499a0bf528SMauro Carvalho Chehab 		val = dib8000_read_word(state, 545);
36509a0bf528SMauro Carvalho Chehab 	s = (val >> 6) & 0xff;
36519a0bf528SMauro Carvalho Chehab 	exp = (val & 0x3f);
36529a0bf528SMauro Carvalho Chehab 	if ((exp & 0x20) != 0)
36539a0bf528SMauro Carvalho Chehab 		exp -= 0x40;
36549a0bf528SMauro Carvalho Chehab 	s <<= exp+16;
36559a0bf528SMauro Carvalho Chehab 
36569a0bf528SMauro Carvalho Chehab 	if (n > 0) {
36579a0bf528SMauro Carvalho Chehab 		u32 t = (s/n) << 16;
36589a0bf528SMauro Carvalho Chehab 		return t + ((s << 16) - n*t) / n;
36599a0bf528SMauro Carvalho Chehab 	}
36609a0bf528SMauro Carvalho Chehab 	return 0xffffffff;
36619a0bf528SMauro Carvalho Chehab }
36629a0bf528SMauro Carvalho Chehab 
36639a0bf528SMauro Carvalho Chehab static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
36649a0bf528SMauro Carvalho Chehab {
36659a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
36669a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
36679a0bf528SMauro Carvalho Chehab 	u32 snr_master;
36689a0bf528SMauro Carvalho Chehab 
36699a0bf528SMauro Carvalho Chehab 	snr_master = dib8000_get_snr(fe);
36709a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
36719a0bf528SMauro Carvalho Chehab 		snr_master += dib8000_get_snr(state->fe[index_frontend]);
36729a0bf528SMauro Carvalho Chehab 
36739a0bf528SMauro Carvalho Chehab 	if ((snr_master >> 16) != 0) {
36749a0bf528SMauro Carvalho Chehab 		snr_master = 10*intlog10(snr_master>>16);
36759a0bf528SMauro Carvalho Chehab 		*snr = snr_master / ((1 << 24) / 10);
36769a0bf528SMauro Carvalho Chehab 	}
36779a0bf528SMauro Carvalho Chehab 	else
36789a0bf528SMauro Carvalho Chehab 		*snr = 0;
36799a0bf528SMauro Carvalho Chehab 
36809a0bf528SMauro Carvalho Chehab 	return 0;
36819a0bf528SMauro Carvalho Chehab }
36829a0bf528SMauro Carvalho Chehab 
36839a0bf528SMauro Carvalho Chehab int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
36849a0bf528SMauro Carvalho Chehab {
36859a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
36869a0bf528SMauro Carvalho Chehab 	u8 index_frontend = 1;
36879a0bf528SMauro Carvalho Chehab 
36889a0bf528SMauro Carvalho Chehab 	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
36899a0bf528SMauro Carvalho Chehab 		index_frontend++;
36909a0bf528SMauro Carvalho Chehab 	if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
36919a0bf528SMauro Carvalho Chehab 		dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
36929a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend] = fe_slave;
36939a0bf528SMauro Carvalho Chehab 		return 0;
36949a0bf528SMauro Carvalho Chehab 	}
36959a0bf528SMauro Carvalho Chehab 
36969a0bf528SMauro Carvalho Chehab 	dprintk("too many slave frontend");
36979a0bf528SMauro Carvalho Chehab 	return -ENOMEM;
36989a0bf528SMauro Carvalho Chehab }
36999a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_set_slave_frontend);
37009a0bf528SMauro Carvalho Chehab 
37019a0bf528SMauro Carvalho Chehab int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
37029a0bf528SMauro Carvalho Chehab {
37039a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37049a0bf528SMauro Carvalho Chehab 	u8 index_frontend = 1;
37059a0bf528SMauro Carvalho Chehab 
37069a0bf528SMauro Carvalho Chehab 	while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
37079a0bf528SMauro Carvalho Chehab 		index_frontend++;
37089a0bf528SMauro Carvalho Chehab 	if (index_frontend != 1) {
37099a0bf528SMauro Carvalho Chehab 		dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1);
37109a0bf528SMauro Carvalho Chehab 		state->fe[index_frontend] = NULL;
37119a0bf528SMauro Carvalho Chehab 		return 0;
37129a0bf528SMauro Carvalho Chehab 	}
37139a0bf528SMauro Carvalho Chehab 
37149a0bf528SMauro Carvalho Chehab 	dprintk("no frontend to be removed");
37159a0bf528SMauro Carvalho Chehab 	return -ENODEV;
37169a0bf528SMauro Carvalho Chehab }
37179a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_remove_slave_frontend);
37189a0bf528SMauro Carvalho Chehab 
37199a0bf528SMauro Carvalho Chehab struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
37209a0bf528SMauro Carvalho Chehab {
37219a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state = fe->demodulator_priv;
37229a0bf528SMauro Carvalho Chehab 
37239a0bf528SMauro Carvalho Chehab 	if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
37249a0bf528SMauro Carvalho Chehab 		return NULL;
37259a0bf528SMauro Carvalho Chehab 	return state->fe[slave_index];
37269a0bf528SMauro Carvalho Chehab }
37279a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_get_slave_frontend);
37289a0bf528SMauro Carvalho Chehab 
37299a0bf528SMauro Carvalho Chehab 
37309a0bf528SMauro Carvalho Chehab int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
37319a0bf528SMauro Carvalho Chehab 		u8 default_addr, u8 first_addr, u8 is_dib8096p)
37329a0bf528SMauro Carvalho Chehab {
37339a0bf528SMauro Carvalho Chehab 	int k = 0, ret = 0;
37349a0bf528SMauro Carvalho Chehab 	u8 new_addr = 0;
37359a0bf528SMauro Carvalho Chehab 	struct i2c_device client = {.adap = host };
37369a0bf528SMauro Carvalho Chehab 
37379a0bf528SMauro Carvalho Chehab 	client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
37389a0bf528SMauro Carvalho Chehab 	if (!client.i2c_write_buffer) {
37399a0bf528SMauro Carvalho Chehab 		dprintk("%s: not enough memory", __func__);
37409a0bf528SMauro Carvalho Chehab 		return -ENOMEM;
37419a0bf528SMauro Carvalho Chehab 	}
37429a0bf528SMauro Carvalho Chehab 	client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
37439a0bf528SMauro Carvalho Chehab 	if (!client.i2c_read_buffer) {
37449a0bf528SMauro Carvalho Chehab 		dprintk("%s: not enough memory", __func__);
37459a0bf528SMauro Carvalho Chehab 		ret = -ENOMEM;
37469a0bf528SMauro Carvalho Chehab 		goto error_memory_read;
37479a0bf528SMauro Carvalho Chehab 	}
37489a0bf528SMauro Carvalho Chehab 	client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
37499a0bf528SMauro Carvalho Chehab 	if (!client.i2c_buffer_lock) {
37509a0bf528SMauro Carvalho Chehab 		dprintk("%s: not enough memory", __func__);
37519a0bf528SMauro Carvalho Chehab 		ret = -ENOMEM;
37529a0bf528SMauro Carvalho Chehab 		goto error_memory_lock;
37539a0bf528SMauro Carvalho Chehab 	}
37549a0bf528SMauro Carvalho Chehab 	mutex_init(client.i2c_buffer_lock);
37559a0bf528SMauro Carvalho Chehab 
37569a0bf528SMauro Carvalho Chehab 	for (k = no_of_demods - 1; k >= 0; k--) {
37579a0bf528SMauro Carvalho Chehab 		/* designated i2c address */
37589a0bf528SMauro Carvalho Chehab 		new_addr = first_addr + (k << 1);
37599a0bf528SMauro Carvalho Chehab 
37609a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
37619a0bf528SMauro Carvalho Chehab 		if (!is_dib8096p)
37629a0bf528SMauro Carvalho Chehab 			dib8000_i2c_write16(&client, 1287, 0x0003);	/* sram lead in, rdy */
37639a0bf528SMauro Carvalho Chehab 		if (dib8000_identify(&client) == 0) {
37649a0bf528SMauro Carvalho Chehab 			/* sram lead in, rdy */
37659a0bf528SMauro Carvalho Chehab 			if (!is_dib8096p)
37669a0bf528SMauro Carvalho Chehab 				dib8000_i2c_write16(&client, 1287, 0x0003);
37679a0bf528SMauro Carvalho Chehab 			client.addr = default_addr;
37689a0bf528SMauro Carvalho Chehab 			if (dib8000_identify(&client) == 0) {
37699a0bf528SMauro Carvalho Chehab 				dprintk("#%d: not identified", k);
37709a0bf528SMauro Carvalho Chehab 				ret  = -EINVAL;
37719a0bf528SMauro Carvalho Chehab 				goto error;
37729a0bf528SMauro Carvalho Chehab 			}
37739a0bf528SMauro Carvalho Chehab 		}
37749a0bf528SMauro Carvalho Chehab 
37759a0bf528SMauro Carvalho Chehab 		/* start diversity to pull_down div_str - just for i2c-enumeration */
37769a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
37779a0bf528SMauro Carvalho Chehab 
37789a0bf528SMauro Carvalho Chehab 		/* set new i2c address and force divstart */
37799a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
37809a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
37819a0bf528SMauro Carvalho Chehab 		dib8000_identify(&client);
37829a0bf528SMauro Carvalho Chehab 
37839a0bf528SMauro Carvalho Chehab 		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
37849a0bf528SMauro Carvalho Chehab 	}
37859a0bf528SMauro Carvalho Chehab 
37869a0bf528SMauro Carvalho Chehab 	for (k = 0; k < no_of_demods; k++) {
37879a0bf528SMauro Carvalho Chehab 		new_addr = first_addr | (k << 1);
37889a0bf528SMauro Carvalho Chehab 		client.addr = new_addr;
37899a0bf528SMauro Carvalho Chehab 
37909a0bf528SMauro Carvalho Chehab 		// unforce divstr
37919a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1285, new_addr << 2);
37929a0bf528SMauro Carvalho Chehab 
37939a0bf528SMauro Carvalho Chehab 		/* deactivate div - it was just for i2c-enumeration */
37949a0bf528SMauro Carvalho Chehab 		dib8000_i2c_write16(&client, 1286, 0);
37959a0bf528SMauro Carvalho Chehab 	}
37969a0bf528SMauro Carvalho Chehab 
37979a0bf528SMauro Carvalho Chehab error:
37989a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_buffer_lock);
37999a0bf528SMauro Carvalho Chehab error_memory_lock:
38009a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_read_buffer);
38019a0bf528SMauro Carvalho Chehab error_memory_read:
38029a0bf528SMauro Carvalho Chehab 	kfree(client.i2c_write_buffer);
38039a0bf528SMauro Carvalho Chehab 
38049a0bf528SMauro Carvalho Chehab 	return ret;
38059a0bf528SMauro Carvalho Chehab }
38069a0bf528SMauro Carvalho Chehab 
38079a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_i2c_enumeration);
38089a0bf528SMauro Carvalho Chehab static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
38099a0bf528SMauro Carvalho Chehab {
38109a0bf528SMauro Carvalho Chehab 	tune->min_delay_ms = 1000;
38119a0bf528SMauro Carvalho Chehab 	tune->step_size = 0;
38129a0bf528SMauro Carvalho Chehab 	tune->max_drift = 0;
38139a0bf528SMauro Carvalho Chehab 	return 0;
38149a0bf528SMauro Carvalho Chehab }
38159a0bf528SMauro Carvalho Chehab 
38169a0bf528SMauro Carvalho Chehab static void dib8000_release(struct dvb_frontend *fe)
38179a0bf528SMauro Carvalho Chehab {
38189a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
38199a0bf528SMauro Carvalho Chehab 	u8 index_frontend;
38209a0bf528SMauro Carvalho Chehab 
38219a0bf528SMauro Carvalho Chehab 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
38229a0bf528SMauro Carvalho Chehab 		dvb_frontend_detach(st->fe[index_frontend]);
38239a0bf528SMauro Carvalho Chehab 
38249a0bf528SMauro Carvalho Chehab 	dibx000_exit_i2c_master(&st->i2c_master);
38259a0bf528SMauro Carvalho Chehab 	i2c_del_adapter(&st->dib8096p_tuner_adap);
38269a0bf528SMauro Carvalho Chehab 	kfree(st->fe[0]);
38279a0bf528SMauro Carvalho Chehab 	kfree(st);
38289a0bf528SMauro Carvalho Chehab }
38299a0bf528SMauro Carvalho Chehab 
38309a0bf528SMauro Carvalho Chehab struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
38319a0bf528SMauro Carvalho Chehab {
38329a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
38339a0bf528SMauro Carvalho Chehab 	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
38349a0bf528SMauro Carvalho Chehab }
38359a0bf528SMauro Carvalho Chehab 
38369a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_get_i2c_master);
38379a0bf528SMauro Carvalho Chehab 
38389a0bf528SMauro Carvalho Chehab int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
38399a0bf528SMauro Carvalho Chehab {
38409a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
38419a0bf528SMauro Carvalho Chehab 	u16 val = dib8000_read_word(st, 299) & 0xffef;
38429a0bf528SMauro Carvalho Chehab 	val |= (onoff & 0x1) << 4;
38439a0bf528SMauro Carvalho Chehab 
38449a0bf528SMauro Carvalho Chehab 	dprintk("pid filter enabled %d", onoff);
38459a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(st, 299, val);
38469a0bf528SMauro Carvalho Chehab }
38479a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_pid_filter_ctrl);
38489a0bf528SMauro Carvalho Chehab 
38499a0bf528SMauro Carvalho Chehab int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
38509a0bf528SMauro Carvalho Chehab {
38519a0bf528SMauro Carvalho Chehab 	struct dib8000_state *st = fe->demodulator_priv;
38529a0bf528SMauro Carvalho Chehab 	dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
38539a0bf528SMauro Carvalho Chehab 	return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
38549a0bf528SMauro Carvalho Chehab }
38559a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_pid_filter);
38569a0bf528SMauro Carvalho Chehab 
38579a0bf528SMauro Carvalho Chehab static const struct dvb_frontend_ops dib8000_ops = {
38589a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_ISDBT },
38599a0bf528SMauro Carvalho Chehab 	.info = {
38609a0bf528SMauro Carvalho Chehab 		 .name = "DiBcom 8000 ISDB-T",
38619a0bf528SMauro Carvalho Chehab 		 .frequency_min = 44250000,
38629a0bf528SMauro Carvalho Chehab 		 .frequency_max = 867250000,
38639a0bf528SMauro Carvalho Chehab 		 .frequency_stepsize = 62500,
38649a0bf528SMauro Carvalho Chehab 		 .caps = FE_CAN_INVERSION_AUTO |
38659a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
38669a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
38679a0bf528SMauro Carvalho Chehab 		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
38689a0bf528SMauro Carvalho Chehab 		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
38699a0bf528SMauro Carvalho Chehab 		 },
38709a0bf528SMauro Carvalho Chehab 
38719a0bf528SMauro Carvalho Chehab 	.release = dib8000_release,
38729a0bf528SMauro Carvalho Chehab 
38739a0bf528SMauro Carvalho Chehab 	.init = dib8000_wakeup,
38749a0bf528SMauro Carvalho Chehab 	.sleep = dib8000_sleep,
38759a0bf528SMauro Carvalho Chehab 
38769a0bf528SMauro Carvalho Chehab 	.set_frontend = dib8000_set_frontend,
38779a0bf528SMauro Carvalho Chehab 	.get_tune_settings = dib8000_fe_get_tune_settings,
38789a0bf528SMauro Carvalho Chehab 	.get_frontend = dib8000_get_frontend,
38799a0bf528SMauro Carvalho Chehab 
38809a0bf528SMauro Carvalho Chehab 	.read_status = dib8000_read_status,
38819a0bf528SMauro Carvalho Chehab 	.read_ber = dib8000_read_ber,
38829a0bf528SMauro Carvalho Chehab 	.read_signal_strength = dib8000_read_signal_strength,
38839a0bf528SMauro Carvalho Chehab 	.read_snr = dib8000_read_snr,
38849a0bf528SMauro Carvalho Chehab 	.read_ucblocks = dib8000_read_unc_blocks,
38859a0bf528SMauro Carvalho Chehab };
38869a0bf528SMauro Carvalho Chehab 
38879a0bf528SMauro Carvalho Chehab struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
38889a0bf528SMauro Carvalho Chehab {
38899a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *fe;
38909a0bf528SMauro Carvalho Chehab 	struct dib8000_state *state;
38919a0bf528SMauro Carvalho Chehab 
38929a0bf528SMauro Carvalho Chehab 	dprintk("dib8000_attach");
38939a0bf528SMauro Carvalho Chehab 
38949a0bf528SMauro Carvalho Chehab 	state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
38959a0bf528SMauro Carvalho Chehab 	if (state == NULL)
38969a0bf528SMauro Carvalho Chehab 		return NULL;
38979a0bf528SMauro Carvalho Chehab 	fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
38989a0bf528SMauro Carvalho Chehab 	if (fe == NULL)
38999a0bf528SMauro Carvalho Chehab 		goto error;
39009a0bf528SMauro Carvalho Chehab 
39019a0bf528SMauro Carvalho Chehab 	memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
39029a0bf528SMauro Carvalho Chehab 	state->i2c.adap = i2c_adap;
39039a0bf528SMauro Carvalho Chehab 	state->i2c.addr = i2c_addr;
39049a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_write_buffer = state->i2c_write_buffer;
39059a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_read_buffer = state->i2c_read_buffer;
39069a0bf528SMauro Carvalho Chehab 	mutex_init(&state->i2c_buffer_lock);
39079a0bf528SMauro Carvalho Chehab 	state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
39089a0bf528SMauro Carvalho Chehab 	state->gpio_val = cfg->gpio_val;
39099a0bf528SMauro Carvalho Chehab 	state->gpio_dir = cfg->gpio_dir;
39109a0bf528SMauro Carvalho Chehab 
39119a0bf528SMauro Carvalho Chehab 	/* Ensure the output mode remains at the previous default if it's
39129a0bf528SMauro Carvalho Chehab 	 * not specifically set by the caller.
39139a0bf528SMauro Carvalho Chehab 	 */
39149a0bf528SMauro Carvalho Chehab 	if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
39159a0bf528SMauro Carvalho Chehab 		state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
39169a0bf528SMauro Carvalho Chehab 
39179a0bf528SMauro Carvalho Chehab 	state->fe[0] = fe;
39189a0bf528SMauro Carvalho Chehab 	fe->demodulator_priv = state;
39199a0bf528SMauro Carvalho Chehab 	memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
39209a0bf528SMauro Carvalho Chehab 
39219a0bf528SMauro Carvalho Chehab 	state->timf_default = cfg->pll->timf;
39229a0bf528SMauro Carvalho Chehab 
39239a0bf528SMauro Carvalho Chehab 	if (dib8000_identify(&state->i2c) == 0)
39249a0bf528SMauro Carvalho Chehab 		goto error;
39259a0bf528SMauro Carvalho Chehab 
39269a0bf528SMauro Carvalho Chehab 	dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
39279a0bf528SMauro Carvalho Chehab 
39289a0bf528SMauro Carvalho Chehab 	/* init 8096p tuner adapter */
39299a0bf528SMauro Carvalho Chehab 	strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
39309a0bf528SMauro Carvalho Chehab 			sizeof(state->dib8096p_tuner_adap.name));
39319a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
39329a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.algo_data = NULL;
39339a0bf528SMauro Carvalho Chehab 	state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
39349a0bf528SMauro Carvalho Chehab 	i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
39359a0bf528SMauro Carvalho Chehab 	i2c_add_adapter(&state->dib8096p_tuner_adap);
39369a0bf528SMauro Carvalho Chehab 
39379a0bf528SMauro Carvalho Chehab 	dib8000_reset(fe);
39389a0bf528SMauro Carvalho Chehab 
39399a0bf528SMauro Carvalho Chehab 	dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));	/* ber_rs_len = 3 */
3940173a64cbSPatrick Boettcher 	state->current_demod_bw = 6000;
39419a0bf528SMauro Carvalho Chehab 
39429a0bf528SMauro Carvalho Chehab 	return fe;
39439a0bf528SMauro Carvalho Chehab 
39449a0bf528SMauro Carvalho Chehab error:
39459a0bf528SMauro Carvalho Chehab 	kfree(state);
39469a0bf528SMauro Carvalho Chehab 	return NULL;
39479a0bf528SMauro Carvalho Chehab }
39489a0bf528SMauro Carvalho Chehab 
39499a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib8000_attach);
39509a0bf528SMauro Carvalho Chehab 
39519a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>");
39529a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
39539a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
3954