xref: /openbmc/linux/drivers/media/dvb-frontends/dib7000p.c (revision 041ad449683bb2d54a7f082d78ec15bbc958a175)
19a0bf528SMauro Carvalho Chehab /*
29a0bf528SMauro Carvalho Chehab  * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
39a0bf528SMauro Carvalho Chehab  *
49a0bf528SMauro Carvalho Chehab  * Copyright (C) 2005-7 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>
14*041ad449SMauro Carvalho Chehab #include <asm/div64.h>
159a0bf528SMauro Carvalho Chehab 
169a0bf528SMauro Carvalho Chehab #include "dvb_math.h"
179a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h"
189a0bf528SMauro Carvalho Chehab 
199a0bf528SMauro Carvalho Chehab #include "dib7000p.h"
209a0bf528SMauro Carvalho Chehab 
219a0bf528SMauro Carvalho Chehab static int debug;
229a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
239a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
249a0bf528SMauro Carvalho Chehab 
259a0bf528SMauro Carvalho Chehab static int buggy_sfn_workaround;
269a0bf528SMauro Carvalho Chehab module_param(buggy_sfn_workaround, int, 0644);
279a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
289a0bf528SMauro Carvalho Chehab 
299a0bf528SMauro Carvalho Chehab #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
309a0bf528SMauro Carvalho Chehab 
319a0bf528SMauro Carvalho Chehab struct i2c_device {
329a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *i2c_adap;
339a0bf528SMauro Carvalho Chehab 	u8 i2c_addr;
349a0bf528SMauro Carvalho Chehab };
359a0bf528SMauro Carvalho Chehab 
369a0bf528SMauro Carvalho Chehab struct dib7000p_state {
379a0bf528SMauro Carvalho Chehab 	struct dvb_frontend demod;
389a0bf528SMauro Carvalho Chehab 	struct dib7000p_config cfg;
399a0bf528SMauro Carvalho Chehab 
409a0bf528SMauro Carvalho Chehab 	u8 i2c_addr;
419a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *i2c_adap;
429a0bf528SMauro Carvalho Chehab 
439a0bf528SMauro Carvalho Chehab 	struct dibx000_i2c_master i2c_master;
449a0bf528SMauro Carvalho Chehab 
459a0bf528SMauro Carvalho Chehab 	u16 wbd_ref;
469a0bf528SMauro Carvalho Chehab 
479a0bf528SMauro Carvalho Chehab 	u8 current_band;
489a0bf528SMauro Carvalho Chehab 	u32 current_bandwidth;
499a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *current_agc;
509a0bf528SMauro Carvalho Chehab 	u32 timf;
519a0bf528SMauro Carvalho Chehab 
529a0bf528SMauro Carvalho Chehab 	u8 div_force_off:1;
539a0bf528SMauro Carvalho Chehab 	u8 div_state:1;
549a0bf528SMauro Carvalho Chehab 	u16 div_sync_wait;
559a0bf528SMauro Carvalho Chehab 
569a0bf528SMauro Carvalho Chehab 	u8 agc_state;
579a0bf528SMauro Carvalho Chehab 
589a0bf528SMauro Carvalho Chehab 	u16 gpio_dir;
599a0bf528SMauro Carvalho Chehab 	u16 gpio_val;
609a0bf528SMauro Carvalho Chehab 
619a0bf528SMauro Carvalho Chehab 	u8 sfn_workaround_active:1;
629a0bf528SMauro Carvalho Chehab 
639a0bf528SMauro Carvalho Chehab #define SOC7090 0x7090
649a0bf528SMauro Carvalho Chehab 	u16 version;
659a0bf528SMauro Carvalho Chehab 
669a0bf528SMauro Carvalho Chehab 	u16 tuner_enable;
679a0bf528SMauro Carvalho Chehab 	struct i2c_adapter dib7090_tuner_adap;
689a0bf528SMauro Carvalho Chehab 
699a0bf528SMauro Carvalho Chehab 	/* for the I2C transfer */
709a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2];
719a0bf528SMauro Carvalho Chehab 	u8 i2c_write_buffer[4];
729a0bf528SMauro Carvalho Chehab 	u8 i2c_read_buffer[2];
739a0bf528SMauro Carvalho Chehab 	struct mutex i2c_buffer_lock;
749a0bf528SMauro Carvalho Chehab 
759a0bf528SMauro Carvalho Chehab 	u8 input_mode_mpeg;
76*041ad449SMauro Carvalho Chehab 
77*041ad449SMauro Carvalho Chehab 	/* for DVBv5 stats */
78*041ad449SMauro Carvalho Chehab 	s64 old_ucb;
79*041ad449SMauro Carvalho Chehab 	unsigned long per_jiffies_stats;
80*041ad449SMauro Carvalho Chehab 	unsigned long ber_jiffies_stats;
81*041ad449SMauro Carvalho Chehab 	unsigned long get_stats_time;
829a0bf528SMauro Carvalho Chehab };
839a0bf528SMauro Carvalho Chehab 
849a0bf528SMauro Carvalho Chehab enum dib7000p_power_mode {
859a0bf528SMauro Carvalho Chehab 	DIB7000P_POWER_ALL = 0,
869a0bf528SMauro Carvalho Chehab 	DIB7000P_POWER_ANALOG_ADC,
879a0bf528SMauro Carvalho Chehab 	DIB7000P_POWER_INTERFACE_ONLY,
889a0bf528SMauro Carvalho Chehab };
899a0bf528SMauro Carvalho Chehab 
909a0bf528SMauro Carvalho Chehab /* dib7090 specific fonctions */
919a0bf528SMauro Carvalho Chehab static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
929a0bf528SMauro Carvalho Chehab static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
939a0bf528SMauro Carvalho Chehab static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode);
949a0bf528SMauro Carvalho Chehab static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode);
959a0bf528SMauro Carvalho Chehab 
969a0bf528SMauro Carvalho Chehab static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
979a0bf528SMauro Carvalho Chehab {
989a0bf528SMauro Carvalho Chehab 	u16 ret;
999a0bf528SMauro Carvalho Chehab 
1009a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
1019a0bf528SMauro Carvalho Chehab 		dprintk("could not acquire lock");
1029a0bf528SMauro Carvalho Chehab 		return 0;
1039a0bf528SMauro Carvalho Chehab 	}
1049a0bf528SMauro Carvalho Chehab 
1059a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = reg >> 8;
1069a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
1079a0bf528SMauro Carvalho Chehab 
1089a0bf528SMauro Carvalho Chehab 	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
1099a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c_addr >> 1;
1109a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
1119a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
1129a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 2;
1139a0bf528SMauro Carvalho Chehab 	state->msg[1].addr = state->i2c_addr >> 1;
1149a0bf528SMauro Carvalho Chehab 	state->msg[1].flags = I2C_M_RD;
1159a0bf528SMauro Carvalho Chehab 	state->msg[1].buf = state->i2c_read_buffer;
1169a0bf528SMauro Carvalho Chehab 	state->msg[1].len = 2;
1179a0bf528SMauro Carvalho Chehab 
1189a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
1199a0bf528SMauro Carvalho Chehab 		dprintk("i2c read error on %d", reg);
1209a0bf528SMauro Carvalho Chehab 
1219a0bf528SMauro Carvalho Chehab 	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
1229a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
1239a0bf528SMauro Carvalho Chehab 	return ret;
1249a0bf528SMauro Carvalho Chehab }
1259a0bf528SMauro Carvalho Chehab 
1269a0bf528SMauro Carvalho Chehab static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
1279a0bf528SMauro Carvalho Chehab {
1289a0bf528SMauro Carvalho Chehab 	int ret;
1299a0bf528SMauro Carvalho Chehab 
1309a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
1319a0bf528SMauro Carvalho Chehab 		dprintk("could not acquire lock");
1329a0bf528SMauro Carvalho Chehab 		return -EINVAL;
1339a0bf528SMauro Carvalho Chehab 	}
1349a0bf528SMauro Carvalho Chehab 
1359a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
1369a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
1379a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
1389a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[3] = val & 0xff;
1399a0bf528SMauro Carvalho Chehab 
1409a0bf528SMauro Carvalho Chehab 	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
1419a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c_addr >> 1;
1429a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
1439a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
1449a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 4;
1459a0bf528SMauro Carvalho Chehab 
1469a0bf528SMauro Carvalho Chehab 	ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
1479a0bf528SMauro Carvalho Chehab 			-EREMOTEIO : 0);
1489a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
1499a0bf528SMauro Carvalho Chehab 	return ret;
1509a0bf528SMauro Carvalho Chehab }
1519a0bf528SMauro Carvalho Chehab 
1529a0bf528SMauro Carvalho Chehab static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
1539a0bf528SMauro Carvalho Chehab {
1549a0bf528SMauro Carvalho Chehab 	u16 l = 0, r, *n;
1559a0bf528SMauro Carvalho Chehab 	n = buf;
1569a0bf528SMauro Carvalho Chehab 	l = *n++;
1579a0bf528SMauro Carvalho Chehab 	while (l) {
1589a0bf528SMauro Carvalho Chehab 		r = *n++;
1599a0bf528SMauro Carvalho Chehab 
1609a0bf528SMauro Carvalho Chehab 		do {
1619a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, r, *n++);
1629a0bf528SMauro Carvalho Chehab 			r++;
1639a0bf528SMauro Carvalho Chehab 		} while (--l);
1649a0bf528SMauro Carvalho Chehab 		l = *n++;
1659a0bf528SMauro Carvalho Chehab 	}
1669a0bf528SMauro Carvalho Chehab }
1679a0bf528SMauro Carvalho Chehab 
1689a0bf528SMauro Carvalho Chehab static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
1699a0bf528SMauro Carvalho Chehab {
1709a0bf528SMauro Carvalho Chehab 	int ret = 0;
1719a0bf528SMauro Carvalho Chehab 	u16 outreg, fifo_threshold, smo_mode;
1729a0bf528SMauro Carvalho Chehab 
1739a0bf528SMauro Carvalho Chehab 	outreg = 0;
1749a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
1759a0bf528SMauro Carvalho Chehab 	smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
1769a0bf528SMauro Carvalho Chehab 
1779a0bf528SMauro Carvalho Chehab 	dprintk("setting output mode for demod %p to %d", &state->demod, mode);
1789a0bf528SMauro Carvalho Chehab 
1799a0bf528SMauro Carvalho Chehab 	switch (mode) {
1809a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:
1819a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10);	/* 0x0400 */
1829a0bf528SMauro Carvalho Chehab 		break;
1839a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK:
1849a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (1 << 6);	/* 0x0440 */
1859a0bf528SMauro Carvalho Chehab 		break;
1869a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:
1879a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (2 << 6) | (0 << 1);	/* 0x0480 */
1889a0bf528SMauro Carvalho Chehab 		break;
1899a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
1909a0bf528SMauro Carvalho Chehab 		if (state->cfg.hostbus_diversity)
1919a0bf528SMauro Carvalho Chehab 			outreg = (1 << 10) | (4 << 6);	/* 0x0500 */
1929a0bf528SMauro Carvalho Chehab 		else
1939a0bf528SMauro Carvalho Chehab 			outreg = (1 << 11);
1949a0bf528SMauro Carvalho Chehab 		break;
1959a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:
1969a0bf528SMauro Carvalho Chehab 		smo_mode |= (3 << 1);
1979a0bf528SMauro Carvalho Chehab 		fifo_threshold = 512;
1989a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (5 << 6);
1999a0bf528SMauro Carvalho Chehab 		break;
2009a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
2019a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (3 << 6);
2029a0bf528SMauro Carvalho Chehab 		break;
2039a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:
2049a0bf528SMauro Carvalho Chehab 		outreg = 0;
2059a0bf528SMauro Carvalho Chehab 		break;
2069a0bf528SMauro Carvalho Chehab 	default:
2079a0bf528SMauro Carvalho Chehab 		dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod);
2089a0bf528SMauro Carvalho Chehab 		break;
2099a0bf528SMauro Carvalho Chehab 	}
2109a0bf528SMauro Carvalho Chehab 
2119a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
2129a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
2139a0bf528SMauro Carvalho Chehab 
2149a0bf528SMauro Carvalho Chehab 	ret |= dib7000p_write_word(state, 235, smo_mode);
2159a0bf528SMauro Carvalho Chehab 	ret |= dib7000p_write_word(state, 236, fifo_threshold);	/* synchronous fread */
2169a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090)
2179a0bf528SMauro Carvalho Chehab 		ret |= dib7000p_write_word(state, 1286, outreg);	/* P_Div_active */
2189a0bf528SMauro Carvalho Chehab 
2199a0bf528SMauro Carvalho Chehab 	return ret;
2209a0bf528SMauro Carvalho Chehab }
2219a0bf528SMauro Carvalho Chehab 
2229a0bf528SMauro Carvalho Chehab static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
2239a0bf528SMauro Carvalho Chehab {
2249a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
2259a0bf528SMauro Carvalho Chehab 
2269a0bf528SMauro Carvalho Chehab 	if (state->div_force_off) {
2279a0bf528SMauro Carvalho Chehab 		dprintk("diversity combination deactivated - forced by COFDM parameters");
2289a0bf528SMauro Carvalho Chehab 		onoff = 0;
2299a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 207, 0);
2309a0bf528SMauro Carvalho Chehab 	} else
2319a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
2329a0bf528SMauro Carvalho Chehab 
2339a0bf528SMauro Carvalho Chehab 	state->div_state = (u8) onoff;
2349a0bf528SMauro Carvalho Chehab 
2359a0bf528SMauro Carvalho Chehab 	if (onoff) {
2369a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 204, 6);
2379a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 205, 16);
2389a0bf528SMauro Carvalho Chehab 		/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
2399a0bf528SMauro Carvalho Chehab 	} else {
2409a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 204, 1);
2419a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 205, 0);
2429a0bf528SMauro Carvalho Chehab 	}
2439a0bf528SMauro Carvalho Chehab 
2449a0bf528SMauro Carvalho Chehab 	return 0;
2459a0bf528SMauro Carvalho Chehab }
2469a0bf528SMauro Carvalho Chehab 
2479a0bf528SMauro Carvalho Chehab static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
2489a0bf528SMauro Carvalho Chehab {
2499a0bf528SMauro Carvalho Chehab 	/* by default everything is powered off */
2509a0bf528SMauro Carvalho Chehab 	u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
2519a0bf528SMauro Carvalho Chehab 
2529a0bf528SMauro Carvalho Chehab 	/* now, depending on the requested mode, we power on */
2539a0bf528SMauro Carvalho Chehab 	switch (mode) {
2549a0bf528SMauro Carvalho Chehab 		/* power up everything in the demod */
2559a0bf528SMauro Carvalho Chehab 	case DIB7000P_POWER_ALL:
2569a0bf528SMauro Carvalho Chehab 		reg_774 = 0x0000;
2579a0bf528SMauro Carvalho Chehab 		reg_775 = 0x0000;
2589a0bf528SMauro Carvalho Chehab 		reg_776 = 0x0;
2599a0bf528SMauro Carvalho Chehab 		reg_899 = 0x0;
2609a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090)
2619a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x001f;
2629a0bf528SMauro Carvalho Chehab 		else
2639a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x01ff;
2649a0bf528SMauro Carvalho Chehab 		break;
2659a0bf528SMauro Carvalho Chehab 
2669a0bf528SMauro Carvalho Chehab 	case DIB7000P_POWER_ANALOG_ADC:
2679a0bf528SMauro Carvalho Chehab 		/* dem, cfg, iqc, sad, agc */
2689a0bf528SMauro Carvalho Chehab 		reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
2699a0bf528SMauro Carvalho Chehab 		/* nud */
2709a0bf528SMauro Carvalho Chehab 		reg_776 &= ~((1 << 0));
2719a0bf528SMauro Carvalho Chehab 		/* Dout */
2729a0bf528SMauro Carvalho Chehab 		if (state->version != SOC7090)
2739a0bf528SMauro Carvalho Chehab 			reg_1280 &= ~((1 << 11));
2749a0bf528SMauro Carvalho Chehab 		reg_1280 &= ~(1 << 6);
2759a0bf528SMauro Carvalho Chehab 		/* fall through wanted to enable the interfaces */
2769a0bf528SMauro Carvalho Chehab 
2779a0bf528SMauro Carvalho Chehab 		/* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
2789a0bf528SMauro Carvalho Chehab 	case DIB7000P_POWER_INTERFACE_ONLY:	/* TODO power up either SDIO or I2C */
2799a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090)
2809a0bf528SMauro Carvalho Chehab 			reg_1280 &= ~((1 << 7) | (1 << 5));
2819a0bf528SMauro Carvalho Chehab 		else
2829a0bf528SMauro Carvalho Chehab 			reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
2839a0bf528SMauro Carvalho Chehab 		break;
2849a0bf528SMauro Carvalho Chehab 
2859a0bf528SMauro Carvalho Chehab /* TODO following stuff is just converted from the dib7000-driver - check when is used what */
2869a0bf528SMauro Carvalho Chehab 	}
2879a0bf528SMauro Carvalho Chehab 
2889a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 774, reg_774);
2899a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 775, reg_775);
2909a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 776, reg_776);
2919a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1280, reg_1280);
2929a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090)
2939a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 899, reg_899);
2949a0bf528SMauro Carvalho Chehab 
2959a0bf528SMauro Carvalho Chehab 	return 0;
2969a0bf528SMauro Carvalho Chehab }
2979a0bf528SMauro Carvalho Chehab 
2989a0bf528SMauro Carvalho Chehab static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
2999a0bf528SMauro Carvalho Chehab {
3009a0bf528SMauro Carvalho Chehab 	u16 reg_908 = 0, reg_909 = 0;
3019a0bf528SMauro Carvalho Chehab 	u16 reg;
3029a0bf528SMauro Carvalho Chehab 
3039a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090) {
3049a0bf528SMauro Carvalho Chehab 		reg_908 = dib7000p_read_word(state, 908);
3059a0bf528SMauro Carvalho Chehab 		reg_909 = dib7000p_read_word(state, 909);
3069a0bf528SMauro Carvalho Chehab 	}
3079a0bf528SMauro Carvalho Chehab 
3089a0bf528SMauro Carvalho Chehab 	switch (no) {
3099a0bf528SMauro Carvalho Chehab 	case DIBX000_SLOW_ADC_ON:
3109a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090) {
3119a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 1925);
3129a0bf528SMauro Carvalho Chehab 
3139a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2));	/* en_slowAdc = 1 & reset_sladc = 1 */
3149a0bf528SMauro Carvalho Chehab 
3159a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 1925);	/* read acces to make it works... strange ... */
3169a0bf528SMauro Carvalho Chehab 			msleep(200);
3179a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 1925, reg & ~(1 << 4));	/* en_slowAdc = 1 & reset_sladc = 0 */
3189a0bf528SMauro Carvalho Chehab 
3199a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
3209a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524);	/* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
3219a0bf528SMauro Carvalho Chehab 		} else {
3229a0bf528SMauro Carvalho Chehab 			reg_909 |= (1 << 1) | (1 << 0);
3239a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 909, reg_909);
3249a0bf528SMauro Carvalho Chehab 			reg_909 &= ~(1 << 1);
3259a0bf528SMauro Carvalho Chehab 		}
3269a0bf528SMauro Carvalho Chehab 		break;
3279a0bf528SMauro Carvalho Chehab 
3289a0bf528SMauro Carvalho Chehab 	case DIBX000_SLOW_ADC_OFF:
3299a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090) {
3309a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 1925);
3319a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4));	/* reset_sladc = 1 en_slowAdc = 0 */
3329a0bf528SMauro Carvalho Chehab 		} else
3339a0bf528SMauro Carvalho Chehab 			reg_909 |= (1 << 1) | (1 << 0);
3349a0bf528SMauro Carvalho Chehab 		break;
3359a0bf528SMauro Carvalho Chehab 
3369a0bf528SMauro Carvalho Chehab 	case DIBX000_ADC_ON:
3379a0bf528SMauro Carvalho Chehab 		reg_908 &= 0x0fff;
3389a0bf528SMauro Carvalho Chehab 		reg_909 &= 0x0003;
3399a0bf528SMauro Carvalho Chehab 		break;
3409a0bf528SMauro Carvalho Chehab 
3419a0bf528SMauro Carvalho Chehab 	case DIBX000_ADC_OFF:
3429a0bf528SMauro Carvalho Chehab 		reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
3439a0bf528SMauro Carvalho Chehab 		reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
3449a0bf528SMauro Carvalho Chehab 		break;
3459a0bf528SMauro Carvalho Chehab 
3469a0bf528SMauro Carvalho Chehab 	case DIBX000_VBG_ENABLE:
3479a0bf528SMauro Carvalho Chehab 		reg_908 &= ~(1 << 15);
3489a0bf528SMauro Carvalho Chehab 		break;
3499a0bf528SMauro Carvalho Chehab 
3509a0bf528SMauro Carvalho Chehab 	case DIBX000_VBG_DISABLE:
3519a0bf528SMauro Carvalho Chehab 		reg_908 |= (1 << 15);
3529a0bf528SMauro Carvalho Chehab 		break;
3539a0bf528SMauro Carvalho Chehab 
3549a0bf528SMauro Carvalho Chehab 	default:
3559a0bf528SMauro Carvalho Chehab 		break;
3569a0bf528SMauro Carvalho Chehab 	}
3579a0bf528SMauro Carvalho Chehab 
3589a0bf528SMauro Carvalho Chehab //	dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
3599a0bf528SMauro Carvalho Chehab 
3609a0bf528SMauro Carvalho Chehab 	reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
3619a0bf528SMauro Carvalho Chehab 	reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
3629a0bf528SMauro Carvalho Chehab 
3639a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090) {
3649a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 908, reg_908);
3659a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 909, reg_909);
3669a0bf528SMauro Carvalho Chehab 	}
3679a0bf528SMauro Carvalho Chehab }
3689a0bf528SMauro Carvalho Chehab 
3699a0bf528SMauro Carvalho Chehab static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
3709a0bf528SMauro Carvalho Chehab {
3719a0bf528SMauro Carvalho Chehab 	u32 timf;
3729a0bf528SMauro Carvalho Chehab 
3739a0bf528SMauro Carvalho Chehab 	// store the current bandwidth for later use
3749a0bf528SMauro Carvalho Chehab 	state->current_bandwidth = bw;
3759a0bf528SMauro Carvalho Chehab 
3769a0bf528SMauro Carvalho Chehab 	if (state->timf == 0) {
3779a0bf528SMauro Carvalho Chehab 		dprintk("using default timf");
3789a0bf528SMauro Carvalho Chehab 		timf = state->cfg.bw->timf;
3799a0bf528SMauro Carvalho Chehab 	} else {
3809a0bf528SMauro Carvalho Chehab 		dprintk("using updated timf");
3819a0bf528SMauro Carvalho Chehab 		timf = state->timf;
3829a0bf528SMauro Carvalho Chehab 	}
3839a0bf528SMauro Carvalho Chehab 
3849a0bf528SMauro Carvalho Chehab 	timf = timf * (bw / 50) / 160;
3859a0bf528SMauro Carvalho Chehab 
3869a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
3879a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
3889a0bf528SMauro Carvalho Chehab 
3899a0bf528SMauro Carvalho Chehab 	return 0;
3909a0bf528SMauro Carvalho Chehab }
3919a0bf528SMauro Carvalho Chehab 
3929a0bf528SMauro Carvalho Chehab static int dib7000p_sad_calib(struct dib7000p_state *state)
3939a0bf528SMauro Carvalho Chehab {
3949a0bf528SMauro Carvalho Chehab /* internal */
3959a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
3969a0bf528SMauro Carvalho Chehab 
3979a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090)
3989a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 74, 2048);
3999a0bf528SMauro Carvalho Chehab 	else
4009a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 74, 776);
4019a0bf528SMauro Carvalho Chehab 
4029a0bf528SMauro Carvalho Chehab 	/* do the calibration */
4039a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 73, (1 << 0));
4049a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 73, (0 << 0));
4059a0bf528SMauro Carvalho Chehab 
4069a0bf528SMauro Carvalho Chehab 	msleep(1);
4079a0bf528SMauro Carvalho Chehab 
4089a0bf528SMauro Carvalho Chehab 	return 0;
4099a0bf528SMauro Carvalho Chehab }
4109a0bf528SMauro Carvalho Chehab 
4118abe4a0aSMauro Carvalho Chehab static int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
4129a0bf528SMauro Carvalho Chehab {
4139a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
4149a0bf528SMauro Carvalho Chehab 	if (value > 4095)
4159a0bf528SMauro Carvalho Chehab 		value = 4095;
4169a0bf528SMauro Carvalho Chehab 	state->wbd_ref = value;
4179a0bf528SMauro Carvalho Chehab 	return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
4189a0bf528SMauro Carvalho Chehab }
4199a0bf528SMauro Carvalho Chehab 
4208abe4a0aSMauro Carvalho Chehab static int dib7000p_get_agc_values(struct dvb_frontend *fe,
4219a0bf528SMauro Carvalho Chehab 		u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
4229a0bf528SMauro Carvalho Chehab {
4239a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
4249a0bf528SMauro Carvalho Chehab 
4259a0bf528SMauro Carvalho Chehab 	if (agc_global != NULL)
4269a0bf528SMauro Carvalho Chehab 		*agc_global = dib7000p_read_word(state, 394);
4279a0bf528SMauro Carvalho Chehab 	if (agc1 != NULL)
4289a0bf528SMauro Carvalho Chehab 		*agc1 = dib7000p_read_word(state, 392);
4299a0bf528SMauro Carvalho Chehab 	if (agc2 != NULL)
4309a0bf528SMauro Carvalho Chehab 		*agc2 = dib7000p_read_word(state, 393);
4319a0bf528SMauro Carvalho Chehab 	if (wbd != NULL)
4329a0bf528SMauro Carvalho Chehab 		*wbd = dib7000p_read_word(state, 397);
4339a0bf528SMauro Carvalho Chehab 
4349a0bf528SMauro Carvalho Chehab 	return 0;
4359a0bf528SMauro Carvalho Chehab }
4369a0bf528SMauro Carvalho Chehab 
4378abe4a0aSMauro Carvalho Chehab static int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
4386fe1099cSOlivier Grenie {
4396fe1099cSOlivier Grenie 	struct dib7000p_state *state = fe->demodulator_priv;
4406fe1099cSOlivier Grenie 	return dib7000p_write_word(state, 108,  v);
4416fe1099cSOlivier Grenie }
4426fe1099cSOlivier Grenie 
4439a0bf528SMauro Carvalho Chehab static void dib7000p_reset_pll(struct dib7000p_state *state)
4449a0bf528SMauro Carvalho Chehab {
4459a0bf528SMauro Carvalho Chehab 	struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
4469a0bf528SMauro Carvalho Chehab 	u16 clk_cfg0;
4479a0bf528SMauro Carvalho Chehab 
4489a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090) {
4499a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1856, (!bw->pll_reset << 13) | (bw->pll_range << 12) | (bw->pll_ratio << 6) | (bw->pll_prediv));
4509a0bf528SMauro Carvalho Chehab 
4519a0bf528SMauro Carvalho Chehab 		while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
4529a0bf528SMauro Carvalho Chehab 			;
4539a0bf528SMauro Carvalho Chehab 
4549a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
4559a0bf528SMauro Carvalho Chehab 	} else {
4569a0bf528SMauro Carvalho Chehab 		/* force PLL bypass */
4579a0bf528SMauro Carvalho Chehab 		clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
4589a0bf528SMauro Carvalho Chehab 			(bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
4599a0bf528SMauro Carvalho Chehab 
4609a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 900, clk_cfg0);
4619a0bf528SMauro Carvalho Chehab 
4629a0bf528SMauro Carvalho Chehab 		/* P_pll_cfg */
4639a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
4649a0bf528SMauro Carvalho Chehab 		clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
4659a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 900, clk_cfg0);
4669a0bf528SMauro Carvalho Chehab 	}
4679a0bf528SMauro Carvalho Chehab 
4689a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
4699a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
4709a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
4719a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
4729a0bf528SMauro Carvalho Chehab 
4739a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 72, bw->sad_cfg);
4749a0bf528SMauro Carvalho Chehab }
4759a0bf528SMauro Carvalho Chehab 
4769a0bf528SMauro Carvalho Chehab static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
4779a0bf528SMauro Carvalho Chehab {
4789a0bf528SMauro Carvalho Chehab 	u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
4799a0bf528SMauro Carvalho Chehab 	internal |= (u32) dib7000p_read_word(state, 19);
4809a0bf528SMauro Carvalho Chehab 	internal /= 1000;
4819a0bf528SMauro Carvalho Chehab 
4829a0bf528SMauro Carvalho Chehab 	return internal;
4839a0bf528SMauro Carvalho Chehab }
4849a0bf528SMauro Carvalho Chehab 
4858abe4a0aSMauro Carvalho Chehab static int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
4869a0bf528SMauro Carvalho Chehab {
4879a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
4889a0bf528SMauro Carvalho Chehab 	u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
4899a0bf528SMauro Carvalho Chehab 	u8 loopdiv, prediv;
4909a0bf528SMauro Carvalho Chehab 	u32 internal, xtal;
4919a0bf528SMauro Carvalho Chehab 
4929a0bf528SMauro Carvalho Chehab 	/* get back old values */
4939a0bf528SMauro Carvalho Chehab 	prediv = reg_1856 & 0x3f;
4949a0bf528SMauro Carvalho Chehab 	loopdiv = (reg_1856 >> 6) & 0x3f;
4959a0bf528SMauro Carvalho Chehab 
4969a0bf528SMauro Carvalho Chehab 	if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
4979a0bf528SMauro Carvalho Chehab 		dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
4989a0bf528SMauro Carvalho Chehab 		reg_1856 &= 0xf000;
4999a0bf528SMauro Carvalho Chehab 		reg_1857 = dib7000p_read_word(state, 1857);
5009a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
5019a0bf528SMauro Carvalho Chehab 
5029a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
5039a0bf528SMauro Carvalho Chehab 
5049a0bf528SMauro Carvalho Chehab 		/* write new system clk into P_sec_len */
5059a0bf528SMauro Carvalho Chehab 		internal = dib7000p_get_internal_freq(state);
5069a0bf528SMauro Carvalho Chehab 		xtal = (internal / loopdiv) * prediv;
5079a0bf528SMauro Carvalho Chehab 		internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio;	/* new internal */
5089a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
5099a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
5109a0bf528SMauro Carvalho Chehab 
5119a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
5129a0bf528SMauro Carvalho Chehab 
5139a0bf528SMauro Carvalho Chehab 		while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
5149a0bf528SMauro Carvalho Chehab 			dprintk("Waiting for PLL to lock");
5159a0bf528SMauro Carvalho Chehab 
5169a0bf528SMauro Carvalho Chehab 		return 0;
5179a0bf528SMauro Carvalho Chehab 	}
5189a0bf528SMauro Carvalho Chehab 	return -EIO;
5199a0bf528SMauro Carvalho Chehab }
5209a0bf528SMauro Carvalho Chehab 
5219a0bf528SMauro Carvalho Chehab static int dib7000p_reset_gpio(struct dib7000p_state *st)
5229a0bf528SMauro Carvalho Chehab {
5239a0bf528SMauro Carvalho Chehab 	/* reset the GPIOs */
5249a0bf528SMauro Carvalho Chehab 	dprintk("gpio dir: %x: val: %x, pwm_pos: %x", st->gpio_dir, st->gpio_val, st->cfg.gpio_pwm_pos);
5259a0bf528SMauro Carvalho Chehab 
5269a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1029, st->gpio_dir);
5279a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1030, st->gpio_val);
5289a0bf528SMauro Carvalho Chehab 
5299a0bf528SMauro Carvalho Chehab 	/* TODO 1031 is P_gpio_od */
5309a0bf528SMauro Carvalho Chehab 
5319a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
5329a0bf528SMauro Carvalho Chehab 
5339a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
5349a0bf528SMauro Carvalho Chehab 	return 0;
5359a0bf528SMauro Carvalho Chehab }
5369a0bf528SMauro Carvalho Chehab 
5379a0bf528SMauro Carvalho Chehab static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
5389a0bf528SMauro Carvalho Chehab {
5399a0bf528SMauro Carvalho Chehab 	st->gpio_dir = dib7000p_read_word(st, 1029);
5409a0bf528SMauro Carvalho Chehab 	st->gpio_dir &= ~(1 << num);	/* reset the direction bit */
5419a0bf528SMauro Carvalho Chehab 	st->gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
5429a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1029, st->gpio_dir);
5439a0bf528SMauro Carvalho Chehab 
5449a0bf528SMauro Carvalho Chehab 	st->gpio_val = dib7000p_read_word(st, 1030);
5459a0bf528SMauro Carvalho Chehab 	st->gpio_val &= ~(1 << num);	/* reset the direction bit */
5469a0bf528SMauro Carvalho Chehab 	st->gpio_val |= (val & 0x01) << num;	/* set the new value */
5479a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1030, st->gpio_val);
5489a0bf528SMauro Carvalho Chehab 
5499a0bf528SMauro Carvalho Chehab 	return 0;
5509a0bf528SMauro Carvalho Chehab }
5519a0bf528SMauro Carvalho Chehab 
5528abe4a0aSMauro Carvalho Chehab static int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
5539a0bf528SMauro Carvalho Chehab {
5549a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
5559a0bf528SMauro Carvalho Chehab 	return dib7000p_cfg_gpio(state, num, dir, val);
5569a0bf528SMauro Carvalho Chehab }
5579a0bf528SMauro Carvalho Chehab 
5589a0bf528SMauro Carvalho Chehab static u16 dib7000p_defaults[] = {
5599a0bf528SMauro Carvalho Chehab 	// auto search configuration
5609a0bf528SMauro Carvalho Chehab 	3, 2,
5619a0bf528SMauro Carvalho Chehab 	0x0004,
5629a0bf528SMauro Carvalho Chehab 	(1<<3)|(1<<11)|(1<<12)|(1<<13),
5639a0bf528SMauro Carvalho Chehab 	0x0814,			/* Equal Lock */
5649a0bf528SMauro Carvalho Chehab 
5659a0bf528SMauro Carvalho Chehab 	12, 6,
5669a0bf528SMauro Carvalho Chehab 	0x001b,
5679a0bf528SMauro Carvalho Chehab 	0x7740,
5689a0bf528SMauro Carvalho Chehab 	0x005b,
5699a0bf528SMauro Carvalho Chehab 	0x8d80,
5709a0bf528SMauro Carvalho Chehab 	0x01c9,
5719a0bf528SMauro Carvalho Chehab 	0xc380,
5729a0bf528SMauro Carvalho Chehab 	0x0000,
5739a0bf528SMauro Carvalho Chehab 	0x0080,
5749a0bf528SMauro Carvalho Chehab 	0x0000,
5759a0bf528SMauro Carvalho Chehab 	0x0090,
5769a0bf528SMauro Carvalho Chehab 	0x0001,
5779a0bf528SMauro Carvalho Chehab 	0xd4c0,
5789a0bf528SMauro Carvalho Chehab 
5799a0bf528SMauro Carvalho Chehab 	1, 26,
5809a0bf528SMauro Carvalho Chehab 	0x6680,
5819a0bf528SMauro Carvalho Chehab 
5829a0bf528SMauro Carvalho Chehab 	/* set ADC level to -16 */
5839a0bf528SMauro Carvalho Chehab 	11, 79,
5849a0bf528SMauro Carvalho Chehab 	(1 << 13) - 825 - 117,
5859a0bf528SMauro Carvalho Chehab 	(1 << 13) - 837 - 117,
5869a0bf528SMauro Carvalho Chehab 	(1 << 13) - 811 - 117,
5879a0bf528SMauro Carvalho Chehab 	(1 << 13) - 766 - 117,
5889a0bf528SMauro Carvalho Chehab 	(1 << 13) - 737 - 117,
5899a0bf528SMauro Carvalho Chehab 	(1 << 13) - 693 - 117,
5909a0bf528SMauro Carvalho Chehab 	(1 << 13) - 648 - 117,
5919a0bf528SMauro Carvalho Chehab 	(1 << 13) - 619 - 117,
5929a0bf528SMauro Carvalho Chehab 	(1 << 13) - 575 - 117,
5939a0bf528SMauro Carvalho Chehab 	(1 << 13) - 531 - 117,
5949a0bf528SMauro Carvalho Chehab 	(1 << 13) - 501 - 117,
5959a0bf528SMauro Carvalho Chehab 
5969a0bf528SMauro Carvalho Chehab 	1, 142,
5979a0bf528SMauro Carvalho Chehab 	0x0410,
5989a0bf528SMauro Carvalho Chehab 
5999a0bf528SMauro Carvalho Chehab 	/* disable power smoothing */
6009a0bf528SMauro Carvalho Chehab 	8, 145,
6019a0bf528SMauro Carvalho Chehab 	0,
6029a0bf528SMauro Carvalho Chehab 	0,
6039a0bf528SMauro Carvalho Chehab 	0,
6049a0bf528SMauro Carvalho Chehab 	0,
6059a0bf528SMauro Carvalho Chehab 	0,
6069a0bf528SMauro Carvalho Chehab 	0,
6079a0bf528SMauro Carvalho Chehab 	0,
6089a0bf528SMauro Carvalho Chehab 	0,
6099a0bf528SMauro Carvalho Chehab 
6109a0bf528SMauro Carvalho Chehab 	1, 154,
6119a0bf528SMauro Carvalho Chehab 	1 << 13,
6129a0bf528SMauro Carvalho Chehab 
6139a0bf528SMauro Carvalho Chehab 	1, 168,
6149a0bf528SMauro Carvalho Chehab 	0x0ccd,
6159a0bf528SMauro Carvalho Chehab 
6169a0bf528SMauro Carvalho Chehab 	1, 183,
6179a0bf528SMauro Carvalho Chehab 	0x200f,
6189a0bf528SMauro Carvalho Chehab 
6199a0bf528SMauro Carvalho Chehab 	1, 212,
6209a0bf528SMauro Carvalho Chehab 		0x169,
6219a0bf528SMauro Carvalho Chehab 
6229a0bf528SMauro Carvalho Chehab 	5, 187,
6239a0bf528SMauro Carvalho Chehab 	0x023d,
6249a0bf528SMauro Carvalho Chehab 	0x00a4,
6259a0bf528SMauro Carvalho Chehab 	0x00a4,
6269a0bf528SMauro Carvalho Chehab 	0x7ff0,
6279a0bf528SMauro Carvalho Chehab 	0x3ccc,
6289a0bf528SMauro Carvalho Chehab 
6299a0bf528SMauro Carvalho Chehab 	1, 198,
6309a0bf528SMauro Carvalho Chehab 	0x800,
6319a0bf528SMauro Carvalho Chehab 
6329a0bf528SMauro Carvalho Chehab 	1, 222,
6339a0bf528SMauro Carvalho Chehab 	0x0010,
6349a0bf528SMauro Carvalho Chehab 
6359a0bf528SMauro Carvalho Chehab 	1, 235,
6369a0bf528SMauro Carvalho Chehab 	0x0062,
6379a0bf528SMauro Carvalho Chehab 
6389a0bf528SMauro Carvalho Chehab 	0,
6399a0bf528SMauro Carvalho Chehab };
6409a0bf528SMauro Carvalho Chehab 
641*041ad449SMauro Carvalho Chehab static void dib7000p_reset_stats(struct dvb_frontend *fe);
642*041ad449SMauro Carvalho Chehab 
6439a0bf528SMauro Carvalho Chehab static int dib7000p_demod_reset(struct dib7000p_state *state)
6449a0bf528SMauro Carvalho Chehab {
6459a0bf528SMauro Carvalho Chehab 	dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
6469a0bf528SMauro Carvalho Chehab 
6479a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090)
6489a0bf528SMauro Carvalho Chehab 		dibx000_reset_i2c_master(&state->i2c_master);
6499a0bf528SMauro Carvalho Chehab 
6509a0bf528SMauro Carvalho Chehab 	dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
6519a0bf528SMauro Carvalho Chehab 
6529a0bf528SMauro Carvalho Chehab 	/* restart all parts */
6539a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, 0xffff);
6549a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 771, 0xffff);
6559a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 772, 0x001f);
6569a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
6579a0bf528SMauro Carvalho Chehab 
6589a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, 0);
6599a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 771, 0);
6609a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 772, 0);
6619a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1280, 0);
6629a0bf528SMauro Carvalho Chehab 
6639a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090) {
6649a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state,  898, 0x0003);
6659a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state,  898, 0);
6669a0bf528SMauro Carvalho Chehab 	}
6679a0bf528SMauro Carvalho Chehab 
6689a0bf528SMauro Carvalho Chehab 	/* default */
6699a0bf528SMauro Carvalho Chehab 	dib7000p_reset_pll(state);
6709a0bf528SMauro Carvalho Chehab 
6719a0bf528SMauro Carvalho Chehab 	if (dib7000p_reset_gpio(state) != 0)
6729a0bf528SMauro Carvalho Chehab 		dprintk("GPIO reset was not successful.");
6739a0bf528SMauro Carvalho Chehab 
6749a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090) {
6759a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 899, 0);
6769a0bf528SMauro Carvalho Chehab 
6779a0bf528SMauro Carvalho Chehab 		/* impulse noise */
6789a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
6799a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
6809a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
6819a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 273, (0<<6) | 30);
6829a0bf528SMauro Carvalho Chehab 	}
6839a0bf528SMauro Carvalho Chehab 	if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
6849a0bf528SMauro Carvalho Chehab 		dprintk("OUTPUT_MODE could not be reset.");
6859a0bf528SMauro Carvalho Chehab 
6869a0bf528SMauro Carvalho Chehab 	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
6879a0bf528SMauro Carvalho Chehab 	dib7000p_sad_calib(state);
6889a0bf528SMauro Carvalho Chehab 	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
6899a0bf528SMauro Carvalho Chehab 
6909a0bf528SMauro Carvalho Chehab 	/* unforce divstr regardless whether i2c enumeration was done or not */
6919a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
6929a0bf528SMauro Carvalho Chehab 
6939a0bf528SMauro Carvalho Chehab 	dib7000p_set_bandwidth(state, 8000);
6949a0bf528SMauro Carvalho Chehab 
6959a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090) {
6969a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 36, 0x0755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
6979a0bf528SMauro Carvalho Chehab 	} else {
6989a0bf528SMauro Carvalho Chehab 		if (state->cfg.tuner_is_baseband)
6999a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 36, 0x0755);
7009a0bf528SMauro Carvalho Chehab 		else
7019a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 36, 0x1f55);
7029a0bf528SMauro Carvalho Chehab 	}
7039a0bf528SMauro Carvalho Chehab 
7049a0bf528SMauro Carvalho Chehab 	dib7000p_write_tab(state, dib7000p_defaults);
7059a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090) {
7069a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 901, 0x0006);
7079a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
7089a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 905, 0x2c8e);
7099a0bf528SMauro Carvalho Chehab 	}
7109a0bf528SMauro Carvalho Chehab 
7119a0bf528SMauro Carvalho Chehab 	dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
7129a0bf528SMauro Carvalho Chehab 
7139a0bf528SMauro Carvalho Chehab 	return 0;
7149a0bf528SMauro Carvalho Chehab }
7159a0bf528SMauro Carvalho Chehab 
7169a0bf528SMauro Carvalho Chehab static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
7179a0bf528SMauro Carvalho Chehab {
7189a0bf528SMauro Carvalho Chehab 	u16 tmp = 0;
7199a0bf528SMauro Carvalho Chehab 	tmp = dib7000p_read_word(state, 903);
7209a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 903, (tmp | 0x1));
7219a0bf528SMauro Carvalho Chehab 	tmp = dib7000p_read_word(state, 900);
7229a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
7239a0bf528SMauro Carvalho Chehab }
7249a0bf528SMauro Carvalho Chehab 
7259a0bf528SMauro Carvalho Chehab static void dib7000p_restart_agc(struct dib7000p_state *state)
7269a0bf528SMauro Carvalho Chehab {
7279a0bf528SMauro Carvalho Chehab 	// P_restart_iqc & P_restart_agc
7289a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
7299a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, 0x0000);
7309a0bf528SMauro Carvalho Chehab }
7319a0bf528SMauro Carvalho Chehab 
7329a0bf528SMauro Carvalho Chehab static int dib7000p_update_lna(struct dib7000p_state *state)
7339a0bf528SMauro Carvalho Chehab {
7349a0bf528SMauro Carvalho Chehab 	u16 dyn_gain;
7359a0bf528SMauro Carvalho Chehab 
7369a0bf528SMauro Carvalho Chehab 	if (state->cfg.update_lna) {
7379a0bf528SMauro Carvalho Chehab 		dyn_gain = dib7000p_read_word(state, 394);
7389a0bf528SMauro Carvalho Chehab 		if (state->cfg.update_lna(&state->demod, dyn_gain)) {
7399a0bf528SMauro Carvalho Chehab 			dib7000p_restart_agc(state);
7409a0bf528SMauro Carvalho Chehab 			return 1;
7419a0bf528SMauro Carvalho Chehab 		}
7429a0bf528SMauro Carvalho Chehab 	}
7439a0bf528SMauro Carvalho Chehab 
7449a0bf528SMauro Carvalho Chehab 	return 0;
7459a0bf528SMauro Carvalho Chehab }
7469a0bf528SMauro Carvalho Chehab 
7479a0bf528SMauro Carvalho Chehab static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
7489a0bf528SMauro Carvalho Chehab {
7499a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *agc = NULL;
7509a0bf528SMauro Carvalho Chehab 	int i;
7519a0bf528SMauro Carvalho Chehab 	if (state->current_band == band && state->current_agc != NULL)
7529a0bf528SMauro Carvalho Chehab 		return 0;
7539a0bf528SMauro Carvalho Chehab 	state->current_band = band;
7549a0bf528SMauro Carvalho Chehab 
7559a0bf528SMauro Carvalho Chehab 	for (i = 0; i < state->cfg.agc_config_count; i++)
7569a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc[i].band_caps & band) {
7579a0bf528SMauro Carvalho Chehab 			agc = &state->cfg.agc[i];
7589a0bf528SMauro Carvalho Chehab 			break;
7599a0bf528SMauro Carvalho Chehab 		}
7609a0bf528SMauro Carvalho Chehab 
7619a0bf528SMauro Carvalho Chehab 	if (agc == NULL) {
7629a0bf528SMauro Carvalho Chehab 		dprintk("no valid AGC configuration found for band 0x%02x", band);
7639a0bf528SMauro Carvalho Chehab 		return -EINVAL;
7649a0bf528SMauro Carvalho Chehab 	}
7659a0bf528SMauro Carvalho Chehab 
7669a0bf528SMauro Carvalho Chehab 	state->current_agc = agc;
7679a0bf528SMauro Carvalho Chehab 
7689a0bf528SMauro Carvalho Chehab 	/* AGC */
7699a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 75, agc->setup);
7709a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 76, agc->inv_gain);
7719a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 77, agc->time_stabiliz);
7729a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
7739a0bf528SMauro Carvalho Chehab 
7749a0bf528SMauro Carvalho Chehab 	// Demod AGC loop configuration
7759a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
7769a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
7779a0bf528SMauro Carvalho Chehab 
7789a0bf528SMauro Carvalho Chehab 	/* AGC continued */
7799a0bf528SMauro Carvalho Chehab 	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
7809a0bf528SMauro Carvalho Chehab 		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
7819a0bf528SMauro Carvalho Chehab 
7829a0bf528SMauro Carvalho Chehab 	if (state->wbd_ref != 0)
7839a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
7849a0bf528SMauro Carvalho Chehab 	else
7859a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
7869a0bf528SMauro Carvalho Chehab 
7879a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
7889a0bf528SMauro Carvalho Chehab 
7899a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 107, agc->agc1_max);
7909a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 108, agc->agc1_min);
7919a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 109, agc->agc2_max);
7929a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 110, agc->agc2_min);
7939a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
7949a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 112, agc->agc1_pt3);
7959a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
7969a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
7979a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
7989a0bf528SMauro Carvalho Chehab 	return 0;
7999a0bf528SMauro Carvalho Chehab }
8009a0bf528SMauro Carvalho Chehab 
8019a0bf528SMauro Carvalho Chehab static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
8029a0bf528SMauro Carvalho Chehab {
8039a0bf528SMauro Carvalho Chehab 	u32 internal = dib7000p_get_internal_freq(state);
8049a0bf528SMauro Carvalho Chehab 	s32 unit_khz_dds_val = 67108864 / (internal);	/* 2**26 / Fsampling is the unit 1KHz offset */
8059a0bf528SMauro Carvalho Chehab 	u32 abs_offset_khz = ABS(offset_khz);
8069a0bf528SMauro Carvalho Chehab 	u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
8079a0bf528SMauro Carvalho Chehab 	u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
8089a0bf528SMauro Carvalho Chehab 
8099a0bf528SMauro Carvalho Chehab 	dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert);
8109a0bf528SMauro Carvalho Chehab 
8119a0bf528SMauro Carvalho Chehab 	if (offset_khz < 0)
8129a0bf528SMauro Carvalho Chehab 		unit_khz_dds_val *= -1;
8139a0bf528SMauro Carvalho Chehab 
8149a0bf528SMauro Carvalho Chehab 	/* IF tuner */
8159a0bf528SMauro Carvalho Chehab 	if (invert)
8169a0bf528SMauro Carvalho Chehab 		dds -= (abs_offset_khz * unit_khz_dds_val);	/* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */
8179a0bf528SMauro Carvalho Chehab 	else
8189a0bf528SMauro Carvalho Chehab 		dds += (abs_offset_khz * unit_khz_dds_val);
8199a0bf528SMauro Carvalho Chehab 
8209a0bf528SMauro Carvalho Chehab 	if (abs_offset_khz <= (internal / 2)) {	/* Max dds offset is the half of the demod freq */
8219a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
8229a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
8239a0bf528SMauro Carvalho Chehab 	}
8249a0bf528SMauro Carvalho Chehab }
8259a0bf528SMauro Carvalho Chehab 
8269a0bf528SMauro Carvalho Chehab static int dib7000p_agc_startup(struct dvb_frontend *demod)
8279a0bf528SMauro Carvalho Chehab {
8289a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
8299a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
8309a0bf528SMauro Carvalho Chehab 	int ret = -1;
8319a0bf528SMauro Carvalho Chehab 	u8 *agc_state = &state->agc_state;
8329a0bf528SMauro Carvalho Chehab 	u8 agc_split;
8339a0bf528SMauro Carvalho Chehab 	u16 reg;
8349a0bf528SMauro Carvalho Chehab 	u32 upd_demod_gain_period = 0x1000;
8356fe1099cSOlivier Grenie 	s32 frequency_offset = 0;
8369a0bf528SMauro Carvalho Chehab 
8379a0bf528SMauro Carvalho Chehab 	switch (state->agc_state) {
8389a0bf528SMauro Carvalho Chehab 	case 0:
8399a0bf528SMauro Carvalho Chehab 		dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
8409a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090) {
8419a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 0x79b) & 0xff00;
8429a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF);	/* lsb */
8439a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
8449a0bf528SMauro Carvalho Chehab 
8459a0bf528SMauro Carvalho Chehab 			/* enable adc i & q */
8469a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 0x780);
8479a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
8489a0bf528SMauro Carvalho Chehab 		} else {
8499a0bf528SMauro Carvalho Chehab 			dib7000p_set_adc_state(state, DIBX000_ADC_ON);
8509a0bf528SMauro Carvalho Chehab 			dib7000p_pll_clk_cfg(state);
8519a0bf528SMauro Carvalho Chehab 		}
8529a0bf528SMauro Carvalho Chehab 
8539a0bf528SMauro Carvalho Chehab 		if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
8549a0bf528SMauro Carvalho Chehab 			return -1;
8559a0bf528SMauro Carvalho Chehab 
8566fe1099cSOlivier Grenie 		if (demod->ops.tuner_ops.get_frequency) {
8576fe1099cSOlivier Grenie 			u32 frequency_tuner;
8586fe1099cSOlivier Grenie 
8596fe1099cSOlivier Grenie 			demod->ops.tuner_ops.get_frequency(demod, &frequency_tuner);
8606fe1099cSOlivier Grenie 			frequency_offset = (s32)frequency_tuner / 1000 - ch->frequency / 1000;
8616fe1099cSOlivier Grenie 		}
8626fe1099cSOlivier Grenie 
8636fe1099cSOlivier Grenie 		dib7000p_set_dds(state, frequency_offset);
8649a0bf528SMauro Carvalho Chehab 		ret = 7;
8659a0bf528SMauro Carvalho Chehab 		(*agc_state)++;
8669a0bf528SMauro Carvalho Chehab 		break;
8679a0bf528SMauro Carvalho Chehab 
8689a0bf528SMauro Carvalho Chehab 	case 1:
8699a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
8709a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(&state->demod, 1);
8719a0bf528SMauro Carvalho Chehab 
8729a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 78, 32768);
8739a0bf528SMauro Carvalho Chehab 		if (!state->current_agc->perform_agc_softsplit) {
8749a0bf528SMauro Carvalho Chehab 			/* we are using the wbd - so slow AGC startup */
8759a0bf528SMauro Carvalho Chehab 			/* force 0 split on WBD and restart AGC */
8769a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
8779a0bf528SMauro Carvalho Chehab 			(*agc_state)++;
8789a0bf528SMauro Carvalho Chehab 			ret = 5;
8799a0bf528SMauro Carvalho Chehab 		} else {
8809a0bf528SMauro Carvalho Chehab 			/* default AGC startup */
8819a0bf528SMauro Carvalho Chehab 			(*agc_state) = 4;
8829a0bf528SMauro Carvalho Chehab 			/* wait AGC rough lock time */
8839a0bf528SMauro Carvalho Chehab 			ret = 7;
8849a0bf528SMauro Carvalho Chehab 		}
8859a0bf528SMauro Carvalho Chehab 
8869a0bf528SMauro Carvalho Chehab 		dib7000p_restart_agc(state);
8879a0bf528SMauro Carvalho Chehab 		break;
8889a0bf528SMauro Carvalho Chehab 
8899a0bf528SMauro Carvalho Chehab 	case 2:		/* fast split search path after 5sec */
8909a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4));	/* freeze AGC loop */
8919a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8));	/* fast split search 0.25kHz */
8929a0bf528SMauro Carvalho Chehab 		(*agc_state)++;
8939a0bf528SMauro Carvalho Chehab 		ret = 14;
8949a0bf528SMauro Carvalho Chehab 		break;
8959a0bf528SMauro Carvalho Chehab 
8969a0bf528SMauro Carvalho Chehab 	case 3:		/* split search ended */
8979a0bf528SMauro Carvalho Chehab 		agc_split = (u8) dib7000p_read_word(state, 396);	/* store the split value for the next time */
8989a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 78, dib7000p_read_word(state, 394));	/* set AGC gain start value */
8999a0bf528SMauro Carvalho Chehab 
9009a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 75, state->current_agc->setup);	/* std AGC loop */
9019a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split);	/* standard split search */
9029a0bf528SMauro Carvalho Chehab 
9039a0bf528SMauro Carvalho Chehab 		dib7000p_restart_agc(state);
9049a0bf528SMauro Carvalho Chehab 
9059a0bf528SMauro Carvalho Chehab 		dprintk("SPLIT %p: %hd", demod, agc_split);
9069a0bf528SMauro Carvalho Chehab 
9079a0bf528SMauro Carvalho Chehab 		(*agc_state)++;
9089a0bf528SMauro Carvalho Chehab 		ret = 5;
9099a0bf528SMauro Carvalho Chehab 		break;
9109a0bf528SMauro Carvalho Chehab 
9119a0bf528SMauro Carvalho Chehab 	case 4:		/* LNA startup */
9129a0bf528SMauro Carvalho Chehab 		ret = 7;
9139a0bf528SMauro Carvalho Chehab 
9149a0bf528SMauro Carvalho Chehab 		if (dib7000p_update_lna(state))
9159a0bf528SMauro Carvalho Chehab 			ret = 5;
9169a0bf528SMauro Carvalho Chehab 		else
9179a0bf528SMauro Carvalho Chehab 			(*agc_state)++;
9189a0bf528SMauro Carvalho Chehab 		break;
9199a0bf528SMauro Carvalho Chehab 
9209a0bf528SMauro Carvalho Chehab 	case 5:
9219a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
9229a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(&state->demod, 0);
9239a0bf528SMauro Carvalho Chehab 		(*agc_state)++;
9249a0bf528SMauro Carvalho Chehab 		break;
9259a0bf528SMauro Carvalho Chehab 	default:
9269a0bf528SMauro Carvalho Chehab 		break;
9279a0bf528SMauro Carvalho Chehab 	}
9289a0bf528SMauro Carvalho Chehab 	return ret;
9299a0bf528SMauro Carvalho Chehab }
9309a0bf528SMauro Carvalho Chehab 
9319a0bf528SMauro Carvalho Chehab static void dib7000p_update_timf(struct dib7000p_state *state)
9329a0bf528SMauro Carvalho Chehab {
9339a0bf528SMauro Carvalho Chehab 	u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
9349a0bf528SMauro Carvalho Chehab 	state->timf = timf * 160 / (state->current_bandwidth / 50);
9359a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 23, (u16) (timf >> 16));
9369a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
9379a0bf528SMauro Carvalho Chehab 	dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf);
9389a0bf528SMauro Carvalho Chehab 
9399a0bf528SMauro Carvalho Chehab }
9409a0bf528SMauro Carvalho Chehab 
9418abe4a0aSMauro Carvalho Chehab static u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
9429a0bf528SMauro Carvalho Chehab {
9439a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
9449a0bf528SMauro Carvalho Chehab 	switch (op) {
9459a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_SET:
9469a0bf528SMauro Carvalho Chehab 		state->timf = timf;
9479a0bf528SMauro Carvalho Chehab 		break;
9489a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_UPDATE:
9499a0bf528SMauro Carvalho Chehab 		dib7000p_update_timf(state);
9509a0bf528SMauro Carvalho Chehab 		break;
9519a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_GET:
9529a0bf528SMauro Carvalho Chehab 		break;
9539a0bf528SMauro Carvalho Chehab 	}
9549a0bf528SMauro Carvalho Chehab 	dib7000p_set_bandwidth(state, state->current_bandwidth);
9559a0bf528SMauro Carvalho Chehab 	return state->timf;
9569a0bf528SMauro Carvalho Chehab }
9579a0bf528SMauro Carvalho Chehab 
9589a0bf528SMauro Carvalho Chehab static void dib7000p_set_channel(struct dib7000p_state *state,
9599a0bf528SMauro Carvalho Chehab 				 struct dtv_frontend_properties *ch, u8 seq)
9609a0bf528SMauro Carvalho Chehab {
9619a0bf528SMauro Carvalho Chehab 	u16 value, est[4];
9629a0bf528SMauro Carvalho Chehab 
9639a0bf528SMauro Carvalho Chehab 	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
9649a0bf528SMauro Carvalho Chehab 
9659a0bf528SMauro Carvalho Chehab 	/* nfft, guard, qam, alpha */
9669a0bf528SMauro Carvalho Chehab 	value = 0;
9679a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
9689a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
9699a0bf528SMauro Carvalho Chehab 		value |= (0 << 7);
9709a0bf528SMauro Carvalho Chehab 		break;
9719a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
9729a0bf528SMauro Carvalho Chehab 		value |= (2 << 7);
9739a0bf528SMauro Carvalho Chehab 		break;
9749a0bf528SMauro Carvalho Chehab 	default:
9759a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
9769a0bf528SMauro Carvalho Chehab 		value |= (1 << 7);
9779a0bf528SMauro Carvalho Chehab 		break;
9789a0bf528SMauro Carvalho Chehab 	}
9799a0bf528SMauro Carvalho Chehab 	switch (ch->guard_interval) {
9809a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_32:
9819a0bf528SMauro Carvalho Chehab 		value |= (0 << 5);
9829a0bf528SMauro Carvalho Chehab 		break;
9839a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_16:
9849a0bf528SMauro Carvalho Chehab 		value |= (1 << 5);
9859a0bf528SMauro Carvalho Chehab 		break;
9869a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_4:
9879a0bf528SMauro Carvalho Chehab 		value |= (3 << 5);
9889a0bf528SMauro Carvalho Chehab 		break;
9899a0bf528SMauro Carvalho Chehab 	default:
9909a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_8:
9919a0bf528SMauro Carvalho Chehab 		value |= (2 << 5);
9929a0bf528SMauro Carvalho Chehab 		break;
9939a0bf528SMauro Carvalho Chehab 	}
9949a0bf528SMauro Carvalho Chehab 	switch (ch->modulation) {
9959a0bf528SMauro Carvalho Chehab 	case QPSK:
9969a0bf528SMauro Carvalho Chehab 		value |= (0 << 3);
9979a0bf528SMauro Carvalho Chehab 		break;
9989a0bf528SMauro Carvalho Chehab 	case QAM_16:
9999a0bf528SMauro Carvalho Chehab 		value |= (1 << 3);
10009a0bf528SMauro Carvalho Chehab 		break;
10019a0bf528SMauro Carvalho Chehab 	default:
10029a0bf528SMauro Carvalho Chehab 	case QAM_64:
10039a0bf528SMauro Carvalho Chehab 		value |= (2 << 3);
10049a0bf528SMauro Carvalho Chehab 		break;
10059a0bf528SMauro Carvalho Chehab 	}
10069a0bf528SMauro Carvalho Chehab 	switch (HIERARCHY_1) {
10079a0bf528SMauro Carvalho Chehab 	case HIERARCHY_2:
10089a0bf528SMauro Carvalho Chehab 		value |= 2;
10099a0bf528SMauro Carvalho Chehab 		break;
10109a0bf528SMauro Carvalho Chehab 	case HIERARCHY_4:
10119a0bf528SMauro Carvalho Chehab 		value |= 4;
10129a0bf528SMauro Carvalho Chehab 		break;
10139a0bf528SMauro Carvalho Chehab 	default:
10149a0bf528SMauro Carvalho Chehab 	case HIERARCHY_1:
10159a0bf528SMauro Carvalho Chehab 		value |= 1;
10169a0bf528SMauro Carvalho Chehab 		break;
10179a0bf528SMauro Carvalho Chehab 	}
10189a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 0, value);
10199a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 5, (seq << 4) | 1);	/* do not force tps, search list 0 */
10209a0bf528SMauro Carvalho Chehab 
10219a0bf528SMauro Carvalho Chehab 	/* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
10229a0bf528SMauro Carvalho Chehab 	value = 0;
10239a0bf528SMauro Carvalho Chehab 	if (1 != 0)
10249a0bf528SMauro Carvalho Chehab 		value |= (1 << 6);
10259a0bf528SMauro Carvalho Chehab 	if (ch->hierarchy == 1)
10269a0bf528SMauro Carvalho Chehab 		value |= (1 << 4);
10279a0bf528SMauro Carvalho Chehab 	if (1 == 1)
10289a0bf528SMauro Carvalho Chehab 		value |= 1;
10299a0bf528SMauro Carvalho Chehab 	switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
10309a0bf528SMauro Carvalho Chehab 	case FEC_2_3:
10319a0bf528SMauro Carvalho Chehab 		value |= (2 << 1);
10329a0bf528SMauro Carvalho Chehab 		break;
10339a0bf528SMauro Carvalho Chehab 	case FEC_3_4:
10349a0bf528SMauro Carvalho Chehab 		value |= (3 << 1);
10359a0bf528SMauro Carvalho Chehab 		break;
10369a0bf528SMauro Carvalho Chehab 	case FEC_5_6:
10379a0bf528SMauro Carvalho Chehab 		value |= (5 << 1);
10389a0bf528SMauro Carvalho Chehab 		break;
10399a0bf528SMauro Carvalho Chehab 	case FEC_7_8:
10409a0bf528SMauro Carvalho Chehab 		value |= (7 << 1);
10419a0bf528SMauro Carvalho Chehab 		break;
10429a0bf528SMauro Carvalho Chehab 	default:
10439a0bf528SMauro Carvalho Chehab 	case FEC_1_2:
10449a0bf528SMauro Carvalho Chehab 		value |= (1 << 1);
10459a0bf528SMauro Carvalho Chehab 		break;
10469a0bf528SMauro Carvalho Chehab 	}
10479a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 208, value);
10489a0bf528SMauro Carvalho Chehab 
10499a0bf528SMauro Carvalho Chehab 	/* offset loop parameters */
10509a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 26, 0x6680);
10519a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 32, 0x0003);
10529a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 29, 0x1273);
10539a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 33, 0x0005);
10549a0bf528SMauro Carvalho Chehab 
10559a0bf528SMauro Carvalho Chehab 	/* P_dvsy_sync_wait */
10569a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
10579a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
10589a0bf528SMauro Carvalho Chehab 		value = 256;
10599a0bf528SMauro Carvalho Chehab 		break;
10609a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
10619a0bf528SMauro Carvalho Chehab 		value = 128;
10629a0bf528SMauro Carvalho Chehab 		break;
10639a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
10649a0bf528SMauro Carvalho Chehab 	default:
10659a0bf528SMauro Carvalho Chehab 		value = 64;
10669a0bf528SMauro Carvalho Chehab 		break;
10679a0bf528SMauro Carvalho Chehab 	}
10689a0bf528SMauro Carvalho Chehab 	switch (ch->guard_interval) {
10699a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_16:
10709a0bf528SMauro Carvalho Chehab 		value *= 2;
10719a0bf528SMauro Carvalho Chehab 		break;
10729a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_8:
10739a0bf528SMauro Carvalho Chehab 		value *= 4;
10749a0bf528SMauro Carvalho Chehab 		break;
10759a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_4:
10769a0bf528SMauro Carvalho Chehab 		value *= 8;
10779a0bf528SMauro Carvalho Chehab 		break;
10789a0bf528SMauro Carvalho Chehab 	default:
10799a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_32:
10809a0bf528SMauro Carvalho Chehab 		value *= 1;
10819a0bf528SMauro Carvalho Chehab 		break;
10829a0bf528SMauro Carvalho Chehab 	}
10839a0bf528SMauro Carvalho Chehab 	if (state->cfg.diversity_delay == 0)
10849a0bf528SMauro Carvalho Chehab 		state->div_sync_wait = (value * 3) / 2 + 48;
10859a0bf528SMauro Carvalho Chehab 	else
10869a0bf528SMauro Carvalho Chehab 		state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
10879a0bf528SMauro Carvalho Chehab 
10889a0bf528SMauro Carvalho Chehab 	/* deactive the possibility of diversity reception if extended interleaver */
10899a0bf528SMauro Carvalho Chehab 	state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K;
10909a0bf528SMauro Carvalho Chehab 	dib7000p_set_diversity_in(&state->demod, state->div_state);
10919a0bf528SMauro Carvalho Chehab 
10929a0bf528SMauro Carvalho Chehab 	/* channel estimation fine configuration */
10939a0bf528SMauro Carvalho Chehab 	switch (ch->modulation) {
10949a0bf528SMauro Carvalho Chehab 	case QAM_64:
10959a0bf528SMauro Carvalho Chehab 		est[0] = 0x0148;	/* P_adp_regul_cnt 0.04 */
10969a0bf528SMauro Carvalho Chehab 		est[1] = 0xfff0;	/* P_adp_noise_cnt -0.002 */
10979a0bf528SMauro Carvalho Chehab 		est[2] = 0x00a4;	/* P_adp_regul_ext 0.02 */
10989a0bf528SMauro Carvalho Chehab 		est[3] = 0xfff8;	/* P_adp_noise_ext -0.001 */
10999a0bf528SMauro Carvalho Chehab 		break;
11009a0bf528SMauro Carvalho Chehab 	case QAM_16:
11019a0bf528SMauro Carvalho Chehab 		est[0] = 0x023d;	/* P_adp_regul_cnt 0.07 */
11029a0bf528SMauro Carvalho Chehab 		est[1] = 0xffdf;	/* P_adp_noise_cnt -0.004 */
11039a0bf528SMauro Carvalho Chehab 		est[2] = 0x00a4;	/* P_adp_regul_ext 0.02 */
11049a0bf528SMauro Carvalho Chehab 		est[3] = 0xfff0;	/* P_adp_noise_ext -0.002 */
11059a0bf528SMauro Carvalho Chehab 		break;
11069a0bf528SMauro Carvalho Chehab 	default:
11079a0bf528SMauro Carvalho Chehab 		est[0] = 0x099a;	/* P_adp_regul_cnt 0.3 */
11089a0bf528SMauro Carvalho Chehab 		est[1] = 0xffae;	/* P_adp_noise_cnt -0.01 */
11099a0bf528SMauro Carvalho Chehab 		est[2] = 0x0333;	/* P_adp_regul_ext 0.1 */
11109a0bf528SMauro Carvalho Chehab 		est[3] = 0xfff8;	/* P_adp_noise_ext -0.002 */
11119a0bf528SMauro Carvalho Chehab 		break;
11129a0bf528SMauro Carvalho Chehab 	}
11139a0bf528SMauro Carvalho Chehab 	for (value = 0; value < 4; value++)
11149a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 187 + value, est[value]);
11159a0bf528SMauro Carvalho Chehab }
11169a0bf528SMauro Carvalho Chehab 
11179a0bf528SMauro Carvalho Chehab static int dib7000p_autosearch_start(struct dvb_frontend *demod)
11189a0bf528SMauro Carvalho Chehab {
11199a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
11209a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
11219a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties schan;
11229a0bf528SMauro Carvalho Chehab 	u32 value, factor;
11239a0bf528SMauro Carvalho Chehab 	u32 internal = dib7000p_get_internal_freq(state);
11249a0bf528SMauro Carvalho Chehab 
11259a0bf528SMauro Carvalho Chehab 	schan = *ch;
11269a0bf528SMauro Carvalho Chehab 	schan.modulation = QAM_64;
11279a0bf528SMauro Carvalho Chehab 	schan.guard_interval = GUARD_INTERVAL_1_32;
11289a0bf528SMauro Carvalho Chehab 	schan.transmission_mode = TRANSMISSION_MODE_8K;
11299a0bf528SMauro Carvalho Chehab 	schan.code_rate_HP = FEC_2_3;
11309a0bf528SMauro Carvalho Chehab 	schan.code_rate_LP = FEC_3_4;
11319a0bf528SMauro Carvalho Chehab 	schan.hierarchy = 0;
11329a0bf528SMauro Carvalho Chehab 
11339a0bf528SMauro Carvalho Chehab 	dib7000p_set_channel(state, &schan, 7);
11349a0bf528SMauro Carvalho Chehab 
11359a0bf528SMauro Carvalho Chehab 	factor = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
11369a0bf528SMauro Carvalho Chehab 	if (factor >= 5000) {
11379a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090)
11389a0bf528SMauro Carvalho Chehab 			factor = 2;
11399a0bf528SMauro Carvalho Chehab 		else
11409a0bf528SMauro Carvalho Chehab 			factor = 1;
11419a0bf528SMauro Carvalho Chehab 	} else
11429a0bf528SMauro Carvalho Chehab 		factor = 6;
11439a0bf528SMauro Carvalho Chehab 
11449a0bf528SMauro Carvalho Chehab 	value = 30 * internal * factor;
11459a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
11469a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 7, (u16) (value & 0xffff));
11479a0bf528SMauro Carvalho Chehab 	value = 100 * internal * factor;
11489a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
11499a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 9, (u16) (value & 0xffff));
11509a0bf528SMauro Carvalho Chehab 	value = 500 * internal * factor;
11519a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
11529a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 11, (u16) (value & 0xffff));
11539a0bf528SMauro Carvalho Chehab 
11549a0bf528SMauro Carvalho Chehab 	value = dib7000p_read_word(state, 0);
11559a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
11569a0bf528SMauro Carvalho Chehab 	dib7000p_read_word(state, 1284);
11579a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 0, (u16) value);
11589a0bf528SMauro Carvalho Chehab 
11599a0bf528SMauro Carvalho Chehab 	return 0;
11609a0bf528SMauro Carvalho Chehab }
11619a0bf528SMauro Carvalho Chehab 
11629a0bf528SMauro Carvalho Chehab static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
11639a0bf528SMauro Carvalho Chehab {
11649a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
11659a0bf528SMauro Carvalho Chehab 	u16 irq_pending = dib7000p_read_word(state, 1284);
11669a0bf528SMauro Carvalho Chehab 
11679a0bf528SMauro Carvalho Chehab 	if (irq_pending & 0x1)
11689a0bf528SMauro Carvalho Chehab 		return 1;
11699a0bf528SMauro Carvalho Chehab 
11709a0bf528SMauro Carvalho Chehab 	if (irq_pending & 0x2)
11719a0bf528SMauro Carvalho Chehab 		return 2;
11729a0bf528SMauro Carvalho Chehab 
11739a0bf528SMauro Carvalho Chehab 	return 0;
11749a0bf528SMauro Carvalho Chehab }
11759a0bf528SMauro Carvalho Chehab 
11769a0bf528SMauro Carvalho Chehab static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
11779a0bf528SMauro Carvalho Chehab {
11789a0bf528SMauro Carvalho Chehab 	static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
11799a0bf528SMauro Carvalho Chehab 	static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
11809a0bf528SMauro Carvalho Chehab 		24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
11819a0bf528SMauro Carvalho Chehab 		53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
11829a0bf528SMauro Carvalho Chehab 		82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
11839a0bf528SMauro Carvalho Chehab 		107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
11849a0bf528SMauro Carvalho Chehab 		128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
11859a0bf528SMauro Carvalho Chehab 		147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
11869a0bf528SMauro Carvalho Chehab 		166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
11879a0bf528SMauro Carvalho Chehab 		183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
11889a0bf528SMauro Carvalho Chehab 		199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
11899a0bf528SMauro Carvalho Chehab 		213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
11909a0bf528SMauro Carvalho Chehab 		225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
11919a0bf528SMauro Carvalho Chehab 		235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
11929a0bf528SMauro Carvalho Chehab 		244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
11939a0bf528SMauro Carvalho Chehab 		250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
11949a0bf528SMauro Carvalho Chehab 		254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
11959a0bf528SMauro Carvalho Chehab 		255, 255, 255, 255, 255, 255
11969a0bf528SMauro Carvalho Chehab 	};
11979a0bf528SMauro Carvalho Chehab 
11989a0bf528SMauro Carvalho Chehab 	u32 xtal = state->cfg.bw->xtal_hz / 1000;
11999a0bf528SMauro Carvalho Chehab 	int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
12009a0bf528SMauro Carvalho Chehab 	int k;
12019a0bf528SMauro Carvalho Chehab 	int coef_re[8], coef_im[8];
12029a0bf528SMauro Carvalho Chehab 	int bw_khz = bw;
12039a0bf528SMauro Carvalho Chehab 	u32 pha;
12049a0bf528SMauro Carvalho Chehab 
12059a0bf528SMauro Carvalho Chehab 	dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
12069a0bf528SMauro Carvalho Chehab 
12079a0bf528SMauro Carvalho Chehab 	if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
12089a0bf528SMauro Carvalho Chehab 		return;
12099a0bf528SMauro Carvalho Chehab 
12109a0bf528SMauro Carvalho Chehab 	bw_khz /= 100;
12119a0bf528SMauro Carvalho Chehab 
12129a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 142, 0x0610);
12139a0bf528SMauro Carvalho Chehab 
12149a0bf528SMauro Carvalho Chehab 	for (k = 0; k < 8; k++) {
12159a0bf528SMauro Carvalho Chehab 		pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
12169a0bf528SMauro Carvalho Chehab 
12179a0bf528SMauro Carvalho Chehab 		if (pha == 0) {
12189a0bf528SMauro Carvalho Chehab 			coef_re[k] = 256;
12199a0bf528SMauro Carvalho Chehab 			coef_im[k] = 0;
12209a0bf528SMauro Carvalho Chehab 		} else if (pha < 256) {
12219a0bf528SMauro Carvalho Chehab 			coef_re[k] = sine[256 - (pha & 0xff)];
12229a0bf528SMauro Carvalho Chehab 			coef_im[k] = sine[pha & 0xff];
12239a0bf528SMauro Carvalho Chehab 		} else if (pha == 256) {
12249a0bf528SMauro Carvalho Chehab 			coef_re[k] = 0;
12259a0bf528SMauro Carvalho Chehab 			coef_im[k] = 256;
12269a0bf528SMauro Carvalho Chehab 		} else if (pha < 512) {
12279a0bf528SMauro Carvalho Chehab 			coef_re[k] = -sine[pha & 0xff];
12289a0bf528SMauro Carvalho Chehab 			coef_im[k] = sine[256 - (pha & 0xff)];
12299a0bf528SMauro Carvalho Chehab 		} else if (pha == 512) {
12309a0bf528SMauro Carvalho Chehab 			coef_re[k] = -256;
12319a0bf528SMauro Carvalho Chehab 			coef_im[k] = 0;
12329a0bf528SMauro Carvalho Chehab 		} else if (pha < 768) {
12339a0bf528SMauro Carvalho Chehab 			coef_re[k] = -sine[256 - (pha & 0xff)];
12349a0bf528SMauro Carvalho Chehab 			coef_im[k] = -sine[pha & 0xff];
12359a0bf528SMauro Carvalho Chehab 		} else if (pha == 768) {
12369a0bf528SMauro Carvalho Chehab 			coef_re[k] = 0;
12379a0bf528SMauro Carvalho Chehab 			coef_im[k] = -256;
12389a0bf528SMauro Carvalho Chehab 		} else {
12399a0bf528SMauro Carvalho Chehab 			coef_re[k] = sine[pha & 0xff];
12409a0bf528SMauro Carvalho Chehab 			coef_im[k] = -sine[256 - (pha & 0xff)];
12419a0bf528SMauro Carvalho Chehab 		}
12429a0bf528SMauro Carvalho Chehab 
12439a0bf528SMauro Carvalho Chehab 		coef_re[k] *= notch[k];
12449a0bf528SMauro Carvalho Chehab 		coef_re[k] += (1 << 14);
12459a0bf528SMauro Carvalho Chehab 		if (coef_re[k] >= (1 << 24))
12469a0bf528SMauro Carvalho Chehab 			coef_re[k] = (1 << 24) - 1;
12479a0bf528SMauro Carvalho Chehab 		coef_re[k] /= (1 << 15);
12489a0bf528SMauro Carvalho Chehab 
12499a0bf528SMauro Carvalho Chehab 		coef_im[k] *= notch[k];
12509a0bf528SMauro Carvalho Chehab 		coef_im[k] += (1 << 14);
12519a0bf528SMauro Carvalho Chehab 		if (coef_im[k] >= (1 << 24))
12529a0bf528SMauro Carvalho Chehab 			coef_im[k] = (1 << 24) - 1;
12539a0bf528SMauro Carvalho Chehab 		coef_im[k] /= (1 << 15);
12549a0bf528SMauro Carvalho Chehab 
12559a0bf528SMauro Carvalho Chehab 		dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
12569a0bf528SMauro Carvalho Chehab 
12579a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
12589a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
12599a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
12609a0bf528SMauro Carvalho Chehab 	}
12619a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 143, 0);
12629a0bf528SMauro Carvalho Chehab }
12639a0bf528SMauro Carvalho Chehab 
12649a0bf528SMauro Carvalho Chehab static int dib7000p_tune(struct dvb_frontend *demod)
12659a0bf528SMauro Carvalho Chehab {
12669a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
12679a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
12689a0bf528SMauro Carvalho Chehab 	u16 tmp = 0;
12699a0bf528SMauro Carvalho Chehab 
12709a0bf528SMauro Carvalho Chehab 	if (ch != NULL)
12719a0bf528SMauro Carvalho Chehab 		dib7000p_set_channel(state, ch, 0);
12729a0bf528SMauro Carvalho Chehab 	else
12739a0bf528SMauro Carvalho Chehab 		return -EINVAL;
12749a0bf528SMauro Carvalho Chehab 
12759a0bf528SMauro Carvalho Chehab 	// restart demod
12769a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, 0x4000);
12779a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, 0x0000);
12789a0bf528SMauro Carvalho Chehab 	msleep(45);
12799a0bf528SMauro Carvalho Chehab 
12809a0bf528SMauro Carvalho Chehab 	/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
12819a0bf528SMauro Carvalho Chehab 	tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
12829a0bf528SMauro Carvalho Chehab 	if (state->sfn_workaround_active) {
12839a0bf528SMauro Carvalho Chehab 		dprintk("SFN workaround is active");
12849a0bf528SMauro Carvalho Chehab 		tmp |= (1 << 9);
12859a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 166, 0x4000);
12869a0bf528SMauro Carvalho Chehab 	} else {
12879a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 166, 0x0000);
12889a0bf528SMauro Carvalho Chehab 	}
12899a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 29, tmp);
12909a0bf528SMauro Carvalho Chehab 
12919a0bf528SMauro Carvalho Chehab 	// never achieved a lock with that bandwidth so far - wait for osc-freq to update
12929a0bf528SMauro Carvalho Chehab 	if (state->timf == 0)
12939a0bf528SMauro Carvalho Chehab 		msleep(200);
12949a0bf528SMauro Carvalho Chehab 
12959a0bf528SMauro Carvalho Chehab 	/* offset loop parameters */
12969a0bf528SMauro Carvalho Chehab 
12979a0bf528SMauro Carvalho Chehab 	/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
12989a0bf528SMauro Carvalho Chehab 	tmp = (6 << 8) | 0x80;
12999a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
13009a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
13019a0bf528SMauro Carvalho Chehab 		tmp |= (2 << 12);
13029a0bf528SMauro Carvalho Chehab 		break;
13039a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
13049a0bf528SMauro Carvalho Chehab 		tmp |= (3 << 12);
13059a0bf528SMauro Carvalho Chehab 		break;
13069a0bf528SMauro Carvalho Chehab 	default:
13079a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
13089a0bf528SMauro Carvalho Chehab 		tmp |= (4 << 12);
13099a0bf528SMauro Carvalho Chehab 		break;
13109a0bf528SMauro Carvalho Chehab 	}
13119a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 26, tmp);	/* timf_a(6xxx) */
13129a0bf528SMauro Carvalho Chehab 
13139a0bf528SMauro Carvalho Chehab 	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
13149a0bf528SMauro Carvalho Chehab 	tmp = (0 << 4);
13159a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
13169a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
13179a0bf528SMauro Carvalho Chehab 		tmp |= 0x6;
13189a0bf528SMauro Carvalho Chehab 		break;
13199a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
13209a0bf528SMauro Carvalho Chehab 		tmp |= 0x7;
13219a0bf528SMauro Carvalho Chehab 		break;
13229a0bf528SMauro Carvalho Chehab 	default:
13239a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
13249a0bf528SMauro Carvalho Chehab 		tmp |= 0x8;
13259a0bf528SMauro Carvalho Chehab 		break;
13269a0bf528SMauro Carvalho Chehab 	}
13279a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 32, tmp);
13289a0bf528SMauro Carvalho Chehab 
13299a0bf528SMauro Carvalho Chehab 	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
13309a0bf528SMauro Carvalho Chehab 	tmp = (0 << 4);
13319a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
13329a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
13339a0bf528SMauro Carvalho Chehab 		tmp |= 0x6;
13349a0bf528SMauro Carvalho Chehab 		break;
13359a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
13369a0bf528SMauro Carvalho Chehab 		tmp |= 0x7;
13379a0bf528SMauro Carvalho Chehab 		break;
13389a0bf528SMauro Carvalho Chehab 	default:
13399a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
13409a0bf528SMauro Carvalho Chehab 		tmp |= 0x8;
13419a0bf528SMauro Carvalho Chehab 		break;
13429a0bf528SMauro Carvalho Chehab 	}
13439a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 33, tmp);
13449a0bf528SMauro Carvalho Chehab 
13459a0bf528SMauro Carvalho Chehab 	tmp = dib7000p_read_word(state, 509);
13469a0bf528SMauro Carvalho Chehab 	if (!((tmp >> 6) & 0x1)) {
13479a0bf528SMauro Carvalho Chehab 		/* restart the fec */
13489a0bf528SMauro Carvalho Chehab 		tmp = dib7000p_read_word(state, 771);
13499a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 771, tmp | (1 << 1));
13509a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 771, tmp);
13519a0bf528SMauro Carvalho Chehab 		msleep(40);
13529a0bf528SMauro Carvalho Chehab 		tmp = dib7000p_read_word(state, 509);
13539a0bf528SMauro Carvalho Chehab 	}
13549a0bf528SMauro Carvalho Chehab 	// we achieved a lock - it's time to update the osc freq
13559a0bf528SMauro Carvalho Chehab 	if ((tmp >> 6) & 0x1) {
13569a0bf528SMauro Carvalho Chehab 		dib7000p_update_timf(state);
13579a0bf528SMauro Carvalho Chehab 		/* P_timf_alpha += 2 */
13589a0bf528SMauro Carvalho Chehab 		tmp = dib7000p_read_word(state, 26);
13599a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
13609a0bf528SMauro Carvalho Chehab 	}
13619a0bf528SMauro Carvalho Chehab 
13629a0bf528SMauro Carvalho Chehab 	if (state->cfg.spur_protect)
13639a0bf528SMauro Carvalho Chehab 		dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
13649a0bf528SMauro Carvalho Chehab 
13659a0bf528SMauro Carvalho Chehab 	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
1366*041ad449SMauro Carvalho Chehab 
1367*041ad449SMauro Carvalho Chehab 	dib7000p_reset_stats(demod);
1368*041ad449SMauro Carvalho Chehab 
13699a0bf528SMauro Carvalho Chehab 	return 0;
13709a0bf528SMauro Carvalho Chehab }
13719a0bf528SMauro Carvalho Chehab 
13729a0bf528SMauro Carvalho Chehab static int dib7000p_wakeup(struct dvb_frontend *demod)
13739a0bf528SMauro Carvalho Chehab {
13749a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
13759a0bf528SMauro Carvalho Chehab 	dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
13769a0bf528SMauro Carvalho Chehab 	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
13779a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090)
13789a0bf528SMauro Carvalho Chehab 		dib7000p_sad_calib(state);
13799a0bf528SMauro Carvalho Chehab 	return 0;
13809a0bf528SMauro Carvalho Chehab }
13819a0bf528SMauro Carvalho Chehab 
13829a0bf528SMauro Carvalho Chehab static int dib7000p_sleep(struct dvb_frontend *demod)
13839a0bf528SMauro Carvalho Chehab {
13849a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
13859a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090)
13869a0bf528SMauro Carvalho Chehab 		return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
13879a0bf528SMauro Carvalho Chehab 	return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
13889a0bf528SMauro Carvalho Chehab }
13899a0bf528SMauro Carvalho Chehab 
13909a0bf528SMauro Carvalho Chehab static int dib7000p_identify(struct dib7000p_state *st)
13919a0bf528SMauro Carvalho Chehab {
13929a0bf528SMauro Carvalho Chehab 	u16 value;
13939a0bf528SMauro Carvalho Chehab 	dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr);
13949a0bf528SMauro Carvalho Chehab 
13959a0bf528SMauro Carvalho Chehab 	if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
13969a0bf528SMauro Carvalho Chehab 		dprintk("wrong Vendor ID (read=0x%x)", value);
13979a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO;
13989a0bf528SMauro Carvalho Chehab 	}
13999a0bf528SMauro Carvalho Chehab 
14009a0bf528SMauro Carvalho Chehab 	if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
14019a0bf528SMauro Carvalho Chehab 		dprintk("wrong Device ID (%x)", value);
14029a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO;
14039a0bf528SMauro Carvalho Chehab 	}
14049a0bf528SMauro Carvalho Chehab 
14059a0bf528SMauro Carvalho Chehab 	return 0;
14069a0bf528SMauro Carvalho Chehab }
14079a0bf528SMauro Carvalho Chehab 
14089a0bf528SMauro Carvalho Chehab static int dib7000p_get_frontend(struct dvb_frontend *fe)
14099a0bf528SMauro Carvalho Chehab {
14109a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
14119a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
14129a0bf528SMauro Carvalho Chehab 	u16 tps = dib7000p_read_word(state, 463);
14139a0bf528SMauro Carvalho Chehab 
14149a0bf528SMauro Carvalho Chehab 	fep->inversion = INVERSION_AUTO;
14159a0bf528SMauro Carvalho Chehab 
14169a0bf528SMauro Carvalho Chehab 	fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
14179a0bf528SMauro Carvalho Chehab 
14189a0bf528SMauro Carvalho Chehab 	switch ((tps >> 8) & 0x3) {
14199a0bf528SMauro Carvalho Chehab 	case 0:
14209a0bf528SMauro Carvalho Chehab 		fep->transmission_mode = TRANSMISSION_MODE_2K;
14219a0bf528SMauro Carvalho Chehab 		break;
14229a0bf528SMauro Carvalho Chehab 	case 1:
14239a0bf528SMauro Carvalho Chehab 		fep->transmission_mode = TRANSMISSION_MODE_8K;
14249a0bf528SMauro Carvalho Chehab 		break;
14259a0bf528SMauro Carvalho Chehab 	/* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
14269a0bf528SMauro Carvalho Chehab 	}
14279a0bf528SMauro Carvalho Chehab 
14289a0bf528SMauro Carvalho Chehab 	switch (tps & 0x3) {
14299a0bf528SMauro Carvalho Chehab 	case 0:
14309a0bf528SMauro Carvalho Chehab 		fep->guard_interval = GUARD_INTERVAL_1_32;
14319a0bf528SMauro Carvalho Chehab 		break;
14329a0bf528SMauro Carvalho Chehab 	case 1:
14339a0bf528SMauro Carvalho Chehab 		fep->guard_interval = GUARD_INTERVAL_1_16;
14349a0bf528SMauro Carvalho Chehab 		break;
14359a0bf528SMauro Carvalho Chehab 	case 2:
14369a0bf528SMauro Carvalho Chehab 		fep->guard_interval = GUARD_INTERVAL_1_8;
14379a0bf528SMauro Carvalho Chehab 		break;
14389a0bf528SMauro Carvalho Chehab 	case 3:
14399a0bf528SMauro Carvalho Chehab 		fep->guard_interval = GUARD_INTERVAL_1_4;
14409a0bf528SMauro Carvalho Chehab 		break;
14419a0bf528SMauro Carvalho Chehab 	}
14429a0bf528SMauro Carvalho Chehab 
14439a0bf528SMauro Carvalho Chehab 	switch ((tps >> 14) & 0x3) {
14449a0bf528SMauro Carvalho Chehab 	case 0:
14459a0bf528SMauro Carvalho Chehab 		fep->modulation = QPSK;
14469a0bf528SMauro Carvalho Chehab 		break;
14479a0bf528SMauro Carvalho Chehab 	case 1:
14489a0bf528SMauro Carvalho Chehab 		fep->modulation = QAM_16;
14499a0bf528SMauro Carvalho Chehab 		break;
14509a0bf528SMauro Carvalho Chehab 	case 2:
14519a0bf528SMauro Carvalho Chehab 	default:
14529a0bf528SMauro Carvalho Chehab 		fep->modulation = QAM_64;
14539a0bf528SMauro Carvalho Chehab 		break;
14549a0bf528SMauro Carvalho Chehab 	}
14559a0bf528SMauro Carvalho Chehab 
14569a0bf528SMauro Carvalho Chehab 	/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
14579a0bf528SMauro Carvalho Chehab 	/* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
14589a0bf528SMauro Carvalho Chehab 
14599a0bf528SMauro Carvalho Chehab 	fep->hierarchy = HIERARCHY_NONE;
14609a0bf528SMauro Carvalho Chehab 	switch ((tps >> 5) & 0x7) {
14619a0bf528SMauro Carvalho Chehab 	case 1:
14629a0bf528SMauro Carvalho Chehab 		fep->code_rate_HP = FEC_1_2;
14639a0bf528SMauro Carvalho Chehab 		break;
14649a0bf528SMauro Carvalho Chehab 	case 2:
14659a0bf528SMauro Carvalho Chehab 		fep->code_rate_HP = FEC_2_3;
14669a0bf528SMauro Carvalho Chehab 		break;
14679a0bf528SMauro Carvalho Chehab 	case 3:
14689a0bf528SMauro Carvalho Chehab 		fep->code_rate_HP = FEC_3_4;
14699a0bf528SMauro Carvalho Chehab 		break;
14709a0bf528SMauro Carvalho Chehab 	case 5:
14719a0bf528SMauro Carvalho Chehab 		fep->code_rate_HP = FEC_5_6;
14729a0bf528SMauro Carvalho Chehab 		break;
14739a0bf528SMauro Carvalho Chehab 	case 7:
14749a0bf528SMauro Carvalho Chehab 	default:
14759a0bf528SMauro Carvalho Chehab 		fep->code_rate_HP = FEC_7_8;
14769a0bf528SMauro Carvalho Chehab 		break;
14779a0bf528SMauro Carvalho Chehab 
14789a0bf528SMauro Carvalho Chehab 	}
14799a0bf528SMauro Carvalho Chehab 
14809a0bf528SMauro Carvalho Chehab 	switch ((tps >> 2) & 0x7) {
14819a0bf528SMauro Carvalho Chehab 	case 1:
14829a0bf528SMauro Carvalho Chehab 		fep->code_rate_LP = FEC_1_2;
14839a0bf528SMauro Carvalho Chehab 		break;
14849a0bf528SMauro Carvalho Chehab 	case 2:
14859a0bf528SMauro Carvalho Chehab 		fep->code_rate_LP = FEC_2_3;
14869a0bf528SMauro Carvalho Chehab 		break;
14879a0bf528SMauro Carvalho Chehab 	case 3:
14889a0bf528SMauro Carvalho Chehab 		fep->code_rate_LP = FEC_3_4;
14899a0bf528SMauro Carvalho Chehab 		break;
14909a0bf528SMauro Carvalho Chehab 	case 5:
14919a0bf528SMauro Carvalho Chehab 		fep->code_rate_LP = FEC_5_6;
14929a0bf528SMauro Carvalho Chehab 		break;
14939a0bf528SMauro Carvalho Chehab 	case 7:
14949a0bf528SMauro Carvalho Chehab 	default:
14959a0bf528SMauro Carvalho Chehab 		fep->code_rate_LP = FEC_7_8;
14969a0bf528SMauro Carvalho Chehab 		break;
14979a0bf528SMauro Carvalho Chehab 	}
14989a0bf528SMauro Carvalho Chehab 
14999a0bf528SMauro Carvalho Chehab 	/* native interleaver: (dib7000p_read_word(state, 464) >>  5) & 0x1 */
15009a0bf528SMauro Carvalho Chehab 
15019a0bf528SMauro Carvalho Chehab 	return 0;
15029a0bf528SMauro Carvalho Chehab }
15039a0bf528SMauro Carvalho Chehab 
15049a0bf528SMauro Carvalho Chehab static int dib7000p_set_frontend(struct dvb_frontend *fe)
15059a0bf528SMauro Carvalho Chehab {
15069a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
15079a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
15089a0bf528SMauro Carvalho Chehab 	int time, ret;
15099a0bf528SMauro Carvalho Chehab 
15109a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090)
15119a0bf528SMauro Carvalho Chehab 		dib7090_set_diversity_in(fe, 0);
15129a0bf528SMauro Carvalho Chehab 	else
15139a0bf528SMauro Carvalho Chehab 		dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
15149a0bf528SMauro Carvalho Chehab 
15159a0bf528SMauro Carvalho Chehab 	/* maybe the parameter has been changed */
15169a0bf528SMauro Carvalho Chehab 	state->sfn_workaround_active = buggy_sfn_workaround;
15179a0bf528SMauro Carvalho Chehab 
15189a0bf528SMauro Carvalho Chehab 	if (fe->ops.tuner_ops.set_params)
15199a0bf528SMauro Carvalho Chehab 		fe->ops.tuner_ops.set_params(fe);
15209a0bf528SMauro Carvalho Chehab 
15219a0bf528SMauro Carvalho Chehab 	/* start up the AGC */
15229a0bf528SMauro Carvalho Chehab 	state->agc_state = 0;
15239a0bf528SMauro Carvalho Chehab 	do {
15249a0bf528SMauro Carvalho Chehab 		time = dib7000p_agc_startup(fe);
15259a0bf528SMauro Carvalho Chehab 		if (time != -1)
15269a0bf528SMauro Carvalho Chehab 			msleep(time);
15279a0bf528SMauro Carvalho Chehab 	} while (time != -1);
15289a0bf528SMauro Carvalho Chehab 
15299a0bf528SMauro Carvalho Chehab 	if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
15309a0bf528SMauro Carvalho Chehab 		fep->guard_interval == GUARD_INTERVAL_AUTO || fep->modulation == QAM_AUTO || fep->code_rate_HP == FEC_AUTO) {
15319a0bf528SMauro Carvalho Chehab 		int i = 800, found;
15329a0bf528SMauro Carvalho Chehab 
15339a0bf528SMauro Carvalho Chehab 		dib7000p_autosearch_start(fe);
15349a0bf528SMauro Carvalho Chehab 		do {
15359a0bf528SMauro Carvalho Chehab 			msleep(1);
15369a0bf528SMauro Carvalho Chehab 			found = dib7000p_autosearch_is_irq(fe);
15379a0bf528SMauro Carvalho Chehab 		} while (found == 0 && i--);
15389a0bf528SMauro Carvalho Chehab 
15399a0bf528SMauro Carvalho Chehab 		dprintk("autosearch returns: %d", found);
15409a0bf528SMauro Carvalho Chehab 		if (found == 0 || found == 1)
15419a0bf528SMauro Carvalho Chehab 			return 0;
15429a0bf528SMauro Carvalho Chehab 
15439a0bf528SMauro Carvalho Chehab 		dib7000p_get_frontend(fe);
15449a0bf528SMauro Carvalho Chehab 	}
15459a0bf528SMauro Carvalho Chehab 
15469a0bf528SMauro Carvalho Chehab 	ret = dib7000p_tune(fe);
15479a0bf528SMauro Carvalho Chehab 
15489a0bf528SMauro Carvalho Chehab 	/* make this a config parameter */
15499a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090) {
15509a0bf528SMauro Carvalho Chehab 		dib7090_set_output_mode(fe, state->cfg.output_mode);
15519a0bf528SMauro Carvalho Chehab 		if (state->cfg.enMpegOutput == 0) {
15529a0bf528SMauro Carvalho Chehab 			dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
15539a0bf528SMauro Carvalho Chehab 			dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
15549a0bf528SMauro Carvalho Chehab 		}
15559a0bf528SMauro Carvalho Chehab 	} else
15569a0bf528SMauro Carvalho Chehab 		dib7000p_set_output_mode(state, state->cfg.output_mode);
15579a0bf528SMauro Carvalho Chehab 
15589a0bf528SMauro Carvalho Chehab 	return ret;
15599a0bf528SMauro Carvalho Chehab }
15609a0bf528SMauro Carvalho Chehab 
1561*041ad449SMauro Carvalho Chehab static int dib7000p_get_stats(struct dvb_frontend *fe, fe_status_t stat);
1562*041ad449SMauro Carvalho Chehab 
15639a0bf528SMauro Carvalho Chehab static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
15649a0bf528SMauro Carvalho Chehab {
15659a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
15669a0bf528SMauro Carvalho Chehab 	u16 lock = dib7000p_read_word(state, 509);
15679a0bf528SMauro Carvalho Chehab 
15689a0bf528SMauro Carvalho Chehab 	*stat = 0;
15699a0bf528SMauro Carvalho Chehab 
15709a0bf528SMauro Carvalho Chehab 	if (lock & 0x8000)
15719a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SIGNAL;
15729a0bf528SMauro Carvalho Chehab 	if (lock & 0x3000)
15739a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_CARRIER;
15749a0bf528SMauro Carvalho Chehab 	if (lock & 0x0100)
15759a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_VITERBI;
15769a0bf528SMauro Carvalho Chehab 	if (lock & 0x0010)
15779a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SYNC;
15789a0bf528SMauro Carvalho Chehab 	if ((lock & 0x0038) == 0x38)
15799a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_LOCK;
15809a0bf528SMauro Carvalho Chehab 
1581*041ad449SMauro Carvalho Chehab 	dib7000p_get_stats(fe, *stat);
1582*041ad449SMauro Carvalho Chehab 
15839a0bf528SMauro Carvalho Chehab 	return 0;
15849a0bf528SMauro Carvalho Chehab }
15859a0bf528SMauro Carvalho Chehab 
15869a0bf528SMauro Carvalho Chehab static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
15879a0bf528SMauro Carvalho Chehab {
15889a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
15899a0bf528SMauro Carvalho Chehab 	*ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
15909a0bf528SMauro Carvalho Chehab 	return 0;
15919a0bf528SMauro Carvalho Chehab }
15929a0bf528SMauro Carvalho Chehab 
15939a0bf528SMauro Carvalho Chehab static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
15949a0bf528SMauro Carvalho Chehab {
15959a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
15969a0bf528SMauro Carvalho Chehab 	*unc = dib7000p_read_word(state, 506);
15979a0bf528SMauro Carvalho Chehab 	return 0;
15989a0bf528SMauro Carvalho Chehab }
15999a0bf528SMauro Carvalho Chehab 
16009a0bf528SMauro Carvalho Chehab static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
16019a0bf528SMauro Carvalho Chehab {
16029a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
16039a0bf528SMauro Carvalho Chehab 	u16 val = dib7000p_read_word(state, 394);
16049a0bf528SMauro Carvalho Chehab 	*strength = 65535 - val;
16059a0bf528SMauro Carvalho Chehab 	return 0;
16069a0bf528SMauro Carvalho Chehab }
16079a0bf528SMauro Carvalho Chehab 
1608*041ad449SMauro Carvalho Chehab static u32 dib7000p_get_snr(struct dvb_frontend *fe)
16099a0bf528SMauro Carvalho Chehab {
16109a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
16119a0bf528SMauro Carvalho Chehab 	u16 val;
16129a0bf528SMauro Carvalho Chehab 	s32 signal_mant, signal_exp, noise_mant, noise_exp;
16139a0bf528SMauro Carvalho Chehab 	u32 result = 0;
16149a0bf528SMauro Carvalho Chehab 
16159a0bf528SMauro Carvalho Chehab 	val = dib7000p_read_word(state, 479);
16169a0bf528SMauro Carvalho Chehab 	noise_mant = (val >> 4) & 0xff;
16179a0bf528SMauro Carvalho Chehab 	noise_exp = ((val & 0xf) << 2);
16189a0bf528SMauro Carvalho Chehab 	val = dib7000p_read_word(state, 480);
16199a0bf528SMauro Carvalho Chehab 	noise_exp += ((val >> 14) & 0x3);
16209a0bf528SMauro Carvalho Chehab 	if ((noise_exp & 0x20) != 0)
16219a0bf528SMauro Carvalho Chehab 		noise_exp -= 0x40;
16229a0bf528SMauro Carvalho Chehab 
16239a0bf528SMauro Carvalho Chehab 	signal_mant = (val >> 6) & 0xFF;
16249a0bf528SMauro Carvalho Chehab 	signal_exp = (val & 0x3F);
16259a0bf528SMauro Carvalho Chehab 	if ((signal_exp & 0x20) != 0)
16269a0bf528SMauro Carvalho Chehab 		signal_exp -= 0x40;
16279a0bf528SMauro Carvalho Chehab 
16289a0bf528SMauro Carvalho Chehab 	if (signal_mant != 0)
16299a0bf528SMauro Carvalho Chehab 		result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
16309a0bf528SMauro Carvalho Chehab 	else
16319a0bf528SMauro Carvalho Chehab 		result = intlog10(2) * 10 * signal_exp - 100;
16329a0bf528SMauro Carvalho Chehab 
16339a0bf528SMauro Carvalho Chehab 	if (noise_mant != 0)
16349a0bf528SMauro Carvalho Chehab 		result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
16359a0bf528SMauro Carvalho Chehab 	else
16369a0bf528SMauro Carvalho Chehab 		result -= intlog10(2) * 10 * noise_exp - 100;
16379a0bf528SMauro Carvalho Chehab 
1638*041ad449SMauro Carvalho Chehab 	return result;
1639*041ad449SMauro Carvalho Chehab }
1640*041ad449SMauro Carvalho Chehab 
1641*041ad449SMauro Carvalho Chehab static int dib7000p_read_snr(struct dvb_frontend *fe, u16 *snr)
1642*041ad449SMauro Carvalho Chehab {
1643*041ad449SMauro Carvalho Chehab 	u32 result;
1644*041ad449SMauro Carvalho Chehab 
1645*041ad449SMauro Carvalho Chehab 	result = dib7000p_get_snr(fe);
1646*041ad449SMauro Carvalho Chehab 
16479a0bf528SMauro Carvalho Chehab 	*snr = result / ((1 << 24) / 10);
16489a0bf528SMauro Carvalho Chehab 	return 0;
16499a0bf528SMauro Carvalho Chehab }
16509a0bf528SMauro Carvalho Chehab 
1651*041ad449SMauro Carvalho Chehab static void dib7000p_reset_stats(struct dvb_frontend *demod)
1652*041ad449SMauro Carvalho Chehab {
1653*041ad449SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
1654*041ad449SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1655*041ad449SMauro Carvalho Chehab 	u32 ucb;
1656*041ad449SMauro Carvalho Chehab 
1657*041ad449SMauro Carvalho Chehab 	memset(&c->strength, 0, sizeof(c->strength));
1658*041ad449SMauro Carvalho Chehab 	memset(&c->cnr, 0, sizeof(c->cnr));
1659*041ad449SMauro Carvalho Chehab 	memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
1660*041ad449SMauro Carvalho Chehab 	memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
1661*041ad449SMauro Carvalho Chehab 	memset(&c->block_error, 0, sizeof(c->block_error));
1662*041ad449SMauro Carvalho Chehab 
1663*041ad449SMauro Carvalho Chehab 	c->strength.len = 1;
1664*041ad449SMauro Carvalho Chehab 	c->cnr.len = 1;
1665*041ad449SMauro Carvalho Chehab 	c->block_error.len = 1;
1666*041ad449SMauro Carvalho Chehab 	c->block_count.len = 1;
1667*041ad449SMauro Carvalho Chehab 	c->post_bit_error.len = 1;
1668*041ad449SMauro Carvalho Chehab 	c->post_bit_count.len = 1;
1669*041ad449SMauro Carvalho Chehab 
1670*041ad449SMauro Carvalho Chehab 	c->strength.stat[0].scale = FE_SCALE_DECIBEL;
1671*041ad449SMauro Carvalho Chehab 	c->strength.stat[0].uvalue = 0;
1672*041ad449SMauro Carvalho Chehab 
1673*041ad449SMauro Carvalho Chehab 	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1674*041ad449SMauro Carvalho Chehab 	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1675*041ad449SMauro Carvalho Chehab 	c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1676*041ad449SMauro Carvalho Chehab 	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1677*041ad449SMauro Carvalho Chehab 	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1678*041ad449SMauro Carvalho Chehab 
1679*041ad449SMauro Carvalho Chehab 	dib7000p_read_unc_blocks(demod, &ucb);
1680*041ad449SMauro Carvalho Chehab 
1681*041ad449SMauro Carvalho Chehab 	state->old_ucb = ucb;
1682*041ad449SMauro Carvalho Chehab 	state->ber_jiffies_stats = 0;
1683*041ad449SMauro Carvalho Chehab 	state->per_jiffies_stats = 0;
1684*041ad449SMauro Carvalho Chehab }
1685*041ad449SMauro Carvalho Chehab 
1686*041ad449SMauro Carvalho Chehab struct linear_segments {
1687*041ad449SMauro Carvalho Chehab 	unsigned x;
1688*041ad449SMauro Carvalho Chehab 	signed y;
1689*041ad449SMauro Carvalho Chehab };
1690*041ad449SMauro Carvalho Chehab 
1691*041ad449SMauro Carvalho Chehab /*
1692*041ad449SMauro Carvalho Chehab  * Table to estimate signal strength in dBm.
1693*041ad449SMauro Carvalho Chehab  * This table should be empirically determinated by measuring the signal
1694*041ad449SMauro Carvalho Chehab  * strength generated by a RF generator directly connected into
1695*041ad449SMauro Carvalho Chehab  * a device.
1696*041ad449SMauro Carvalho Chehab  */
1697*041ad449SMauro Carvalho Chehab /* FIXME: Calibrate the table */
1698*041ad449SMauro Carvalho Chehab 
1699*041ad449SMauro Carvalho Chehab #define DB_OFFSET 0
1700*041ad449SMauro Carvalho Chehab 
1701*041ad449SMauro Carvalho Chehab static struct linear_segments strength_to_db_table[] = {
1702*041ad449SMauro Carvalho Chehab 	{ 65535,  65535},
1703*041ad449SMauro Carvalho Chehab 	{     0,      0},
1704*041ad449SMauro Carvalho Chehab };
1705*041ad449SMauro Carvalho Chehab 
1706*041ad449SMauro Carvalho Chehab static u32 interpolate_value(u32 value, struct linear_segments *segments,
1707*041ad449SMauro Carvalho Chehab 			     unsigned len)
1708*041ad449SMauro Carvalho Chehab {
1709*041ad449SMauro Carvalho Chehab 	u64 tmp64;
1710*041ad449SMauro Carvalho Chehab 	u32 dx;
1711*041ad449SMauro Carvalho Chehab 	s32 dy;
1712*041ad449SMauro Carvalho Chehab 	int i, ret;
1713*041ad449SMauro Carvalho Chehab 
1714*041ad449SMauro Carvalho Chehab 	if (value >= segments[0].x)
1715*041ad449SMauro Carvalho Chehab 		return segments[0].y;
1716*041ad449SMauro Carvalho Chehab 	if (value < segments[len-1].x)
1717*041ad449SMauro Carvalho Chehab 		return segments[len-1].y;
1718*041ad449SMauro Carvalho Chehab 
1719*041ad449SMauro Carvalho Chehab 	for (i = 1; i < len - 1; i++) {
1720*041ad449SMauro Carvalho Chehab 		/* If value is identical, no need to interpolate */
1721*041ad449SMauro Carvalho Chehab 		if (value == segments[i].x)
1722*041ad449SMauro Carvalho Chehab 			return segments[i].y;
1723*041ad449SMauro Carvalho Chehab 		if (value > segments[i].x)
1724*041ad449SMauro Carvalho Chehab 			break;
1725*041ad449SMauro Carvalho Chehab 	}
1726*041ad449SMauro Carvalho Chehab 
1727*041ad449SMauro Carvalho Chehab 	/* Linear interpolation between the two (x,y) points */
1728*041ad449SMauro Carvalho Chehab 	dy = segments[i - 1].y - segments[i].y;
1729*041ad449SMauro Carvalho Chehab 	dx = segments[i - 1].x - segments[i].x;
1730*041ad449SMauro Carvalho Chehab 
1731*041ad449SMauro Carvalho Chehab 	tmp64 = value - segments[i].x;
1732*041ad449SMauro Carvalho Chehab 	tmp64 *= dy;
1733*041ad449SMauro Carvalho Chehab 	do_div(tmp64, dx);
1734*041ad449SMauro Carvalho Chehab 	ret = segments[i].y + tmp64;
1735*041ad449SMauro Carvalho Chehab 
1736*041ad449SMauro Carvalho Chehab 	return ret;
1737*041ad449SMauro Carvalho Chehab }
1738*041ad449SMauro Carvalho Chehab 
1739*041ad449SMauro Carvalho Chehab /* FIXME: may require changes - this one was borrowed from dib8000 */
1740*041ad449SMauro Carvalho Chehab static u32 dib7000p_get_time_us(struct dvb_frontend *demod, int layer)
1741*041ad449SMauro Carvalho Chehab {
1742*041ad449SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1743*041ad449SMauro Carvalho Chehab 	u64 time_us, tmp64;
1744*041ad449SMauro Carvalho Chehab 	u32 tmp, denom;
1745*041ad449SMauro Carvalho Chehab 	int guard, rate_num, rate_denum = 1, bits_per_symbol;
1746*041ad449SMauro Carvalho Chehab 	int interleaving = 0, fft_div;
1747*041ad449SMauro Carvalho Chehab 
1748*041ad449SMauro Carvalho Chehab 	switch (c->guard_interval) {
1749*041ad449SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_4:
1750*041ad449SMauro Carvalho Chehab 		guard = 4;
1751*041ad449SMauro Carvalho Chehab 		break;
1752*041ad449SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_8:
1753*041ad449SMauro Carvalho Chehab 		guard = 8;
1754*041ad449SMauro Carvalho Chehab 		break;
1755*041ad449SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_16:
1756*041ad449SMauro Carvalho Chehab 		guard = 16;
1757*041ad449SMauro Carvalho Chehab 		break;
1758*041ad449SMauro Carvalho Chehab 	default:
1759*041ad449SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_32:
1760*041ad449SMauro Carvalho Chehab 		guard = 32;
1761*041ad449SMauro Carvalho Chehab 		break;
1762*041ad449SMauro Carvalho Chehab 	}
1763*041ad449SMauro Carvalho Chehab 
1764*041ad449SMauro Carvalho Chehab 	switch (c->transmission_mode) {
1765*041ad449SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
1766*041ad449SMauro Carvalho Chehab 		fft_div = 4;
1767*041ad449SMauro Carvalho Chehab 		break;
1768*041ad449SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
1769*041ad449SMauro Carvalho Chehab 		fft_div = 2;
1770*041ad449SMauro Carvalho Chehab 		break;
1771*041ad449SMauro Carvalho Chehab 	default:
1772*041ad449SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
1773*041ad449SMauro Carvalho Chehab 		fft_div = 1;
1774*041ad449SMauro Carvalho Chehab 		break;
1775*041ad449SMauro Carvalho Chehab 	}
1776*041ad449SMauro Carvalho Chehab 
1777*041ad449SMauro Carvalho Chehab 	switch (c->modulation) {
1778*041ad449SMauro Carvalho Chehab 	case DQPSK:
1779*041ad449SMauro Carvalho Chehab 	case QPSK:
1780*041ad449SMauro Carvalho Chehab 		bits_per_symbol = 2;
1781*041ad449SMauro Carvalho Chehab 		break;
1782*041ad449SMauro Carvalho Chehab 	case QAM_16:
1783*041ad449SMauro Carvalho Chehab 		bits_per_symbol = 4;
1784*041ad449SMauro Carvalho Chehab 		break;
1785*041ad449SMauro Carvalho Chehab 	default:
1786*041ad449SMauro Carvalho Chehab 	case QAM_64:
1787*041ad449SMauro Carvalho Chehab 		bits_per_symbol = 6;
1788*041ad449SMauro Carvalho Chehab 		break;
1789*041ad449SMauro Carvalho Chehab 	}
1790*041ad449SMauro Carvalho Chehab 
1791*041ad449SMauro Carvalho Chehab 	switch ((c->hierarchy == 0 || 1 == 1) ? c->code_rate_HP : c->code_rate_LP) {
1792*041ad449SMauro Carvalho Chehab 	case FEC_1_2:
1793*041ad449SMauro Carvalho Chehab 		rate_num = 1;
1794*041ad449SMauro Carvalho Chehab 		rate_denum = 2;
1795*041ad449SMauro Carvalho Chehab 		break;
1796*041ad449SMauro Carvalho Chehab 	case FEC_2_3:
1797*041ad449SMauro Carvalho Chehab 		rate_num = 2;
1798*041ad449SMauro Carvalho Chehab 		rate_denum = 3;
1799*041ad449SMauro Carvalho Chehab 		break;
1800*041ad449SMauro Carvalho Chehab 	case FEC_3_4:
1801*041ad449SMauro Carvalho Chehab 		rate_num = 3;
1802*041ad449SMauro Carvalho Chehab 		rate_denum = 4;
1803*041ad449SMauro Carvalho Chehab 		break;
1804*041ad449SMauro Carvalho Chehab 	case FEC_5_6:
1805*041ad449SMauro Carvalho Chehab 		rate_num = 5;
1806*041ad449SMauro Carvalho Chehab 		rate_denum = 6;
1807*041ad449SMauro Carvalho Chehab 		break;
1808*041ad449SMauro Carvalho Chehab 	default:
1809*041ad449SMauro Carvalho Chehab 	case FEC_7_8:
1810*041ad449SMauro Carvalho Chehab 		rate_num = 7;
1811*041ad449SMauro Carvalho Chehab 		rate_denum = 8;
1812*041ad449SMauro Carvalho Chehab 		break;
1813*041ad449SMauro Carvalho Chehab 	}
1814*041ad449SMauro Carvalho Chehab 
1815*041ad449SMauro Carvalho Chehab 	interleaving = interleaving;
1816*041ad449SMauro Carvalho Chehab 
1817*041ad449SMauro Carvalho Chehab 	denom = bits_per_symbol * rate_num * fft_div * 384;
1818*041ad449SMauro Carvalho Chehab 
1819*041ad449SMauro Carvalho Chehab 	/* If calculus gets wrong, wait for 1s for the next stats */
1820*041ad449SMauro Carvalho Chehab 	if (!denom)
1821*041ad449SMauro Carvalho Chehab 		return 0;
1822*041ad449SMauro Carvalho Chehab 
1823*041ad449SMauro Carvalho Chehab 	/* Estimate the period for the total bit rate */
1824*041ad449SMauro Carvalho Chehab 	time_us = rate_denum * (1008 * 1562500L);
1825*041ad449SMauro Carvalho Chehab 	tmp64 = time_us;
1826*041ad449SMauro Carvalho Chehab 	do_div(tmp64, guard);
1827*041ad449SMauro Carvalho Chehab 	time_us = time_us + tmp64;
1828*041ad449SMauro Carvalho Chehab 	time_us += denom / 2;
1829*041ad449SMauro Carvalho Chehab 	do_div(time_us, denom);
1830*041ad449SMauro Carvalho Chehab 
1831*041ad449SMauro Carvalho Chehab 	tmp = 1008 * 96 * interleaving;
1832*041ad449SMauro Carvalho Chehab 	time_us += tmp + tmp / guard;
1833*041ad449SMauro Carvalho Chehab 
1834*041ad449SMauro Carvalho Chehab 	return time_us;
1835*041ad449SMauro Carvalho Chehab }
1836*041ad449SMauro Carvalho Chehab 
1837*041ad449SMauro Carvalho Chehab static int dib7000p_get_stats(struct dvb_frontend *demod, fe_status_t stat)
1838*041ad449SMauro Carvalho Chehab {
1839*041ad449SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
1840*041ad449SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1841*041ad449SMauro Carvalho Chehab 	int i;
1842*041ad449SMauro Carvalho Chehab 	int show_per_stats = 0;
1843*041ad449SMauro Carvalho Chehab 	u32 time_us = 0, val, snr;
1844*041ad449SMauro Carvalho Chehab 	u64 blocks, ucb;
1845*041ad449SMauro Carvalho Chehab 	s32 db;
1846*041ad449SMauro Carvalho Chehab 	u16 strength;
1847*041ad449SMauro Carvalho Chehab 
1848*041ad449SMauro Carvalho Chehab 	/* Get Signal strength */
1849*041ad449SMauro Carvalho Chehab 	dib7000p_read_signal_strength(demod, &strength);
1850*041ad449SMauro Carvalho Chehab 	val = strength;
1851*041ad449SMauro Carvalho Chehab 	db = interpolate_value(val,
1852*041ad449SMauro Carvalho Chehab 			       strength_to_db_table,
1853*041ad449SMauro Carvalho Chehab 			       ARRAY_SIZE(strength_to_db_table)) - DB_OFFSET;
1854*041ad449SMauro Carvalho Chehab 	c->strength.stat[0].svalue = db;
1855*041ad449SMauro Carvalho Chehab 
1856*041ad449SMauro Carvalho Chehab 	/* FIXME: Remove this when calibrated to DB */
1857*041ad449SMauro Carvalho Chehab 	c->strength.stat[0].scale = FE_SCALE_COUNTER;
1858*041ad449SMauro Carvalho Chehab 
1859*041ad449SMauro Carvalho Chehab 	/* UCB/BER/CNR measures require lock */
1860*041ad449SMauro Carvalho Chehab 	if (!(stat & FE_HAS_LOCK)) {
1861*041ad449SMauro Carvalho Chehab 		c->cnr.len = 1;
1862*041ad449SMauro Carvalho Chehab 		c->block_count.len = 1;
1863*041ad449SMauro Carvalho Chehab 		c->block_error.len = 1;
1864*041ad449SMauro Carvalho Chehab 		c->post_bit_error.len = 1;
1865*041ad449SMauro Carvalho Chehab 		c->post_bit_count.len = 1;
1866*041ad449SMauro Carvalho Chehab 		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1867*041ad449SMauro Carvalho Chehab 		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1868*041ad449SMauro Carvalho Chehab 		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1869*041ad449SMauro Carvalho Chehab 		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1870*041ad449SMauro Carvalho Chehab 		c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1871*041ad449SMauro Carvalho Chehab 		return 0;
1872*041ad449SMauro Carvalho Chehab 	}
1873*041ad449SMauro Carvalho Chehab 
1874*041ad449SMauro Carvalho Chehab 	/* Check if time for stats was elapsed */
1875*041ad449SMauro Carvalho Chehab 	if (time_after(jiffies, state->per_jiffies_stats)) {
1876*041ad449SMauro Carvalho Chehab 		state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
1877*041ad449SMauro Carvalho Chehab 
1878*041ad449SMauro Carvalho Chehab 		/* Get SNR */
1879*041ad449SMauro Carvalho Chehab 		snr = dib7000p_get_snr(demod);
1880*041ad449SMauro Carvalho Chehab 		if (snr)
1881*041ad449SMauro Carvalho Chehab 			snr = (1000L * snr) >> 24;
1882*041ad449SMauro Carvalho Chehab 		else
1883*041ad449SMauro Carvalho Chehab 			snr = 0;
1884*041ad449SMauro Carvalho Chehab 		c->cnr.stat[0].svalue = snr;
1885*041ad449SMauro Carvalho Chehab 		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
1886*041ad449SMauro Carvalho Chehab 
1887*041ad449SMauro Carvalho Chehab 		/* Get UCB measures */
1888*041ad449SMauro Carvalho Chehab 		dib7000p_read_unc_blocks(demod, &val);
1889*041ad449SMauro Carvalho Chehab 		ucb = val - state->old_ucb;
1890*041ad449SMauro Carvalho Chehab 		if (val < state->old_ucb)
1891*041ad449SMauro Carvalho Chehab 			ucb += 0x100000000LL;
1892*041ad449SMauro Carvalho Chehab 
1893*041ad449SMauro Carvalho Chehab 		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
1894*041ad449SMauro Carvalho Chehab 		c->block_error.stat[0].uvalue = ucb;
1895*041ad449SMauro Carvalho Chehab 
1896*041ad449SMauro Carvalho Chehab 		/* Estimate the number of packets based on bitrate */
1897*041ad449SMauro Carvalho Chehab 		if (!time_us)
1898*041ad449SMauro Carvalho Chehab 			time_us = dib7000p_get_time_us(demod, -1);
1899*041ad449SMauro Carvalho Chehab 
1900*041ad449SMauro Carvalho Chehab 		if (time_us) {
1901*041ad449SMauro Carvalho Chehab 			blocks = 1250000ULL * 1000000ULL;
1902*041ad449SMauro Carvalho Chehab 			do_div(blocks, time_us * 8 * 204);
1903*041ad449SMauro Carvalho Chehab 			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
1904*041ad449SMauro Carvalho Chehab 			c->block_count.stat[0].uvalue += blocks;
1905*041ad449SMauro Carvalho Chehab 		}
1906*041ad449SMauro Carvalho Chehab 
1907*041ad449SMauro Carvalho Chehab 		show_per_stats = 1;
1908*041ad449SMauro Carvalho Chehab 	}
1909*041ad449SMauro Carvalho Chehab 
1910*041ad449SMauro Carvalho Chehab 	/* Get post-BER measures */
1911*041ad449SMauro Carvalho Chehab 	if (time_after(jiffies, state->ber_jiffies_stats)) {
1912*041ad449SMauro Carvalho Chehab 		time_us = dib7000p_get_time_us(demod, -1);
1913*041ad449SMauro Carvalho Chehab 		state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
1914*041ad449SMauro Carvalho Chehab 
1915*041ad449SMauro Carvalho Chehab 		dprintk("Next all layers stats available in %u us.", time_us);
1916*041ad449SMauro Carvalho Chehab 
1917*041ad449SMauro Carvalho Chehab 		dib7000p_read_ber(demod, &val);
1918*041ad449SMauro Carvalho Chehab 		c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
1919*041ad449SMauro Carvalho Chehab 		c->post_bit_error.stat[0].uvalue += val;
1920*041ad449SMauro Carvalho Chehab 
1921*041ad449SMauro Carvalho Chehab 		c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
1922*041ad449SMauro Carvalho Chehab 		c->post_bit_count.stat[0].uvalue += 100000000;
1923*041ad449SMauro Carvalho Chehab 	}
1924*041ad449SMauro Carvalho Chehab 
1925*041ad449SMauro Carvalho Chehab 	/* Get PER measures */
1926*041ad449SMauro Carvalho Chehab 	if (show_per_stats) {
1927*041ad449SMauro Carvalho Chehab 		dib7000p_read_unc_blocks(demod, &val);
1928*041ad449SMauro Carvalho Chehab 
1929*041ad449SMauro Carvalho Chehab 		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
1930*041ad449SMauro Carvalho Chehab 		c->block_error.stat[0].uvalue += val;
1931*041ad449SMauro Carvalho Chehab 
1932*041ad449SMauro Carvalho Chehab 		time_us = dib7000p_get_time_us(demod, i);
1933*041ad449SMauro Carvalho Chehab 		if (time_us) {
1934*041ad449SMauro Carvalho Chehab 			blocks = 1250000ULL * 1000000ULL;
1935*041ad449SMauro Carvalho Chehab 			do_div(blocks, time_us * 8 * 204);
1936*041ad449SMauro Carvalho Chehab 			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
1937*041ad449SMauro Carvalho Chehab 			c->block_count.stat[0].uvalue += blocks;
1938*041ad449SMauro Carvalho Chehab 		}
1939*041ad449SMauro Carvalho Chehab 	}
1940*041ad449SMauro Carvalho Chehab 	return 0;
1941*041ad449SMauro Carvalho Chehab }
1942*041ad449SMauro Carvalho Chehab 
19439a0bf528SMauro Carvalho Chehab static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
19449a0bf528SMauro Carvalho Chehab {
19459a0bf528SMauro Carvalho Chehab 	tune->min_delay_ms = 1000;
19469a0bf528SMauro Carvalho Chehab 	return 0;
19479a0bf528SMauro Carvalho Chehab }
19489a0bf528SMauro Carvalho Chehab 
19499a0bf528SMauro Carvalho Chehab static void dib7000p_release(struct dvb_frontend *demod)
19509a0bf528SMauro Carvalho Chehab {
19519a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *st = demod->demodulator_priv;
19529a0bf528SMauro Carvalho Chehab 	dibx000_exit_i2c_master(&st->i2c_master);
19539a0bf528SMauro Carvalho Chehab 	i2c_del_adapter(&st->dib7090_tuner_adap);
19549a0bf528SMauro Carvalho Chehab 	kfree(st);
19559a0bf528SMauro Carvalho Chehab }
19569a0bf528SMauro Carvalho Chehab 
19578abe4a0aSMauro Carvalho Chehab static int dib7000pc_detection(struct i2c_adapter *i2c_adap)
19589a0bf528SMauro Carvalho Chehab {
19599a0bf528SMauro Carvalho Chehab 	u8 *tx, *rx;
19609a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2] = {
19619a0bf528SMauro Carvalho Chehab 		{.addr = 18 >> 1, .flags = 0, .len = 2},
19629a0bf528SMauro Carvalho Chehab 		{.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
19639a0bf528SMauro Carvalho Chehab 	};
19649a0bf528SMauro Carvalho Chehab 	int ret = 0;
19659a0bf528SMauro Carvalho Chehab 
19669a0bf528SMauro Carvalho Chehab 	tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
19679a0bf528SMauro Carvalho Chehab 	if (!tx)
19689a0bf528SMauro Carvalho Chehab 		return -ENOMEM;
19699a0bf528SMauro Carvalho Chehab 	rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
19709a0bf528SMauro Carvalho Chehab 	if (!rx) {
19719a0bf528SMauro Carvalho Chehab 		ret = -ENOMEM;
19729a0bf528SMauro Carvalho Chehab 		goto rx_memory_error;
19739a0bf528SMauro Carvalho Chehab 	}
19749a0bf528SMauro Carvalho Chehab 
19759a0bf528SMauro Carvalho Chehab 	msg[0].buf = tx;
19769a0bf528SMauro Carvalho Chehab 	msg[1].buf = rx;
19779a0bf528SMauro Carvalho Chehab 
19789a0bf528SMauro Carvalho Chehab 	tx[0] = 0x03;
19799a0bf528SMauro Carvalho Chehab 	tx[1] = 0x00;
19809a0bf528SMauro Carvalho Chehab 
19819a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(i2c_adap, msg, 2) == 2)
19829a0bf528SMauro Carvalho Chehab 		if (rx[0] == 0x01 && rx[1] == 0xb3) {
19839a0bf528SMauro Carvalho Chehab 			dprintk("-D-  DiB7000PC detected");
19849a0bf528SMauro Carvalho Chehab 			return 1;
19859a0bf528SMauro Carvalho Chehab 		}
19869a0bf528SMauro Carvalho Chehab 
19879a0bf528SMauro Carvalho Chehab 	msg[0].addr = msg[1].addr = 0x40;
19889a0bf528SMauro Carvalho Chehab 
19899a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(i2c_adap, msg, 2) == 2)
19909a0bf528SMauro Carvalho Chehab 		if (rx[0] == 0x01 && rx[1] == 0xb3) {
19919a0bf528SMauro Carvalho Chehab 			dprintk("-D-  DiB7000PC detected");
19929a0bf528SMauro Carvalho Chehab 			return 1;
19939a0bf528SMauro Carvalho Chehab 		}
19949a0bf528SMauro Carvalho Chehab 
19959a0bf528SMauro Carvalho Chehab 	dprintk("-D-  DiB7000PC not detected");
19969a0bf528SMauro Carvalho Chehab 
19979a0bf528SMauro Carvalho Chehab 	kfree(rx);
19989a0bf528SMauro Carvalho Chehab rx_memory_error:
19999a0bf528SMauro Carvalho Chehab 	kfree(tx);
20009a0bf528SMauro Carvalho Chehab 	return ret;
20019a0bf528SMauro Carvalho Chehab }
20029a0bf528SMauro Carvalho Chehab 
20038abe4a0aSMauro Carvalho Chehab static struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
20049a0bf528SMauro Carvalho Chehab {
20059a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *st = demod->demodulator_priv;
20069a0bf528SMauro Carvalho Chehab 	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
20079a0bf528SMauro Carvalho Chehab }
20089a0bf528SMauro Carvalho Chehab 
20098abe4a0aSMauro Carvalho Chehab static int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
20109a0bf528SMauro Carvalho Chehab {
20119a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
20129a0bf528SMauro Carvalho Chehab 	u16 val = dib7000p_read_word(state, 235) & 0xffef;
20139a0bf528SMauro Carvalho Chehab 	val |= (onoff & 0x1) << 4;
20149a0bf528SMauro Carvalho Chehab 	dprintk("PID filter enabled %d", onoff);
20159a0bf528SMauro Carvalho Chehab 	return dib7000p_write_word(state, 235, val);
20169a0bf528SMauro Carvalho Chehab }
20179a0bf528SMauro Carvalho Chehab 
20188abe4a0aSMauro Carvalho Chehab static int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
20199a0bf528SMauro Carvalho Chehab {
20209a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
20219a0bf528SMauro Carvalho Chehab 	dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
20229a0bf528SMauro Carvalho Chehab 	return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
20239a0bf528SMauro Carvalho Chehab }
20249a0bf528SMauro Carvalho Chehab 
20258abe4a0aSMauro Carvalho Chehab static int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
20269a0bf528SMauro Carvalho Chehab {
20279a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *dpst;
20289a0bf528SMauro Carvalho Chehab 	int k = 0;
20299a0bf528SMauro Carvalho Chehab 	u8 new_addr = 0;
20309a0bf528SMauro Carvalho Chehab 
20319a0bf528SMauro Carvalho Chehab 	dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
20329a0bf528SMauro Carvalho Chehab 	if (!dpst)
20339a0bf528SMauro Carvalho Chehab 		return -ENOMEM;
20349a0bf528SMauro Carvalho Chehab 
20359a0bf528SMauro Carvalho Chehab 	dpst->i2c_adap = i2c;
20369a0bf528SMauro Carvalho Chehab 	mutex_init(&dpst->i2c_buffer_lock);
20379a0bf528SMauro Carvalho Chehab 
20389a0bf528SMauro Carvalho Chehab 	for (k = no_of_demods - 1; k >= 0; k--) {
20399a0bf528SMauro Carvalho Chehab 		dpst->cfg = cfg[k];
20409a0bf528SMauro Carvalho Chehab 
20419a0bf528SMauro Carvalho Chehab 		/* designated i2c address */
20429a0bf528SMauro Carvalho Chehab 		if (cfg[k].default_i2c_addr != 0)
20439a0bf528SMauro Carvalho Chehab 			new_addr = cfg[k].default_i2c_addr + (k << 1);
20449a0bf528SMauro Carvalho Chehab 		else
20459a0bf528SMauro Carvalho Chehab 			new_addr = (0x40 + k) << 1;
20469a0bf528SMauro Carvalho Chehab 		dpst->i2c_addr = new_addr;
20479a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(dpst, 1287, 0x0003);	/* sram lead in, rdy */
20489a0bf528SMauro Carvalho Chehab 		if (dib7000p_identify(dpst) != 0) {
20499a0bf528SMauro Carvalho Chehab 			dpst->i2c_addr = default_addr;
20509a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(dpst, 1287, 0x0003);	/* sram lead in, rdy */
20519a0bf528SMauro Carvalho Chehab 			if (dib7000p_identify(dpst) != 0) {
20529a0bf528SMauro Carvalho Chehab 				dprintk("DiB7000P #%d: not identified\n", k);
20539a0bf528SMauro Carvalho Chehab 				kfree(dpst);
20549a0bf528SMauro Carvalho Chehab 				return -EIO;
20559a0bf528SMauro Carvalho Chehab 			}
20569a0bf528SMauro Carvalho Chehab 		}
20579a0bf528SMauro Carvalho Chehab 
20589a0bf528SMauro Carvalho Chehab 		/* start diversity to pull_down div_str - just for i2c-enumeration */
20599a0bf528SMauro Carvalho Chehab 		dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
20609a0bf528SMauro Carvalho Chehab 
20619a0bf528SMauro Carvalho Chehab 		/* set new i2c address and force divstart */
20629a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
20639a0bf528SMauro Carvalho Chehab 
20649a0bf528SMauro Carvalho Chehab 		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
20659a0bf528SMauro Carvalho Chehab 	}
20669a0bf528SMauro Carvalho Chehab 
20679a0bf528SMauro Carvalho Chehab 	for (k = 0; k < no_of_demods; k++) {
20689a0bf528SMauro Carvalho Chehab 		dpst->cfg = cfg[k];
20699a0bf528SMauro Carvalho Chehab 		if (cfg[k].default_i2c_addr != 0)
20709a0bf528SMauro Carvalho Chehab 			dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
20719a0bf528SMauro Carvalho Chehab 		else
20729a0bf528SMauro Carvalho Chehab 			dpst->i2c_addr = (0x40 + k) << 1;
20739a0bf528SMauro Carvalho Chehab 
20749a0bf528SMauro Carvalho Chehab 		// unforce divstr
20759a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
20769a0bf528SMauro Carvalho Chehab 
20779a0bf528SMauro Carvalho Chehab 		/* deactivate div - it was just for i2c-enumeration */
20789a0bf528SMauro Carvalho Chehab 		dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
20799a0bf528SMauro Carvalho Chehab 	}
20809a0bf528SMauro Carvalho Chehab 
20819a0bf528SMauro Carvalho Chehab 	kfree(dpst);
20829a0bf528SMauro Carvalho Chehab 	return 0;
20839a0bf528SMauro Carvalho Chehab }
20849a0bf528SMauro Carvalho Chehab 
20859a0bf528SMauro Carvalho Chehab static const s32 lut_1000ln_mant[] = {
20869a0bf528SMauro Carvalho Chehab 	6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
20879a0bf528SMauro Carvalho Chehab };
20889a0bf528SMauro Carvalho Chehab 
20899a0bf528SMauro Carvalho Chehab static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
20909a0bf528SMauro Carvalho Chehab {
20919a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
20929a0bf528SMauro Carvalho Chehab 	u32 tmp_val = 0, exp = 0, mant = 0;
20939a0bf528SMauro Carvalho Chehab 	s32 pow_i;
20949a0bf528SMauro Carvalho Chehab 	u16 buf[2];
20959a0bf528SMauro Carvalho Chehab 	u8 ix = 0;
20969a0bf528SMauro Carvalho Chehab 
20979a0bf528SMauro Carvalho Chehab 	buf[0] = dib7000p_read_word(state, 0x184);
20989a0bf528SMauro Carvalho Chehab 	buf[1] = dib7000p_read_word(state, 0x185);
20999a0bf528SMauro Carvalho Chehab 	pow_i = (buf[0] << 16) | buf[1];
21009a0bf528SMauro Carvalho Chehab 	dprintk("raw pow_i = %d", pow_i);
21019a0bf528SMauro Carvalho Chehab 
21029a0bf528SMauro Carvalho Chehab 	tmp_val = pow_i;
21039a0bf528SMauro Carvalho Chehab 	while (tmp_val >>= 1)
21049a0bf528SMauro Carvalho Chehab 		exp++;
21059a0bf528SMauro Carvalho Chehab 
21069a0bf528SMauro Carvalho Chehab 	mant = (pow_i * 1000 / (1 << exp));
21079a0bf528SMauro Carvalho Chehab 	dprintk(" mant = %d exp = %d", mant / 1000, exp);
21089a0bf528SMauro Carvalho Chehab 
21099a0bf528SMauro Carvalho Chehab 	ix = (u8) ((mant - 1000) / 100);	/* index of the LUT */
21109a0bf528SMauro Carvalho Chehab 	dprintk(" ix = %d", ix);
21119a0bf528SMauro Carvalho Chehab 
21129a0bf528SMauro Carvalho Chehab 	pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
21139a0bf528SMauro Carvalho Chehab 	pow_i = (pow_i << 8) / 1000;
21149a0bf528SMauro Carvalho Chehab 	dprintk(" pow_i = %d", pow_i);
21159a0bf528SMauro Carvalho Chehab 
21169a0bf528SMauro Carvalho Chehab 	return pow_i;
21179a0bf528SMauro Carvalho Chehab }
21189a0bf528SMauro Carvalho Chehab 
21199a0bf528SMauro Carvalho Chehab static int map_addr_to_serpar_number(struct i2c_msg *msg)
21209a0bf528SMauro Carvalho Chehab {
21219a0bf528SMauro Carvalho Chehab 	if ((msg->buf[0] <= 15))
21229a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 1;
21239a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 17)
21249a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 15;
21259a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 16)
21269a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 17;
21279a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 19)
21289a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 16;
21299a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
21309a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 3;
21319a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 28)
21329a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 23;
21339a0bf528SMauro Carvalho Chehab 	else
21349a0bf528SMauro Carvalho Chehab 		return -EINVAL;
21359a0bf528SMauro Carvalho Chehab 	return 0;
21369a0bf528SMauro Carvalho Chehab }
21379a0bf528SMauro Carvalho Chehab 
21389a0bf528SMauro Carvalho Chehab static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
21399a0bf528SMauro Carvalho Chehab {
21409a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
21419a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1;
21429a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
21439a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
21449a0bf528SMauro Carvalho Chehab 
21459a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
21469a0bf528SMauro Carvalho Chehab 		n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
21479a0bf528SMauro Carvalho Chehab 		i--;
21489a0bf528SMauro Carvalho Chehab 		if (i == 0)
21499a0bf528SMauro Carvalho Chehab 			dprintk("Tuner ITF: write busy (overflow)");
21509a0bf528SMauro Carvalho Chehab 	}
21519a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
21529a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
21539a0bf528SMauro Carvalho Chehab 
21549a0bf528SMauro Carvalho Chehab 	return num;
21559a0bf528SMauro Carvalho Chehab }
21569a0bf528SMauro Carvalho Chehab 
21579a0bf528SMauro Carvalho Chehab static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
21589a0bf528SMauro Carvalho Chehab {
21599a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
21609a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1, n_empty = 1;
21619a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
21629a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
21639a0bf528SMauro Carvalho Chehab 	u16 read_word;
21649a0bf528SMauro Carvalho Chehab 
21659a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
21669a0bf528SMauro Carvalho Chehab 		n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
21679a0bf528SMauro Carvalho Chehab 		i--;
21689a0bf528SMauro Carvalho Chehab 		if (i == 0)
21699a0bf528SMauro Carvalho Chehab 			dprintk("TunerITF: read busy (overflow)");
21709a0bf528SMauro Carvalho Chehab 	}
21719a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
21729a0bf528SMauro Carvalho Chehab 
21739a0bf528SMauro Carvalho Chehab 	i = 1000;
21749a0bf528SMauro Carvalho Chehab 	while (n_empty == 1 && i) {
21759a0bf528SMauro Carvalho Chehab 		n_empty = dib7000p_read_word(state, 1984) & 0x1;
21769a0bf528SMauro Carvalho Chehab 		i--;
21779a0bf528SMauro Carvalho Chehab 		if (i == 0)
21789a0bf528SMauro Carvalho Chehab 			dprintk("TunerITF: read busy (empty)");
21799a0bf528SMauro Carvalho Chehab 	}
21809a0bf528SMauro Carvalho Chehab 	read_word = dib7000p_read_word(state, 1987);
21819a0bf528SMauro Carvalho Chehab 	msg[1].buf[0] = (read_word >> 8) & 0xff;
21829a0bf528SMauro Carvalho Chehab 	msg[1].buf[1] = (read_word) & 0xff;
21839a0bf528SMauro Carvalho Chehab 
21849a0bf528SMauro Carvalho Chehab 	return num;
21859a0bf528SMauro Carvalho Chehab }
21869a0bf528SMauro Carvalho Chehab 
21879a0bf528SMauro Carvalho Chehab static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
21889a0bf528SMauro Carvalho Chehab {
21899a0bf528SMauro Carvalho Chehab 	if (map_addr_to_serpar_number(&msg[0]) == 0) {	/* else = Tuner regs to ignore : DIG_CFG, CTRL_RF_LT, PLL_CFG, PWM1_REG, ADCCLK, DIG_CFG_3; SLEEP_EN... */
21909a0bf528SMauro Carvalho Chehab 		if (num == 1) {	/* write */
21919a0bf528SMauro Carvalho Chehab 			return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
21929a0bf528SMauro Carvalho Chehab 		} else {	/* read */
21939a0bf528SMauro Carvalho Chehab 			return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
21949a0bf528SMauro Carvalho Chehab 		}
21959a0bf528SMauro Carvalho Chehab 	}
21969a0bf528SMauro Carvalho Chehab 	return num;
21979a0bf528SMauro Carvalho Chehab }
21989a0bf528SMauro Carvalho Chehab 
21999a0bf528SMauro Carvalho Chehab static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
22009a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num, u16 apb_address)
22019a0bf528SMauro Carvalho Chehab {
22029a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
22039a0bf528SMauro Carvalho Chehab 	u16 word;
22049a0bf528SMauro Carvalho Chehab 
22059a0bf528SMauro Carvalho Chehab 	if (num == 1) {		/* write */
22069a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
22079a0bf528SMauro Carvalho Chehab 	} else {
22089a0bf528SMauro Carvalho Chehab 		word = dib7000p_read_word(state, apb_address);
22099a0bf528SMauro Carvalho Chehab 		msg[1].buf[0] = (word >> 8) & 0xff;
22109a0bf528SMauro Carvalho Chehab 		msg[1].buf[1] = (word) & 0xff;
22119a0bf528SMauro Carvalho Chehab 	}
22129a0bf528SMauro Carvalho Chehab 
22139a0bf528SMauro Carvalho Chehab 	return num;
22149a0bf528SMauro Carvalho Chehab }
22159a0bf528SMauro Carvalho Chehab 
22169a0bf528SMauro Carvalho Chehab static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
22179a0bf528SMauro Carvalho Chehab {
22189a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
22199a0bf528SMauro Carvalho Chehab 
22209a0bf528SMauro Carvalho Chehab 	u16 apb_address = 0, word;
22219a0bf528SMauro Carvalho Chehab 	int i = 0;
22229a0bf528SMauro Carvalho Chehab 	switch (msg[0].buf[0]) {
22239a0bf528SMauro Carvalho Chehab 	case 0x12:
22249a0bf528SMauro Carvalho Chehab 		apb_address = 1920;
22259a0bf528SMauro Carvalho Chehab 		break;
22269a0bf528SMauro Carvalho Chehab 	case 0x14:
22279a0bf528SMauro Carvalho Chehab 		apb_address = 1921;
22289a0bf528SMauro Carvalho Chehab 		break;
22299a0bf528SMauro Carvalho Chehab 	case 0x24:
22309a0bf528SMauro Carvalho Chehab 		apb_address = 1922;
22319a0bf528SMauro Carvalho Chehab 		break;
22329a0bf528SMauro Carvalho Chehab 	case 0x1a:
22339a0bf528SMauro Carvalho Chehab 		apb_address = 1923;
22349a0bf528SMauro Carvalho Chehab 		break;
22359a0bf528SMauro Carvalho Chehab 	case 0x22:
22369a0bf528SMauro Carvalho Chehab 		apb_address = 1924;
22379a0bf528SMauro Carvalho Chehab 		break;
22389a0bf528SMauro Carvalho Chehab 	case 0x33:
22399a0bf528SMauro Carvalho Chehab 		apb_address = 1926;
22409a0bf528SMauro Carvalho Chehab 		break;
22419a0bf528SMauro Carvalho Chehab 	case 0x34:
22429a0bf528SMauro Carvalho Chehab 		apb_address = 1927;
22439a0bf528SMauro Carvalho Chehab 		break;
22449a0bf528SMauro Carvalho Chehab 	case 0x35:
22459a0bf528SMauro Carvalho Chehab 		apb_address = 1928;
22469a0bf528SMauro Carvalho Chehab 		break;
22479a0bf528SMauro Carvalho Chehab 	case 0x36:
22489a0bf528SMauro Carvalho Chehab 		apb_address = 1929;
22499a0bf528SMauro Carvalho Chehab 		break;
22509a0bf528SMauro Carvalho Chehab 	case 0x37:
22519a0bf528SMauro Carvalho Chehab 		apb_address = 1930;
22529a0bf528SMauro Carvalho Chehab 		break;
22539a0bf528SMauro Carvalho Chehab 	case 0x38:
22549a0bf528SMauro Carvalho Chehab 		apb_address = 1931;
22559a0bf528SMauro Carvalho Chehab 		break;
22569a0bf528SMauro Carvalho Chehab 	case 0x39:
22579a0bf528SMauro Carvalho Chehab 		apb_address = 1932;
22589a0bf528SMauro Carvalho Chehab 		break;
22599a0bf528SMauro Carvalho Chehab 	case 0x2a:
22609a0bf528SMauro Carvalho Chehab 		apb_address = 1935;
22619a0bf528SMauro Carvalho Chehab 		break;
22629a0bf528SMauro Carvalho Chehab 	case 0x2b:
22639a0bf528SMauro Carvalho Chehab 		apb_address = 1936;
22649a0bf528SMauro Carvalho Chehab 		break;
22659a0bf528SMauro Carvalho Chehab 	case 0x2c:
22669a0bf528SMauro Carvalho Chehab 		apb_address = 1937;
22679a0bf528SMauro Carvalho Chehab 		break;
22689a0bf528SMauro Carvalho Chehab 	case 0x2d:
22699a0bf528SMauro Carvalho Chehab 		apb_address = 1938;
22709a0bf528SMauro Carvalho Chehab 		break;
22719a0bf528SMauro Carvalho Chehab 	case 0x2e:
22729a0bf528SMauro Carvalho Chehab 		apb_address = 1939;
22739a0bf528SMauro Carvalho Chehab 		break;
22749a0bf528SMauro Carvalho Chehab 	case 0x2f:
22759a0bf528SMauro Carvalho Chehab 		apb_address = 1940;
22769a0bf528SMauro Carvalho Chehab 		break;
22779a0bf528SMauro Carvalho Chehab 	case 0x30:
22789a0bf528SMauro Carvalho Chehab 		apb_address = 1941;
22799a0bf528SMauro Carvalho Chehab 		break;
22809a0bf528SMauro Carvalho Chehab 	case 0x31:
22819a0bf528SMauro Carvalho Chehab 		apb_address = 1942;
22829a0bf528SMauro Carvalho Chehab 		break;
22839a0bf528SMauro Carvalho Chehab 	case 0x32:
22849a0bf528SMauro Carvalho Chehab 		apb_address = 1943;
22859a0bf528SMauro Carvalho Chehab 		break;
22869a0bf528SMauro Carvalho Chehab 	case 0x3e:
22879a0bf528SMauro Carvalho Chehab 		apb_address = 1944;
22889a0bf528SMauro Carvalho Chehab 		break;
22899a0bf528SMauro Carvalho Chehab 	case 0x3f:
22909a0bf528SMauro Carvalho Chehab 		apb_address = 1945;
22919a0bf528SMauro Carvalho Chehab 		break;
22929a0bf528SMauro Carvalho Chehab 	case 0x40:
22939a0bf528SMauro Carvalho Chehab 		apb_address = 1948;
22949a0bf528SMauro Carvalho Chehab 		break;
22959a0bf528SMauro Carvalho Chehab 	case 0x25:
22969a0bf528SMauro Carvalho Chehab 		apb_address = 914;
22979a0bf528SMauro Carvalho Chehab 		break;
22989a0bf528SMauro Carvalho Chehab 	case 0x26:
22999a0bf528SMauro Carvalho Chehab 		apb_address = 915;
23009a0bf528SMauro Carvalho Chehab 		break;
23019a0bf528SMauro Carvalho Chehab 	case 0x27:
23029a0bf528SMauro Carvalho Chehab 		apb_address = 917;
23039a0bf528SMauro Carvalho Chehab 		break;
23049a0bf528SMauro Carvalho Chehab 	case 0x28:
23059a0bf528SMauro Carvalho Chehab 		apb_address = 916;
23069a0bf528SMauro Carvalho Chehab 		break;
23079a0bf528SMauro Carvalho Chehab 	case 0x1d:
23089a0bf528SMauro Carvalho Chehab 		i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
23099a0bf528SMauro Carvalho Chehab 		word = dib7000p_read_word(state, 384 + i);
23109a0bf528SMauro Carvalho Chehab 		msg[1].buf[0] = (word >> 8) & 0xff;
23119a0bf528SMauro Carvalho Chehab 		msg[1].buf[1] = (word) & 0xff;
23129a0bf528SMauro Carvalho Chehab 		return num;
23139a0bf528SMauro Carvalho Chehab 	case 0x1f:
23149a0bf528SMauro Carvalho Chehab 		if (num == 1) {	/* write */
23159a0bf528SMauro Carvalho Chehab 			word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
23169a0bf528SMauro Carvalho Chehab 			word &= 0x3;
23179a0bf528SMauro Carvalho Chehab 			word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
23189a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 72, word);	/* Set the proper input */
23199a0bf528SMauro Carvalho Chehab 			return num;
23209a0bf528SMauro Carvalho Chehab 		}
23219a0bf528SMauro Carvalho Chehab 	}
23229a0bf528SMauro Carvalho Chehab 
23239a0bf528SMauro Carvalho Chehab 	if (apb_address != 0)	/* R/W acces via APB */
23249a0bf528SMauro Carvalho Chehab 		return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
23259a0bf528SMauro Carvalho Chehab 	else			/* R/W access via SERPAR  */
23269a0bf528SMauro Carvalho Chehab 		return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
23279a0bf528SMauro Carvalho Chehab 
23289a0bf528SMauro Carvalho Chehab 	return 0;
23299a0bf528SMauro Carvalho Chehab }
23309a0bf528SMauro Carvalho Chehab 
23319a0bf528SMauro Carvalho Chehab static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
23329a0bf528SMauro Carvalho Chehab {
23339a0bf528SMauro Carvalho Chehab 	return I2C_FUNC_I2C;
23349a0bf528SMauro Carvalho Chehab }
23359a0bf528SMauro Carvalho Chehab 
23369a0bf528SMauro Carvalho Chehab static struct i2c_algorithm dib7090_tuner_xfer_algo = {
23379a0bf528SMauro Carvalho Chehab 	.master_xfer = dib7090_tuner_xfer,
23389a0bf528SMauro Carvalho Chehab 	.functionality = dib7000p_i2c_func,
23399a0bf528SMauro Carvalho Chehab };
23409a0bf528SMauro Carvalho Chehab 
23418abe4a0aSMauro Carvalho Chehab static struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
23429a0bf528SMauro Carvalho Chehab {
23439a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *st = fe->demodulator_priv;
23449a0bf528SMauro Carvalho Chehab 	return &st->dib7090_tuner_adap;
23459a0bf528SMauro Carvalho Chehab }
23469a0bf528SMauro Carvalho Chehab 
23479a0bf528SMauro Carvalho Chehab static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
23489a0bf528SMauro Carvalho Chehab {
23499a0bf528SMauro Carvalho Chehab 	u16 reg;
23509a0bf528SMauro Carvalho Chehab 
23519a0bf528SMauro Carvalho Chehab 	/* drive host bus 2, 3, 4 */
23529a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
23539a0bf528SMauro Carvalho Chehab 	reg |= (drive << 12) | (drive << 6) | drive;
23549a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1798, reg);
23559a0bf528SMauro Carvalho Chehab 
23569a0bf528SMauro Carvalho Chehab 	/* drive host bus 5,6 */
23579a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
23589a0bf528SMauro Carvalho Chehab 	reg |= (drive << 8) | (drive << 2);
23599a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1799, reg);
23609a0bf528SMauro Carvalho Chehab 
23619a0bf528SMauro Carvalho Chehab 	/* drive host bus 7, 8, 9 */
23629a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
23639a0bf528SMauro Carvalho Chehab 	reg |= (drive << 12) | (drive << 6) | drive;
23649a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1800, reg);
23659a0bf528SMauro Carvalho Chehab 
23669a0bf528SMauro Carvalho Chehab 	/* drive host bus 10, 11 */
23679a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
23689a0bf528SMauro Carvalho Chehab 	reg |= (drive << 8) | (drive << 2);
23699a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1801, reg);
23709a0bf528SMauro Carvalho Chehab 
23719a0bf528SMauro Carvalho Chehab 	/* drive host bus 12, 13, 14 */
23729a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
23739a0bf528SMauro Carvalho Chehab 	reg |= (drive << 12) | (drive << 6) | drive;
23749a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1802, reg);
23759a0bf528SMauro Carvalho Chehab 
23769a0bf528SMauro Carvalho Chehab 	return 0;
23779a0bf528SMauro Carvalho Chehab }
23789a0bf528SMauro Carvalho Chehab 
23799a0bf528SMauro Carvalho Chehab static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
23809a0bf528SMauro Carvalho Chehab {
23819a0bf528SMauro Carvalho Chehab 	u32 quantif = 3;
23829a0bf528SMauro Carvalho Chehab 	u32 nom = (insertExtSynchro * P_Kin + syncSize);
23839a0bf528SMauro Carvalho Chehab 	u32 denom = P_Kout;
23849a0bf528SMauro Carvalho Chehab 	u32 syncFreq = ((nom << quantif) / denom);
23859a0bf528SMauro Carvalho Chehab 
23869a0bf528SMauro Carvalho Chehab 	if ((syncFreq & ((1 << quantif) - 1)) != 0)
23879a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif) + 1;
23889a0bf528SMauro Carvalho Chehab 	else
23899a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif);
23909a0bf528SMauro Carvalho Chehab 
23919a0bf528SMauro Carvalho Chehab 	if (syncFreq != 0)
23929a0bf528SMauro Carvalho Chehab 		syncFreq = syncFreq - 1;
23939a0bf528SMauro Carvalho Chehab 
23949a0bf528SMauro Carvalho Chehab 	return syncFreq;
23959a0bf528SMauro Carvalho Chehab }
23969a0bf528SMauro Carvalho Chehab 
23979a0bf528SMauro Carvalho Chehab static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
23989a0bf528SMauro Carvalho Chehab {
23999a0bf528SMauro Carvalho Chehab 	dprintk("Configure DibStream Tx");
24009a0bf528SMauro Carvalho Chehab 
24019a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1615, 1);
24029a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1603, P_Kin);
24039a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1605, P_Kout);
24049a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1606, insertExtSynchro);
24059a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1608, synchroMode);
24069a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
24079a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1610, syncWord & 0xffff);
24089a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1612, syncSize);
24099a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1615, 0);
24109a0bf528SMauro Carvalho Chehab 
24119a0bf528SMauro Carvalho Chehab 	return 0;
24129a0bf528SMauro Carvalho Chehab }
24139a0bf528SMauro Carvalho Chehab 
24149a0bf528SMauro Carvalho Chehab static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
24159a0bf528SMauro Carvalho Chehab 		u32 dataOutRate)
24169a0bf528SMauro Carvalho Chehab {
24179a0bf528SMauro Carvalho Chehab 	u32 syncFreq;
24189a0bf528SMauro Carvalho Chehab 
24199a0bf528SMauro Carvalho Chehab 	dprintk("Configure DibStream Rx");
24209a0bf528SMauro Carvalho Chehab 	if ((P_Kin != 0) && (P_Kout != 0)) {
24219a0bf528SMauro Carvalho Chehab 		syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
24229a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1542, syncFreq);
24239a0bf528SMauro Carvalho Chehab 	}
24249a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1554, 1);
24259a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1536, P_Kin);
24269a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1537, P_Kout);
24279a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1539, synchroMode);
24289a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
24299a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1541, syncWord & 0xffff);
24309a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1543, syncSize);
24319a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1544, dataOutRate);
24329a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1554, 0);
24339a0bf528SMauro Carvalho Chehab 
24349a0bf528SMauro Carvalho Chehab 	return 0;
24359a0bf528SMauro Carvalho Chehab }
24369a0bf528SMauro Carvalho Chehab 
24379a0bf528SMauro Carvalho Chehab static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
24389a0bf528SMauro Carvalho Chehab {
24399a0bf528SMauro Carvalho Chehab 	u16 reg_1287 = dib7000p_read_word(state, 1287);
24409a0bf528SMauro Carvalho Chehab 
24419a0bf528SMauro Carvalho Chehab 	switch (onoff) {
24429a0bf528SMauro Carvalho Chehab 	case 1:
24439a0bf528SMauro Carvalho Chehab 			reg_1287 &= ~(1<<7);
24449a0bf528SMauro Carvalho Chehab 			break;
24459a0bf528SMauro Carvalho Chehab 	case 0:
24469a0bf528SMauro Carvalho Chehab 			reg_1287 |= (1<<7);
24479a0bf528SMauro Carvalho Chehab 			break;
24489a0bf528SMauro Carvalho Chehab 	}
24499a0bf528SMauro Carvalho Chehab 
24509a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1287, reg_1287);
24519a0bf528SMauro Carvalho Chehab }
24529a0bf528SMauro Carvalho Chehab 
24539a0bf528SMauro Carvalho Chehab static void dib7090_configMpegMux(struct dib7000p_state *state,
24549a0bf528SMauro Carvalho Chehab 		u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
24559a0bf528SMauro Carvalho Chehab {
24569a0bf528SMauro Carvalho Chehab 	dprintk("Enable Mpeg mux");
24579a0bf528SMauro Carvalho Chehab 
24589a0bf528SMauro Carvalho Chehab 	dib7090_enMpegMux(state, 0);
24599a0bf528SMauro Carvalho Chehab 
24609a0bf528SMauro Carvalho Chehab 	/* If the input mode is MPEG do not divide the serial clock */
24619a0bf528SMauro Carvalho Chehab 	if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
24629a0bf528SMauro Carvalho Chehab 		enSerialClkDiv2 = 0;
24639a0bf528SMauro Carvalho Chehab 
24649a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
24659a0bf528SMauro Carvalho Chehab 			| ((enSerialMode & 0x1) << 1)
24669a0bf528SMauro Carvalho Chehab 			| (enSerialClkDiv2 & 0x1));
24679a0bf528SMauro Carvalho Chehab 
24689a0bf528SMauro Carvalho Chehab 	dib7090_enMpegMux(state, 1);
24699a0bf528SMauro Carvalho Chehab }
24709a0bf528SMauro Carvalho Chehab 
24719a0bf528SMauro Carvalho Chehab static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
24729a0bf528SMauro Carvalho Chehab {
24739a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
24749a0bf528SMauro Carvalho Chehab 
24759a0bf528SMauro Carvalho Chehab 	switch (mode) {
24769a0bf528SMauro Carvalho Chehab 	case MPEG_ON_DIBTX:
24779a0bf528SMauro Carvalho Chehab 			dprintk("SET MPEG ON DIBSTREAM TX");
24789a0bf528SMauro Carvalho Chehab 			dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
24799a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<9);
24809a0bf528SMauro Carvalho Chehab 			break;
24819a0bf528SMauro Carvalho Chehab 	case DIV_ON_DIBTX:
24829a0bf528SMauro Carvalho Chehab 			dprintk("SET DIV_OUT ON DIBSTREAM TX");
24839a0bf528SMauro Carvalho Chehab 			dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
24849a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<8);
24859a0bf528SMauro Carvalho Chehab 			break;
24869a0bf528SMauro Carvalho Chehab 	case ADC_ON_DIBTX:
24879a0bf528SMauro Carvalho Chehab 			dprintk("SET ADC_OUT ON DIBSTREAM TX");
24889a0bf528SMauro Carvalho Chehab 			dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
24899a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<7);
24909a0bf528SMauro Carvalho Chehab 			break;
24919a0bf528SMauro Carvalho Chehab 	default:
24929a0bf528SMauro Carvalho Chehab 			break;
24939a0bf528SMauro Carvalho Chehab 	}
24949a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1288, reg_1288);
24959a0bf528SMauro Carvalho Chehab }
24969a0bf528SMauro Carvalho Chehab 
24979a0bf528SMauro Carvalho Chehab static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
24989a0bf528SMauro Carvalho Chehab {
24999a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
25009a0bf528SMauro Carvalho Chehab 
25019a0bf528SMauro Carvalho Chehab 	switch (mode) {
25029a0bf528SMauro Carvalho Chehab 	case DEMOUT_ON_HOSTBUS:
25039a0bf528SMauro Carvalho Chehab 			dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
25049a0bf528SMauro Carvalho Chehab 			dib7090_enMpegMux(state, 0);
25059a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<6);
25069a0bf528SMauro Carvalho Chehab 			break;
25079a0bf528SMauro Carvalho Chehab 	case DIBTX_ON_HOSTBUS:
25089a0bf528SMauro Carvalho Chehab 			dprintk("SET DIBSTREAM TX ON HOST BUS");
25099a0bf528SMauro Carvalho Chehab 			dib7090_enMpegMux(state, 0);
25109a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<5);
25119a0bf528SMauro Carvalho Chehab 			break;
25129a0bf528SMauro Carvalho Chehab 	case MPEG_ON_HOSTBUS:
25139a0bf528SMauro Carvalho Chehab 			dprintk("SET MPEG MUX ON HOST BUS");
25149a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<4);
25159a0bf528SMauro Carvalho Chehab 			break;
25169a0bf528SMauro Carvalho Chehab 	default:
25179a0bf528SMauro Carvalho Chehab 			break;
25189a0bf528SMauro Carvalho Chehab 	}
25199a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1288, reg_1288);
25209a0bf528SMauro Carvalho Chehab }
25219a0bf528SMauro Carvalho Chehab 
25229a0bf528SMauro Carvalho Chehab int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
25239a0bf528SMauro Carvalho Chehab {
25249a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
25259a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
25269a0bf528SMauro Carvalho Chehab 
25279a0bf528SMauro Carvalho Chehab 	switch (onoff) {
25289a0bf528SMauro Carvalho Chehab 	case 0: /* only use the internal way - not the diversity input */
25299a0bf528SMauro Carvalho Chehab 			dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__);
25309a0bf528SMauro Carvalho Chehab 			dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
25319a0bf528SMauro Carvalho Chehab 
25329a0bf528SMauro Carvalho Chehab 			/* Do not divide the serial clock of MPEG MUX */
25339a0bf528SMauro Carvalho Chehab 			/* in SERIAL MODE in case input mode MPEG is used */
25349a0bf528SMauro Carvalho Chehab 			reg_1287 = dib7000p_read_word(state, 1287);
25359a0bf528SMauro Carvalho Chehab 			/* enSerialClkDiv2 == 1 ? */
25369a0bf528SMauro Carvalho Chehab 			if ((reg_1287 & 0x1) == 1) {
25379a0bf528SMauro Carvalho Chehab 				/* force enSerialClkDiv2 = 0 */
25389a0bf528SMauro Carvalho Chehab 				reg_1287 &= ~0x1;
25399a0bf528SMauro Carvalho Chehab 				dib7000p_write_word(state, 1287, reg_1287);
25409a0bf528SMauro Carvalho Chehab 			}
25419a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 1;
25429a0bf528SMauro Carvalho Chehab 			break;
25439a0bf528SMauro Carvalho Chehab 	case 1: /* both ways */
25449a0bf528SMauro Carvalho Chehab 	case 2: /* only the diversity input */
25459a0bf528SMauro Carvalho Chehab 			dprintk("%s ON : Enable diversity INPUT", __func__);
25469a0bf528SMauro Carvalho Chehab 			dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
25479a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 0;
25489a0bf528SMauro Carvalho Chehab 			break;
25499a0bf528SMauro Carvalho Chehab 	}
25509a0bf528SMauro Carvalho Chehab 
25519a0bf528SMauro Carvalho Chehab 	dib7000p_set_diversity_in(&state->demod, onoff);
25529a0bf528SMauro Carvalho Chehab 	return 0;
25539a0bf528SMauro Carvalho Chehab }
25549a0bf528SMauro Carvalho Chehab 
25559a0bf528SMauro Carvalho Chehab static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
25569a0bf528SMauro Carvalho Chehab {
25579a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
25589a0bf528SMauro Carvalho Chehab 
25599a0bf528SMauro Carvalho Chehab 	u16 outreg, smo_mode, fifo_threshold;
25609a0bf528SMauro Carvalho Chehab 	u8 prefer_mpeg_mux_use = 1;
25619a0bf528SMauro Carvalho Chehab 	int ret = 0;
25629a0bf528SMauro Carvalho Chehab 
25639a0bf528SMauro Carvalho Chehab 	dib7090_host_bus_drive(state, 1);
25649a0bf528SMauro Carvalho Chehab 
25659a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
25669a0bf528SMauro Carvalho Chehab 	smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
25679a0bf528SMauro Carvalho Chehab 	outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
25689a0bf528SMauro Carvalho Chehab 
25699a0bf528SMauro Carvalho Chehab 	switch (mode) {
25709a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:
25719a0bf528SMauro Carvalho Chehab 		outreg = 0;
25729a0bf528SMauro Carvalho Chehab 		break;
25739a0bf528SMauro Carvalho Chehab 
25749a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:
25759a0bf528SMauro Carvalho Chehab 		if (prefer_mpeg_mux_use) {
25769a0bf528SMauro Carvalho Chehab 			dprintk("setting output mode TS_SERIAL using Mpeg Mux");
25779a0bf528SMauro Carvalho Chehab 			dib7090_configMpegMux(state, 3, 1, 1);
25789a0bf528SMauro Carvalho Chehab 			dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
25799a0bf528SMauro Carvalho Chehab 		} else {/* Use Smooth block */
25809a0bf528SMauro Carvalho Chehab 			dprintk("setting output mode TS_SERIAL using Smooth bloc");
25819a0bf528SMauro Carvalho Chehab 			dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
25829a0bf528SMauro Carvalho Chehab 			outreg |= (2<<6) | (0 << 1);
25839a0bf528SMauro Carvalho Chehab 		}
25849a0bf528SMauro Carvalho Chehab 		break;
25859a0bf528SMauro Carvalho Chehab 
25869a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:
25879a0bf528SMauro Carvalho Chehab 		if (prefer_mpeg_mux_use) {
25889a0bf528SMauro Carvalho Chehab 			dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux");
25899a0bf528SMauro Carvalho Chehab 			dib7090_configMpegMux(state, 2, 0, 0);
25909a0bf528SMauro Carvalho Chehab 			dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
25919a0bf528SMauro Carvalho Chehab 		} else { /* Use Smooth block */
25929a0bf528SMauro Carvalho Chehab 			dprintk("setting output mode TS_PARALLEL_GATED using Smooth block");
25939a0bf528SMauro Carvalho Chehab 			dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
25949a0bf528SMauro Carvalho Chehab 			outreg |= (0<<6);
25959a0bf528SMauro Carvalho Chehab 		}
25969a0bf528SMauro Carvalho Chehab 		break;
25979a0bf528SMauro Carvalho Chehab 
25989a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK:	/* Using Smooth block only */
25999a0bf528SMauro Carvalho Chehab 		dprintk("setting output mode TS_PARALLEL_CONT using Smooth block");
26009a0bf528SMauro Carvalho Chehab 		dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
26019a0bf528SMauro Carvalho Chehab 		outreg |= (1<<6);
26029a0bf528SMauro Carvalho Chehab 		break;
26039a0bf528SMauro Carvalho Chehab 
26049a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:	/* Using Smooth block because not supported by new Mpeg Mux bloc */
26059a0bf528SMauro Carvalho Chehab 		dprintk("setting output mode TS_FIFO using Smooth block");
26069a0bf528SMauro Carvalho Chehab 		dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
26079a0bf528SMauro Carvalho Chehab 		outreg |= (5<<6);
26089a0bf528SMauro Carvalho Chehab 		smo_mode |= (3 << 1);
26099a0bf528SMauro Carvalho Chehab 		fifo_threshold = 512;
26109a0bf528SMauro Carvalho Chehab 		break;
26119a0bf528SMauro Carvalho Chehab 
26129a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
26139a0bf528SMauro Carvalho Chehab 		dprintk("setting output mode MODE_DIVERSITY");
26149a0bf528SMauro Carvalho Chehab 		dib7090_setDibTxMux(state, DIV_ON_DIBTX);
26159a0bf528SMauro Carvalho Chehab 		dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
26169a0bf528SMauro Carvalho Chehab 		break;
26179a0bf528SMauro Carvalho Chehab 
26189a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
26199a0bf528SMauro Carvalho Chehab 		dprintk("setting output mode MODE_ANALOG_ADC");
26209a0bf528SMauro Carvalho Chehab 		dib7090_setDibTxMux(state, ADC_ON_DIBTX);
26219a0bf528SMauro Carvalho Chehab 		dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
26229a0bf528SMauro Carvalho Chehab 		break;
26239a0bf528SMauro Carvalho Chehab 	}
26249a0bf528SMauro Carvalho Chehab 	if (mode != OUTMODE_HIGH_Z)
26259a0bf528SMauro Carvalho Chehab 		outreg |= (1 << 10);
26269a0bf528SMauro Carvalho Chehab 
26279a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
26289a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
26299a0bf528SMauro Carvalho Chehab 
26309a0bf528SMauro Carvalho Chehab 	ret |= dib7000p_write_word(state, 235, smo_mode);
26319a0bf528SMauro Carvalho Chehab 	ret |= dib7000p_write_word(state, 236, fifo_threshold);	/* synchronous fread */
26329a0bf528SMauro Carvalho Chehab 	ret |= dib7000p_write_word(state, 1286, outreg);
26339a0bf528SMauro Carvalho Chehab 
26349a0bf528SMauro Carvalho Chehab 	return ret;
26359a0bf528SMauro Carvalho Chehab }
26369a0bf528SMauro Carvalho Chehab 
26378abe4a0aSMauro Carvalho Chehab static int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
26389a0bf528SMauro Carvalho Chehab {
26399a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
26409a0bf528SMauro Carvalho Chehab 	u16 en_cur_state;
26419a0bf528SMauro Carvalho Chehab 
26429a0bf528SMauro Carvalho Chehab 	dprintk("sleep dib7090: %d", onoff);
26439a0bf528SMauro Carvalho Chehab 
26449a0bf528SMauro Carvalho Chehab 	en_cur_state = dib7000p_read_word(state, 1922);
26459a0bf528SMauro Carvalho Chehab 
26469a0bf528SMauro Carvalho Chehab 	if (en_cur_state > 0xff)
26479a0bf528SMauro Carvalho Chehab 		state->tuner_enable = en_cur_state;
26489a0bf528SMauro Carvalho Chehab 
26499a0bf528SMauro Carvalho Chehab 	if (onoff)
26509a0bf528SMauro Carvalho Chehab 		en_cur_state &= 0x00ff;
26519a0bf528SMauro Carvalho Chehab 	else {
26529a0bf528SMauro Carvalho Chehab 		if (state->tuner_enable != 0)
26539a0bf528SMauro Carvalho Chehab 			en_cur_state = state->tuner_enable;
26549a0bf528SMauro Carvalho Chehab 	}
26559a0bf528SMauro Carvalho Chehab 
26569a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1922, en_cur_state);
26579a0bf528SMauro Carvalho Chehab 
26589a0bf528SMauro Carvalho Chehab 	return 0;
26599a0bf528SMauro Carvalho Chehab }
26609a0bf528SMauro Carvalho Chehab 
26618abe4a0aSMauro Carvalho Chehab static int dib7090_get_adc_power(struct dvb_frontend *fe)
26629a0bf528SMauro Carvalho Chehab {
26639a0bf528SMauro Carvalho Chehab 	return dib7000p_get_adc_power(fe);
26649a0bf528SMauro Carvalho Chehab }
26659a0bf528SMauro Carvalho Chehab 
26668abe4a0aSMauro Carvalho Chehab static int dib7090_slave_reset(struct dvb_frontend *fe)
26679a0bf528SMauro Carvalho Chehab {
26689a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
26699a0bf528SMauro Carvalho Chehab 	u16 reg;
26709a0bf528SMauro Carvalho Chehab 
26719a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1794);
26729a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1794, reg | (4 << 12));
26739a0bf528SMauro Carvalho Chehab 
26749a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1032, 0xffff);
26759a0bf528SMauro Carvalho Chehab 	return 0;
26769a0bf528SMauro Carvalho Chehab }
26779a0bf528SMauro Carvalho Chehab 
26789a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops dib7000p_ops;
26798abe4a0aSMauro Carvalho Chehab static struct dvb_frontend *dib7000p_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
26809a0bf528SMauro Carvalho Chehab {
26819a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *demod;
26829a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *st;
26839a0bf528SMauro Carvalho Chehab 	st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
26849a0bf528SMauro Carvalho Chehab 	if (st == NULL)
26859a0bf528SMauro Carvalho Chehab 		return NULL;
26869a0bf528SMauro Carvalho Chehab 
26879a0bf528SMauro Carvalho Chehab 	memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
26889a0bf528SMauro Carvalho Chehab 	st->i2c_adap = i2c_adap;
26899a0bf528SMauro Carvalho Chehab 	st->i2c_addr = i2c_addr;
26909a0bf528SMauro Carvalho Chehab 	st->gpio_val = cfg->gpio_val;
26919a0bf528SMauro Carvalho Chehab 	st->gpio_dir = cfg->gpio_dir;
26929a0bf528SMauro Carvalho Chehab 
26939a0bf528SMauro Carvalho Chehab 	/* Ensure the output mode remains at the previous default if it's
26949a0bf528SMauro Carvalho Chehab 	 * not specifically set by the caller.
26959a0bf528SMauro Carvalho Chehab 	 */
26969a0bf528SMauro Carvalho Chehab 	if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
26979a0bf528SMauro Carvalho Chehab 		st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
26989a0bf528SMauro Carvalho Chehab 
26999a0bf528SMauro Carvalho Chehab 	demod = &st->demod;
27009a0bf528SMauro Carvalho Chehab 	demod->demodulator_priv = st;
27019a0bf528SMauro Carvalho Chehab 	memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
27029a0bf528SMauro Carvalho Chehab 	mutex_init(&st->i2c_buffer_lock);
27039a0bf528SMauro Carvalho Chehab 
27049a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1287, 0x0003);	/* sram lead in, rdy */
27059a0bf528SMauro Carvalho Chehab 
27069a0bf528SMauro Carvalho Chehab 	if (dib7000p_identify(st) != 0)
27079a0bf528SMauro Carvalho Chehab 		goto error;
27089a0bf528SMauro Carvalho Chehab 
27099a0bf528SMauro Carvalho Chehab 	st->version = dib7000p_read_word(st, 897);
27109a0bf528SMauro Carvalho Chehab 
27119a0bf528SMauro Carvalho Chehab 	/* FIXME: make sure the dev.parent field is initialized, or else
27129a0bf528SMauro Carvalho Chehab 	   request_firmware() will hit an OOPS (this should be moved somewhere
27139a0bf528SMauro Carvalho Chehab 	   more common) */
27149a0bf528SMauro Carvalho Chehab 	st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
27159a0bf528SMauro Carvalho Chehab 
27169a0bf528SMauro Carvalho Chehab 	dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
27179a0bf528SMauro Carvalho Chehab 
27189a0bf528SMauro Carvalho Chehab 	/* init 7090 tuner adapter */
27199a0bf528SMauro Carvalho Chehab 	strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
27209a0bf528SMauro Carvalho Chehab 	st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
27219a0bf528SMauro Carvalho Chehab 	st->dib7090_tuner_adap.algo_data = NULL;
27229a0bf528SMauro Carvalho Chehab 	st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
27239a0bf528SMauro Carvalho Chehab 	i2c_set_adapdata(&st->dib7090_tuner_adap, st);
27249a0bf528SMauro Carvalho Chehab 	i2c_add_adapter(&st->dib7090_tuner_adap);
27259a0bf528SMauro Carvalho Chehab 
27269a0bf528SMauro Carvalho Chehab 	dib7000p_demod_reset(st);
27279a0bf528SMauro Carvalho Chehab 
2728*041ad449SMauro Carvalho Chehab 	dib7000p_reset_stats(demod);
2729*041ad449SMauro Carvalho Chehab 
27309a0bf528SMauro Carvalho Chehab 	if (st->version == SOC7090) {
27319a0bf528SMauro Carvalho Chehab 		dib7090_set_output_mode(demod, st->cfg.output_mode);
27329a0bf528SMauro Carvalho Chehab 		dib7090_set_diversity_in(demod, 0);
27339a0bf528SMauro Carvalho Chehab 	}
27349a0bf528SMauro Carvalho Chehab 
27359a0bf528SMauro Carvalho Chehab 	return demod;
27369a0bf528SMauro Carvalho Chehab 
27379a0bf528SMauro Carvalho Chehab error:
27389a0bf528SMauro Carvalho Chehab 	kfree(st);
27399a0bf528SMauro Carvalho Chehab 	return NULL;
27409a0bf528SMauro Carvalho Chehab }
27418abe4a0aSMauro Carvalho Chehab 
27428abe4a0aSMauro Carvalho Chehab void *dib7000p_attach(struct dib7000p_ops *ops)
27438abe4a0aSMauro Carvalho Chehab {
27448abe4a0aSMauro Carvalho Chehab 	if (!ops)
27458abe4a0aSMauro Carvalho Chehab 		return NULL;
27468abe4a0aSMauro Carvalho Chehab 
27478abe4a0aSMauro Carvalho Chehab 	ops->slave_reset = dib7090_slave_reset;
27488abe4a0aSMauro Carvalho Chehab 	ops->get_adc_power = dib7090_get_adc_power;
27498abe4a0aSMauro Carvalho Chehab 	ops->dib7000pc_detection = dib7000pc_detection;
27508abe4a0aSMauro Carvalho Chehab 	ops->get_i2c_tuner = dib7090_get_i2c_tuner;
27518abe4a0aSMauro Carvalho Chehab 	ops->tuner_sleep = dib7090_tuner_sleep;
27528abe4a0aSMauro Carvalho Chehab 	ops->init = dib7000p_init;
27538abe4a0aSMauro Carvalho Chehab 	ops->set_agc1_min = dib7000p_set_agc1_min;
27548abe4a0aSMauro Carvalho Chehab 	ops->set_gpio = dib7000p_set_gpio;
27558abe4a0aSMauro Carvalho Chehab 	ops->i2c_enumeration = dib7000p_i2c_enumeration;
27568abe4a0aSMauro Carvalho Chehab 	ops->pid_filter = dib7000p_pid_filter;
27578abe4a0aSMauro Carvalho Chehab 	ops->pid_filter_ctrl = dib7000p_pid_filter_ctrl;
27588abe4a0aSMauro Carvalho Chehab 	ops->get_i2c_master = dib7000p_get_i2c_master;
27598abe4a0aSMauro Carvalho Chehab 	ops->update_pll = dib7000p_update_pll;
27608abe4a0aSMauro Carvalho Chehab 	ops->ctrl_timf = dib7000p_ctrl_timf;
27618abe4a0aSMauro Carvalho Chehab 	ops->get_agc_values = dib7000p_get_agc_values;
27628abe4a0aSMauro Carvalho Chehab 	ops->set_wbd_ref = dib7000p_set_wbd_ref;
27638abe4a0aSMauro Carvalho Chehab 
27648abe4a0aSMauro Carvalho Chehab 	return ops;
27658abe4a0aSMauro Carvalho Chehab }
27668abe4a0aSMauro Carvalho Chehab EXPORT_SYMBOL(dib7000p_attach);
27679a0bf528SMauro Carvalho Chehab 
27689a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops dib7000p_ops = {
27699a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_DVBT },
27709a0bf528SMauro Carvalho Chehab 	.info = {
27719a0bf528SMauro Carvalho Chehab 		 .name = "DiBcom 7000PC",
27729a0bf528SMauro Carvalho Chehab 		 .frequency_min = 44250000,
27739a0bf528SMauro Carvalho Chehab 		 .frequency_max = 867250000,
27749a0bf528SMauro Carvalho Chehab 		 .frequency_stepsize = 62500,
27759a0bf528SMauro Carvalho Chehab 		 .caps = FE_CAN_INVERSION_AUTO |
27769a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
27779a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
27789a0bf528SMauro Carvalho Chehab 		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
27799a0bf528SMauro Carvalho Chehab 		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
27809a0bf528SMauro Carvalho Chehab 		 },
27819a0bf528SMauro Carvalho Chehab 
27829a0bf528SMauro Carvalho Chehab 	.release = dib7000p_release,
27839a0bf528SMauro Carvalho Chehab 
27849a0bf528SMauro Carvalho Chehab 	.init = dib7000p_wakeup,
27859a0bf528SMauro Carvalho Chehab 	.sleep = dib7000p_sleep,
27869a0bf528SMauro Carvalho Chehab 
27879a0bf528SMauro Carvalho Chehab 	.set_frontend = dib7000p_set_frontend,
27889a0bf528SMauro Carvalho Chehab 	.get_tune_settings = dib7000p_fe_get_tune_settings,
27899a0bf528SMauro Carvalho Chehab 	.get_frontend = dib7000p_get_frontend,
27909a0bf528SMauro Carvalho Chehab 
27919a0bf528SMauro Carvalho Chehab 	.read_status = dib7000p_read_status,
27929a0bf528SMauro Carvalho Chehab 	.read_ber = dib7000p_read_ber,
27939a0bf528SMauro Carvalho Chehab 	.read_signal_strength = dib7000p_read_signal_strength,
27949a0bf528SMauro Carvalho Chehab 	.read_snr = dib7000p_read_snr,
27959a0bf528SMauro Carvalho Chehab 	.read_ucblocks = dib7000p_read_unc_blocks,
27969a0bf528SMauro Carvalho Chehab };
27979a0bf528SMauro Carvalho Chehab 
27989a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
27999a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
28009a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
28019a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
2802