xref: /openbmc/linux/drivers/media/dvb-frontends/dib7000p.c (revision 5332b6263742cd75963eccdea9e3af4a464c2999)
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  */
105a0e2a4eSMauro Carvalho Chehab 
115a0e2a4eSMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
125a0e2a4eSMauro Carvalho Chehab 
139a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
149a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
159a0bf528SMauro Carvalho Chehab #include <linux/i2c.h>
169a0bf528SMauro Carvalho Chehab #include <linux/mutex.h>
17041ad449SMauro Carvalho Chehab #include <asm/div64.h>
189a0bf528SMauro Carvalho Chehab 
199a0bf528SMauro Carvalho Chehab #include "dvb_math.h"
209a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h"
219a0bf528SMauro Carvalho Chehab 
229a0bf528SMauro Carvalho Chehab #include "dib7000p.h"
239a0bf528SMauro Carvalho Chehab 
249a0bf528SMauro Carvalho Chehab static int debug;
259a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
269a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
279a0bf528SMauro Carvalho Chehab 
289a0bf528SMauro Carvalho Chehab static int buggy_sfn_workaround;
299a0bf528SMauro Carvalho Chehab module_param(buggy_sfn_workaround, int, 0644);
309a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
319a0bf528SMauro Carvalho Chehab 
325a0e2a4eSMauro Carvalho Chehab #define dprintk(fmt, arg...) do {					\
335a0e2a4eSMauro Carvalho Chehab 	if (debug)							\
345a0e2a4eSMauro Carvalho Chehab 		printk(KERN_DEBUG pr_fmt("%s: " fmt),			\
355a0e2a4eSMauro Carvalho Chehab 		       __func__, ##arg);				\
365a0e2a4eSMauro Carvalho Chehab } while (0)
379a0bf528SMauro Carvalho Chehab 
389a0bf528SMauro Carvalho Chehab struct i2c_device {
399a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *i2c_adap;
409a0bf528SMauro Carvalho Chehab 	u8 i2c_addr;
419a0bf528SMauro Carvalho Chehab };
429a0bf528SMauro Carvalho Chehab 
439a0bf528SMauro Carvalho Chehab struct dib7000p_state {
449a0bf528SMauro Carvalho Chehab 	struct dvb_frontend demod;
459a0bf528SMauro Carvalho Chehab 	struct dib7000p_config cfg;
469a0bf528SMauro Carvalho Chehab 
479a0bf528SMauro Carvalho Chehab 	u8 i2c_addr;
489a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *i2c_adap;
499a0bf528SMauro Carvalho Chehab 
509a0bf528SMauro Carvalho Chehab 	struct dibx000_i2c_master i2c_master;
519a0bf528SMauro Carvalho Chehab 
529a0bf528SMauro Carvalho Chehab 	u16 wbd_ref;
539a0bf528SMauro Carvalho Chehab 
549a0bf528SMauro Carvalho Chehab 	u8 current_band;
559a0bf528SMauro Carvalho Chehab 	u32 current_bandwidth;
569a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *current_agc;
579a0bf528SMauro Carvalho Chehab 	u32 timf;
589a0bf528SMauro Carvalho Chehab 
599a0bf528SMauro Carvalho Chehab 	u8 div_force_off:1;
609a0bf528SMauro Carvalho Chehab 	u8 div_state:1;
619a0bf528SMauro Carvalho Chehab 	u16 div_sync_wait;
629a0bf528SMauro Carvalho Chehab 
639a0bf528SMauro Carvalho Chehab 	u8 agc_state;
649a0bf528SMauro Carvalho Chehab 
659a0bf528SMauro Carvalho Chehab 	u16 gpio_dir;
669a0bf528SMauro Carvalho Chehab 	u16 gpio_val;
679a0bf528SMauro Carvalho Chehab 
689a0bf528SMauro Carvalho Chehab 	u8 sfn_workaround_active:1;
699a0bf528SMauro Carvalho Chehab 
709a0bf528SMauro Carvalho Chehab #define SOC7090 0x7090
719a0bf528SMauro Carvalho Chehab 	u16 version;
729a0bf528SMauro Carvalho Chehab 
739a0bf528SMauro Carvalho Chehab 	u16 tuner_enable;
749a0bf528SMauro Carvalho Chehab 	struct i2c_adapter dib7090_tuner_adap;
759a0bf528SMauro Carvalho Chehab 
769a0bf528SMauro Carvalho Chehab 	/* for the I2C transfer */
779a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2];
789a0bf528SMauro Carvalho Chehab 	u8 i2c_write_buffer[4];
799a0bf528SMauro Carvalho Chehab 	u8 i2c_read_buffer[2];
809a0bf528SMauro Carvalho Chehab 	struct mutex i2c_buffer_lock;
819a0bf528SMauro Carvalho Chehab 
829a0bf528SMauro Carvalho Chehab 	u8 input_mode_mpeg;
83041ad449SMauro Carvalho Chehab 
84041ad449SMauro Carvalho Chehab 	/* for DVBv5 stats */
85041ad449SMauro Carvalho Chehab 	s64 old_ucb;
86041ad449SMauro Carvalho Chehab 	unsigned long per_jiffies_stats;
87041ad449SMauro Carvalho Chehab 	unsigned long ber_jiffies_stats;
88041ad449SMauro Carvalho Chehab 	unsigned long get_stats_time;
899a0bf528SMauro Carvalho Chehab };
909a0bf528SMauro Carvalho Chehab 
919a0bf528SMauro Carvalho Chehab enum dib7000p_power_mode {
929a0bf528SMauro Carvalho Chehab 	DIB7000P_POWER_ALL = 0,
939a0bf528SMauro Carvalho Chehab 	DIB7000P_POWER_ANALOG_ADC,
949a0bf528SMauro Carvalho Chehab 	DIB7000P_POWER_INTERFACE_ONLY,
959a0bf528SMauro Carvalho Chehab };
969a0bf528SMauro Carvalho Chehab 
979a0bf528SMauro Carvalho Chehab /* dib7090 specific fonctions */
989a0bf528SMauro Carvalho Chehab static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
999a0bf528SMauro Carvalho Chehab static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
1009a0bf528SMauro Carvalho Chehab static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode);
1019a0bf528SMauro Carvalho Chehab static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode);
1029a0bf528SMauro Carvalho Chehab 
1039a0bf528SMauro Carvalho Chehab static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
1049a0bf528SMauro Carvalho Chehab {
1059a0bf528SMauro Carvalho Chehab 	u16 ret;
1069a0bf528SMauro Carvalho Chehab 
1079a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
1085a0e2a4eSMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
1099a0bf528SMauro Carvalho Chehab 		return 0;
1109a0bf528SMauro Carvalho Chehab 	}
1119a0bf528SMauro Carvalho Chehab 
1129a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = reg >> 8;
1139a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
1149a0bf528SMauro Carvalho Chehab 
1159a0bf528SMauro Carvalho Chehab 	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
1169a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c_addr >> 1;
1179a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
1189a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
1199a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 2;
1209a0bf528SMauro Carvalho Chehab 	state->msg[1].addr = state->i2c_addr >> 1;
1219a0bf528SMauro Carvalho Chehab 	state->msg[1].flags = I2C_M_RD;
1229a0bf528SMauro Carvalho Chehab 	state->msg[1].buf = state->i2c_read_buffer;
1239a0bf528SMauro Carvalho Chehab 	state->msg[1].len = 2;
1249a0bf528SMauro Carvalho Chehab 
1259a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
1265a0e2a4eSMauro Carvalho Chehab 		dprintk("i2c read error on %d\n", reg);
1279a0bf528SMauro Carvalho Chehab 
1289a0bf528SMauro Carvalho Chehab 	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
1299a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
1309a0bf528SMauro Carvalho Chehab 	return ret;
1319a0bf528SMauro Carvalho Chehab }
1329a0bf528SMauro Carvalho Chehab 
1339a0bf528SMauro Carvalho Chehab static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
1349a0bf528SMauro Carvalho Chehab {
1359a0bf528SMauro Carvalho Chehab 	int ret;
1369a0bf528SMauro Carvalho Chehab 
1379a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
1385a0e2a4eSMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
1399a0bf528SMauro Carvalho Chehab 		return -EINVAL;
1409a0bf528SMauro Carvalho Chehab 	}
1419a0bf528SMauro Carvalho Chehab 
1429a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
1439a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
1449a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
1459a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[3] = val & 0xff;
1469a0bf528SMauro Carvalho Chehab 
1479a0bf528SMauro Carvalho Chehab 	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
1489a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c_addr >> 1;
1499a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
1509a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
1519a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 4;
1529a0bf528SMauro Carvalho Chehab 
1539a0bf528SMauro Carvalho Chehab 	ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
1549a0bf528SMauro Carvalho Chehab 			-EREMOTEIO : 0);
1559a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
1569a0bf528SMauro Carvalho Chehab 	return ret;
1579a0bf528SMauro Carvalho Chehab }
1589a0bf528SMauro Carvalho Chehab 
1599a0bf528SMauro Carvalho Chehab static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
1609a0bf528SMauro Carvalho Chehab {
1619a0bf528SMauro Carvalho Chehab 	u16 l = 0, r, *n;
1629a0bf528SMauro Carvalho Chehab 	n = buf;
1639a0bf528SMauro Carvalho Chehab 	l = *n++;
1649a0bf528SMauro Carvalho Chehab 	while (l) {
1659a0bf528SMauro Carvalho Chehab 		r = *n++;
1669a0bf528SMauro Carvalho Chehab 
1679a0bf528SMauro Carvalho Chehab 		do {
1689a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, r, *n++);
1699a0bf528SMauro Carvalho Chehab 			r++;
1709a0bf528SMauro Carvalho Chehab 		} while (--l);
1719a0bf528SMauro Carvalho Chehab 		l = *n++;
1729a0bf528SMauro Carvalho Chehab 	}
1739a0bf528SMauro Carvalho Chehab }
1749a0bf528SMauro Carvalho Chehab 
1759a0bf528SMauro Carvalho Chehab static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
1769a0bf528SMauro Carvalho Chehab {
1779a0bf528SMauro Carvalho Chehab 	int ret = 0;
1789a0bf528SMauro Carvalho Chehab 	u16 outreg, fifo_threshold, smo_mode;
1799a0bf528SMauro Carvalho Chehab 
1809a0bf528SMauro Carvalho Chehab 	outreg = 0;
1819a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
1829a0bf528SMauro Carvalho Chehab 	smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
1839a0bf528SMauro Carvalho Chehab 
1845a0e2a4eSMauro Carvalho Chehab 	dprintk("setting output mode for demod %p to %d\n", &state->demod, mode);
1859a0bf528SMauro Carvalho Chehab 
1869a0bf528SMauro Carvalho Chehab 	switch (mode) {
1879a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:
1889a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10);	/* 0x0400 */
1899a0bf528SMauro Carvalho Chehab 		break;
1909a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK:
1919a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (1 << 6);	/* 0x0440 */
1929a0bf528SMauro Carvalho Chehab 		break;
1939a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:
1949a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (2 << 6) | (0 << 1);	/* 0x0480 */
1959a0bf528SMauro Carvalho Chehab 		break;
1969a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
1979a0bf528SMauro Carvalho Chehab 		if (state->cfg.hostbus_diversity)
1989a0bf528SMauro Carvalho Chehab 			outreg = (1 << 10) | (4 << 6);	/* 0x0500 */
1999a0bf528SMauro Carvalho Chehab 		else
2009a0bf528SMauro Carvalho Chehab 			outreg = (1 << 11);
2019a0bf528SMauro Carvalho Chehab 		break;
2029a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:
2039a0bf528SMauro Carvalho Chehab 		smo_mode |= (3 << 1);
2049a0bf528SMauro Carvalho Chehab 		fifo_threshold = 512;
2059a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (5 << 6);
2069a0bf528SMauro Carvalho Chehab 		break;
2079a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
2089a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (3 << 6);
2099a0bf528SMauro Carvalho Chehab 		break;
2109a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:
2119a0bf528SMauro Carvalho Chehab 		outreg = 0;
2129a0bf528SMauro Carvalho Chehab 		break;
2139a0bf528SMauro Carvalho Chehab 	default:
2145a0e2a4eSMauro Carvalho Chehab 		dprintk("Unhandled output_mode passed to be set for demod %p\n", &state->demod);
2159a0bf528SMauro Carvalho Chehab 		break;
2169a0bf528SMauro Carvalho Chehab 	}
2179a0bf528SMauro Carvalho Chehab 
2189a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
2199a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
2209a0bf528SMauro Carvalho Chehab 
2219a0bf528SMauro Carvalho Chehab 	ret |= dib7000p_write_word(state, 235, smo_mode);
2229a0bf528SMauro Carvalho Chehab 	ret |= dib7000p_write_word(state, 236, fifo_threshold);	/* synchronous fread */
2239a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090)
2249a0bf528SMauro Carvalho Chehab 		ret |= dib7000p_write_word(state, 1286, outreg);	/* P_Div_active */
2259a0bf528SMauro Carvalho Chehab 
2269a0bf528SMauro Carvalho Chehab 	return ret;
2279a0bf528SMauro Carvalho Chehab }
2289a0bf528SMauro Carvalho Chehab 
2299a0bf528SMauro Carvalho Chehab static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
2309a0bf528SMauro Carvalho Chehab {
2319a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
2329a0bf528SMauro Carvalho Chehab 
2339a0bf528SMauro Carvalho Chehab 	if (state->div_force_off) {
2345a0e2a4eSMauro Carvalho Chehab 		dprintk("diversity combination deactivated - forced by COFDM parameters\n");
2359a0bf528SMauro Carvalho Chehab 		onoff = 0;
2369a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 207, 0);
2379a0bf528SMauro Carvalho Chehab 	} else
2389a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
2399a0bf528SMauro Carvalho Chehab 
2409a0bf528SMauro Carvalho Chehab 	state->div_state = (u8) onoff;
2419a0bf528SMauro Carvalho Chehab 
2429a0bf528SMauro Carvalho Chehab 	if (onoff) {
2439a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 204, 6);
2449a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 205, 16);
2459a0bf528SMauro Carvalho Chehab 		/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
2469a0bf528SMauro Carvalho Chehab 	} else {
2479a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 204, 1);
2489a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 205, 0);
2499a0bf528SMauro Carvalho Chehab 	}
2509a0bf528SMauro Carvalho Chehab 
2519a0bf528SMauro Carvalho Chehab 	return 0;
2529a0bf528SMauro Carvalho Chehab }
2539a0bf528SMauro Carvalho Chehab 
2549a0bf528SMauro Carvalho Chehab static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
2559a0bf528SMauro Carvalho Chehab {
2569a0bf528SMauro Carvalho Chehab 	/* by default everything is powered off */
2579a0bf528SMauro Carvalho Chehab 	u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
2589a0bf528SMauro Carvalho Chehab 
2599a0bf528SMauro Carvalho Chehab 	/* now, depending on the requested mode, we power on */
2609a0bf528SMauro Carvalho Chehab 	switch (mode) {
2619a0bf528SMauro Carvalho Chehab 		/* power up everything in the demod */
2629a0bf528SMauro Carvalho Chehab 	case DIB7000P_POWER_ALL:
2639a0bf528SMauro Carvalho Chehab 		reg_774 = 0x0000;
2649a0bf528SMauro Carvalho Chehab 		reg_775 = 0x0000;
2659a0bf528SMauro Carvalho Chehab 		reg_776 = 0x0;
2669a0bf528SMauro Carvalho Chehab 		reg_899 = 0x0;
2679a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090)
2689a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x001f;
2699a0bf528SMauro Carvalho Chehab 		else
2709a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x01ff;
2719a0bf528SMauro Carvalho Chehab 		break;
2729a0bf528SMauro Carvalho Chehab 
2739a0bf528SMauro Carvalho Chehab 	case DIB7000P_POWER_ANALOG_ADC:
2749a0bf528SMauro Carvalho Chehab 		/* dem, cfg, iqc, sad, agc */
2759a0bf528SMauro Carvalho Chehab 		reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
2769a0bf528SMauro Carvalho Chehab 		/* nud */
2779a0bf528SMauro Carvalho Chehab 		reg_776 &= ~((1 << 0));
2789a0bf528SMauro Carvalho Chehab 		/* Dout */
2799a0bf528SMauro Carvalho Chehab 		if (state->version != SOC7090)
2809a0bf528SMauro Carvalho Chehab 			reg_1280 &= ~((1 << 11));
2819a0bf528SMauro Carvalho Chehab 		reg_1280 &= ~(1 << 6);
2829a0bf528SMauro Carvalho Chehab 		/* fall through wanted to enable the interfaces */
2839a0bf528SMauro Carvalho Chehab 
2849a0bf528SMauro Carvalho Chehab 		/* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
2859a0bf528SMauro Carvalho Chehab 	case DIB7000P_POWER_INTERFACE_ONLY:	/* TODO power up either SDIO or I2C */
2869a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090)
2879a0bf528SMauro Carvalho Chehab 			reg_1280 &= ~((1 << 7) | (1 << 5));
2889a0bf528SMauro Carvalho Chehab 		else
2899a0bf528SMauro Carvalho Chehab 			reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
2909a0bf528SMauro Carvalho Chehab 		break;
2919a0bf528SMauro Carvalho Chehab 
2929a0bf528SMauro Carvalho Chehab /* TODO following stuff is just converted from the dib7000-driver - check when is used what */
2939a0bf528SMauro Carvalho Chehab 	}
2949a0bf528SMauro Carvalho Chehab 
2959a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 774, reg_774);
2969a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 775, reg_775);
2979a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 776, reg_776);
2989a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1280, reg_1280);
2999a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090)
3009a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 899, reg_899);
3019a0bf528SMauro Carvalho Chehab 
3029a0bf528SMauro Carvalho Chehab 	return 0;
3039a0bf528SMauro Carvalho Chehab }
3049a0bf528SMauro Carvalho Chehab 
3059a0bf528SMauro Carvalho Chehab static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
3069a0bf528SMauro Carvalho Chehab {
3079a0bf528SMauro Carvalho Chehab 	u16 reg_908 = 0, reg_909 = 0;
3089a0bf528SMauro Carvalho Chehab 	u16 reg;
3099a0bf528SMauro Carvalho Chehab 
3109a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090) {
3119a0bf528SMauro Carvalho Chehab 		reg_908 = dib7000p_read_word(state, 908);
3129a0bf528SMauro Carvalho Chehab 		reg_909 = dib7000p_read_word(state, 909);
3139a0bf528SMauro Carvalho Chehab 	}
3149a0bf528SMauro Carvalho Chehab 
3159a0bf528SMauro Carvalho Chehab 	switch (no) {
3169a0bf528SMauro Carvalho Chehab 	case DIBX000_SLOW_ADC_ON:
3179a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090) {
3189a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 1925);
3199a0bf528SMauro Carvalho Chehab 
3209a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2));	/* en_slowAdc = 1 & reset_sladc = 1 */
3219a0bf528SMauro Carvalho Chehab 
3229a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 1925);	/* read acces to make it works... strange ... */
3239a0bf528SMauro Carvalho Chehab 			msleep(200);
3249a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 1925, reg & ~(1 << 4));	/* en_slowAdc = 1 & reset_sladc = 0 */
3259a0bf528SMauro Carvalho Chehab 
3269a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
3279a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524);	/* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
3289a0bf528SMauro Carvalho Chehab 		} else {
3299a0bf528SMauro Carvalho Chehab 			reg_909 |= (1 << 1) | (1 << 0);
3309a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 909, reg_909);
3319a0bf528SMauro Carvalho Chehab 			reg_909 &= ~(1 << 1);
3329a0bf528SMauro Carvalho Chehab 		}
3339a0bf528SMauro Carvalho Chehab 		break;
3349a0bf528SMauro Carvalho Chehab 
3359a0bf528SMauro Carvalho Chehab 	case DIBX000_SLOW_ADC_OFF:
3369a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090) {
3379a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 1925);
3389a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4));	/* reset_sladc = 1 en_slowAdc = 0 */
3399a0bf528SMauro Carvalho Chehab 		} else
3409a0bf528SMauro Carvalho Chehab 			reg_909 |= (1 << 1) | (1 << 0);
3419a0bf528SMauro Carvalho Chehab 		break;
3429a0bf528SMauro Carvalho Chehab 
3439a0bf528SMauro Carvalho Chehab 	case DIBX000_ADC_ON:
3449a0bf528SMauro Carvalho Chehab 		reg_908 &= 0x0fff;
3459a0bf528SMauro Carvalho Chehab 		reg_909 &= 0x0003;
3469a0bf528SMauro Carvalho Chehab 		break;
3479a0bf528SMauro Carvalho Chehab 
3489a0bf528SMauro Carvalho Chehab 	case DIBX000_ADC_OFF:
3499a0bf528SMauro Carvalho Chehab 		reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
3509a0bf528SMauro Carvalho Chehab 		reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
3519a0bf528SMauro Carvalho Chehab 		break;
3529a0bf528SMauro Carvalho Chehab 
3539a0bf528SMauro Carvalho Chehab 	case DIBX000_VBG_ENABLE:
3549a0bf528SMauro Carvalho Chehab 		reg_908 &= ~(1 << 15);
3559a0bf528SMauro Carvalho Chehab 		break;
3569a0bf528SMauro Carvalho Chehab 
3579a0bf528SMauro Carvalho Chehab 	case DIBX000_VBG_DISABLE:
3589a0bf528SMauro Carvalho Chehab 		reg_908 |= (1 << 15);
3599a0bf528SMauro Carvalho Chehab 		break;
3609a0bf528SMauro Carvalho Chehab 
3619a0bf528SMauro Carvalho Chehab 	default:
3629a0bf528SMauro Carvalho Chehab 		break;
3639a0bf528SMauro Carvalho Chehab 	}
3649a0bf528SMauro Carvalho Chehab 
3659a0bf528SMauro Carvalho Chehab //	dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
3669a0bf528SMauro Carvalho Chehab 
3679a0bf528SMauro Carvalho Chehab 	reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
3689a0bf528SMauro Carvalho Chehab 	reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
3699a0bf528SMauro Carvalho Chehab 
3709a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090) {
3719a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 908, reg_908);
3729a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 909, reg_909);
3739a0bf528SMauro Carvalho Chehab 	}
3749a0bf528SMauro Carvalho Chehab }
3759a0bf528SMauro Carvalho Chehab 
3769a0bf528SMauro Carvalho Chehab static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
3779a0bf528SMauro Carvalho Chehab {
3789a0bf528SMauro Carvalho Chehab 	u32 timf;
3799a0bf528SMauro Carvalho Chehab 
3809a0bf528SMauro Carvalho Chehab 	// store the current bandwidth for later use
3819a0bf528SMauro Carvalho Chehab 	state->current_bandwidth = bw;
3829a0bf528SMauro Carvalho Chehab 
3839a0bf528SMauro Carvalho Chehab 	if (state->timf == 0) {
3845a0e2a4eSMauro Carvalho Chehab 		dprintk("using default timf\n");
3859a0bf528SMauro Carvalho Chehab 		timf = state->cfg.bw->timf;
3869a0bf528SMauro Carvalho Chehab 	} else {
3875a0e2a4eSMauro Carvalho Chehab 		dprintk("using updated timf\n");
3889a0bf528SMauro Carvalho Chehab 		timf = state->timf;
3899a0bf528SMauro Carvalho Chehab 	}
3909a0bf528SMauro Carvalho Chehab 
3919a0bf528SMauro Carvalho Chehab 	timf = timf * (bw / 50) / 160;
3929a0bf528SMauro Carvalho Chehab 
3939a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
3949a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
3959a0bf528SMauro Carvalho Chehab 
3969a0bf528SMauro Carvalho Chehab 	return 0;
3979a0bf528SMauro Carvalho Chehab }
3989a0bf528SMauro Carvalho Chehab 
3999a0bf528SMauro Carvalho Chehab static int dib7000p_sad_calib(struct dib7000p_state *state)
4009a0bf528SMauro Carvalho Chehab {
4019a0bf528SMauro Carvalho Chehab /* internal */
4029a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
4039a0bf528SMauro Carvalho Chehab 
4049a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090)
4059a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 74, 2048);
4069a0bf528SMauro Carvalho Chehab 	else
4079a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 74, 776);
4089a0bf528SMauro Carvalho Chehab 
4099a0bf528SMauro Carvalho Chehab 	/* do the calibration */
4109a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 73, (1 << 0));
4119a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 73, (0 << 0));
4129a0bf528SMauro Carvalho Chehab 
4139a0bf528SMauro Carvalho Chehab 	msleep(1);
4149a0bf528SMauro Carvalho Chehab 
4159a0bf528SMauro Carvalho Chehab 	return 0;
4169a0bf528SMauro Carvalho Chehab }
4179a0bf528SMauro Carvalho Chehab 
4188abe4a0aSMauro Carvalho Chehab static int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
4199a0bf528SMauro Carvalho Chehab {
4209a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
4219a0bf528SMauro Carvalho Chehab 	if (value > 4095)
4229a0bf528SMauro Carvalho Chehab 		value = 4095;
4239a0bf528SMauro Carvalho Chehab 	state->wbd_ref = value;
4249a0bf528SMauro Carvalho Chehab 	return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
4259a0bf528SMauro Carvalho Chehab }
4269a0bf528SMauro Carvalho Chehab 
4278abe4a0aSMauro Carvalho Chehab static int dib7000p_get_agc_values(struct dvb_frontend *fe,
4289a0bf528SMauro Carvalho Chehab 		u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
4299a0bf528SMauro Carvalho Chehab {
4309a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
4319a0bf528SMauro Carvalho Chehab 
4329a0bf528SMauro Carvalho Chehab 	if (agc_global != NULL)
4339a0bf528SMauro Carvalho Chehab 		*agc_global = dib7000p_read_word(state, 394);
4349a0bf528SMauro Carvalho Chehab 	if (agc1 != NULL)
4359a0bf528SMauro Carvalho Chehab 		*agc1 = dib7000p_read_word(state, 392);
4369a0bf528SMauro Carvalho Chehab 	if (agc2 != NULL)
4379a0bf528SMauro Carvalho Chehab 		*agc2 = dib7000p_read_word(state, 393);
4389a0bf528SMauro Carvalho Chehab 	if (wbd != NULL)
4399a0bf528SMauro Carvalho Chehab 		*wbd = dib7000p_read_word(state, 397);
4409a0bf528SMauro Carvalho Chehab 
4419a0bf528SMauro Carvalho Chehab 	return 0;
4429a0bf528SMauro Carvalho Chehab }
4439a0bf528SMauro Carvalho Chehab 
4448abe4a0aSMauro Carvalho Chehab static int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
4456fe1099cSOlivier Grenie {
4466fe1099cSOlivier Grenie 	struct dib7000p_state *state = fe->demodulator_priv;
4476fe1099cSOlivier Grenie 	return dib7000p_write_word(state, 108,  v);
4486fe1099cSOlivier Grenie }
4496fe1099cSOlivier Grenie 
4509a0bf528SMauro Carvalho Chehab static void dib7000p_reset_pll(struct dib7000p_state *state)
4519a0bf528SMauro Carvalho Chehab {
4529a0bf528SMauro Carvalho Chehab 	struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
4539a0bf528SMauro Carvalho Chehab 	u16 clk_cfg0;
4549a0bf528SMauro Carvalho Chehab 
4559a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090) {
4569a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1856, (!bw->pll_reset << 13) | (bw->pll_range << 12) | (bw->pll_ratio << 6) | (bw->pll_prediv));
4579a0bf528SMauro Carvalho Chehab 
4589a0bf528SMauro Carvalho Chehab 		while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
4599a0bf528SMauro Carvalho Chehab 			;
4609a0bf528SMauro Carvalho Chehab 
4619a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
4629a0bf528SMauro Carvalho Chehab 	} else {
4639a0bf528SMauro Carvalho Chehab 		/* force PLL bypass */
4649a0bf528SMauro Carvalho Chehab 		clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
4659a0bf528SMauro Carvalho Chehab 			(bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
4669a0bf528SMauro Carvalho Chehab 
4679a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 900, clk_cfg0);
4689a0bf528SMauro Carvalho Chehab 
4699a0bf528SMauro Carvalho Chehab 		/* P_pll_cfg */
4709a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
4719a0bf528SMauro Carvalho Chehab 		clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
4729a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 900, clk_cfg0);
4739a0bf528SMauro Carvalho Chehab 	}
4749a0bf528SMauro Carvalho Chehab 
4759a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
4769a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
4779a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
4789a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
4799a0bf528SMauro Carvalho Chehab 
4809a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 72, bw->sad_cfg);
4819a0bf528SMauro Carvalho Chehab }
4829a0bf528SMauro Carvalho Chehab 
4839a0bf528SMauro Carvalho Chehab static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
4849a0bf528SMauro Carvalho Chehab {
4859a0bf528SMauro Carvalho Chehab 	u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
4869a0bf528SMauro Carvalho Chehab 	internal |= (u32) dib7000p_read_word(state, 19);
4879a0bf528SMauro Carvalho Chehab 	internal /= 1000;
4889a0bf528SMauro Carvalho Chehab 
4899a0bf528SMauro Carvalho Chehab 	return internal;
4909a0bf528SMauro Carvalho Chehab }
4919a0bf528SMauro Carvalho Chehab 
4928abe4a0aSMauro Carvalho Chehab static int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
4939a0bf528SMauro Carvalho Chehab {
4949a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
4959a0bf528SMauro Carvalho Chehab 	u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
4969a0bf528SMauro Carvalho Chehab 	u8 loopdiv, prediv;
4979a0bf528SMauro Carvalho Chehab 	u32 internal, xtal;
4989a0bf528SMauro Carvalho Chehab 
4999a0bf528SMauro Carvalho Chehab 	/* get back old values */
5009a0bf528SMauro Carvalho Chehab 	prediv = reg_1856 & 0x3f;
5019a0bf528SMauro Carvalho Chehab 	loopdiv = (reg_1856 >> 6) & 0x3f;
5029a0bf528SMauro Carvalho Chehab 
5039a0bf528SMauro Carvalho Chehab 	if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
5045a0e2a4eSMauro Carvalho Chehab 		dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)\n", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
5059a0bf528SMauro Carvalho Chehab 		reg_1856 &= 0xf000;
5069a0bf528SMauro Carvalho Chehab 		reg_1857 = dib7000p_read_word(state, 1857);
5079a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
5089a0bf528SMauro Carvalho Chehab 
5099a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
5109a0bf528SMauro Carvalho Chehab 
5119a0bf528SMauro Carvalho Chehab 		/* write new system clk into P_sec_len */
5129a0bf528SMauro Carvalho Chehab 		internal = dib7000p_get_internal_freq(state);
5139a0bf528SMauro Carvalho Chehab 		xtal = (internal / loopdiv) * prediv;
5149a0bf528SMauro Carvalho Chehab 		internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio;	/* new internal */
5159a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
5169a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
5179a0bf528SMauro Carvalho Chehab 
5189a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
5199a0bf528SMauro Carvalho Chehab 
5209a0bf528SMauro Carvalho Chehab 		while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
5215a0e2a4eSMauro Carvalho Chehab 			dprintk("Waiting for PLL to lock\n");
5229a0bf528SMauro Carvalho Chehab 
5239a0bf528SMauro Carvalho Chehab 		return 0;
5249a0bf528SMauro Carvalho Chehab 	}
5259a0bf528SMauro Carvalho Chehab 	return -EIO;
5269a0bf528SMauro Carvalho Chehab }
5279a0bf528SMauro Carvalho Chehab 
5289a0bf528SMauro Carvalho Chehab static int dib7000p_reset_gpio(struct dib7000p_state *st)
5299a0bf528SMauro Carvalho Chehab {
5309a0bf528SMauro Carvalho Chehab 	/* reset the GPIOs */
5315a0e2a4eSMauro Carvalho Chehab 	dprintk("gpio dir: %x: val: %x, pwm_pos: %x\n", st->gpio_dir, st->gpio_val, st->cfg.gpio_pwm_pos);
5329a0bf528SMauro Carvalho Chehab 
5339a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1029, st->gpio_dir);
5349a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1030, st->gpio_val);
5359a0bf528SMauro Carvalho Chehab 
5369a0bf528SMauro Carvalho Chehab 	/* TODO 1031 is P_gpio_od */
5379a0bf528SMauro Carvalho Chehab 
5389a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
5399a0bf528SMauro Carvalho Chehab 
5409a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
5419a0bf528SMauro Carvalho Chehab 	return 0;
5429a0bf528SMauro Carvalho Chehab }
5439a0bf528SMauro Carvalho Chehab 
5449a0bf528SMauro Carvalho Chehab static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
5459a0bf528SMauro Carvalho Chehab {
5469a0bf528SMauro Carvalho Chehab 	st->gpio_dir = dib7000p_read_word(st, 1029);
5479a0bf528SMauro Carvalho Chehab 	st->gpio_dir &= ~(1 << num);	/* reset the direction bit */
5489a0bf528SMauro Carvalho Chehab 	st->gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
5499a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1029, st->gpio_dir);
5509a0bf528SMauro Carvalho Chehab 
5519a0bf528SMauro Carvalho Chehab 	st->gpio_val = dib7000p_read_word(st, 1030);
5529a0bf528SMauro Carvalho Chehab 	st->gpio_val &= ~(1 << num);	/* reset the direction bit */
5539a0bf528SMauro Carvalho Chehab 	st->gpio_val |= (val & 0x01) << num;	/* set the new value */
5549a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1030, st->gpio_val);
5559a0bf528SMauro Carvalho Chehab 
5569a0bf528SMauro Carvalho Chehab 	return 0;
5579a0bf528SMauro Carvalho Chehab }
5589a0bf528SMauro Carvalho Chehab 
5598abe4a0aSMauro Carvalho Chehab static int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
5609a0bf528SMauro Carvalho Chehab {
5619a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
5629a0bf528SMauro Carvalho Chehab 	return dib7000p_cfg_gpio(state, num, dir, val);
5639a0bf528SMauro Carvalho Chehab }
5649a0bf528SMauro Carvalho Chehab 
5659a0bf528SMauro Carvalho Chehab static u16 dib7000p_defaults[] = {
5669a0bf528SMauro Carvalho Chehab 	// auto search configuration
5679a0bf528SMauro Carvalho Chehab 	3, 2,
5689a0bf528SMauro Carvalho Chehab 	0x0004,
5699a0bf528SMauro Carvalho Chehab 	(1<<3)|(1<<11)|(1<<12)|(1<<13),
5709a0bf528SMauro Carvalho Chehab 	0x0814,			/* Equal Lock */
5719a0bf528SMauro Carvalho Chehab 
5729a0bf528SMauro Carvalho Chehab 	12, 6,
5739a0bf528SMauro Carvalho Chehab 	0x001b,
5749a0bf528SMauro Carvalho Chehab 	0x7740,
5759a0bf528SMauro Carvalho Chehab 	0x005b,
5769a0bf528SMauro Carvalho Chehab 	0x8d80,
5779a0bf528SMauro Carvalho Chehab 	0x01c9,
5789a0bf528SMauro Carvalho Chehab 	0xc380,
5799a0bf528SMauro Carvalho Chehab 	0x0000,
5809a0bf528SMauro Carvalho Chehab 	0x0080,
5819a0bf528SMauro Carvalho Chehab 	0x0000,
5829a0bf528SMauro Carvalho Chehab 	0x0090,
5839a0bf528SMauro Carvalho Chehab 	0x0001,
5849a0bf528SMauro Carvalho Chehab 	0xd4c0,
5859a0bf528SMauro Carvalho Chehab 
5869a0bf528SMauro Carvalho Chehab 	1, 26,
5879a0bf528SMauro Carvalho Chehab 	0x6680,
5889a0bf528SMauro Carvalho Chehab 
5899a0bf528SMauro Carvalho Chehab 	/* set ADC level to -16 */
5909a0bf528SMauro Carvalho Chehab 	11, 79,
5919a0bf528SMauro Carvalho Chehab 	(1 << 13) - 825 - 117,
5929a0bf528SMauro Carvalho Chehab 	(1 << 13) - 837 - 117,
5939a0bf528SMauro Carvalho Chehab 	(1 << 13) - 811 - 117,
5949a0bf528SMauro Carvalho Chehab 	(1 << 13) - 766 - 117,
5959a0bf528SMauro Carvalho Chehab 	(1 << 13) - 737 - 117,
5969a0bf528SMauro Carvalho Chehab 	(1 << 13) - 693 - 117,
5979a0bf528SMauro Carvalho Chehab 	(1 << 13) - 648 - 117,
5989a0bf528SMauro Carvalho Chehab 	(1 << 13) - 619 - 117,
5999a0bf528SMauro Carvalho Chehab 	(1 << 13) - 575 - 117,
6009a0bf528SMauro Carvalho Chehab 	(1 << 13) - 531 - 117,
6019a0bf528SMauro Carvalho Chehab 	(1 << 13) - 501 - 117,
6029a0bf528SMauro Carvalho Chehab 
6039a0bf528SMauro Carvalho Chehab 	1, 142,
6049a0bf528SMauro Carvalho Chehab 	0x0410,
6059a0bf528SMauro Carvalho Chehab 
6069a0bf528SMauro Carvalho Chehab 	/* disable power smoothing */
6079a0bf528SMauro Carvalho Chehab 	8, 145,
6089a0bf528SMauro Carvalho Chehab 	0,
6099a0bf528SMauro Carvalho Chehab 	0,
6109a0bf528SMauro Carvalho Chehab 	0,
6119a0bf528SMauro Carvalho Chehab 	0,
6129a0bf528SMauro Carvalho Chehab 	0,
6139a0bf528SMauro Carvalho Chehab 	0,
6149a0bf528SMauro Carvalho Chehab 	0,
6159a0bf528SMauro Carvalho Chehab 	0,
6169a0bf528SMauro Carvalho Chehab 
6179a0bf528SMauro Carvalho Chehab 	1, 154,
6189a0bf528SMauro Carvalho Chehab 	1 << 13,
6199a0bf528SMauro Carvalho Chehab 
6209a0bf528SMauro Carvalho Chehab 	1, 168,
6219a0bf528SMauro Carvalho Chehab 	0x0ccd,
6229a0bf528SMauro Carvalho Chehab 
6239a0bf528SMauro Carvalho Chehab 	1, 183,
6249a0bf528SMauro Carvalho Chehab 	0x200f,
6259a0bf528SMauro Carvalho Chehab 
6269a0bf528SMauro Carvalho Chehab 	1, 212,
6279a0bf528SMauro Carvalho Chehab 		0x169,
6289a0bf528SMauro Carvalho Chehab 
6299a0bf528SMauro Carvalho Chehab 	5, 187,
6309a0bf528SMauro Carvalho Chehab 	0x023d,
6319a0bf528SMauro Carvalho Chehab 	0x00a4,
6329a0bf528SMauro Carvalho Chehab 	0x00a4,
6339a0bf528SMauro Carvalho Chehab 	0x7ff0,
6349a0bf528SMauro Carvalho Chehab 	0x3ccc,
6359a0bf528SMauro Carvalho Chehab 
6369a0bf528SMauro Carvalho Chehab 	1, 198,
6379a0bf528SMauro Carvalho Chehab 	0x800,
6389a0bf528SMauro Carvalho Chehab 
6399a0bf528SMauro Carvalho Chehab 	1, 222,
6409a0bf528SMauro Carvalho Chehab 	0x0010,
6419a0bf528SMauro Carvalho Chehab 
6429a0bf528SMauro Carvalho Chehab 	1, 235,
6439a0bf528SMauro Carvalho Chehab 	0x0062,
6449a0bf528SMauro Carvalho Chehab 
6459a0bf528SMauro Carvalho Chehab 	0,
6469a0bf528SMauro Carvalho Chehab };
6479a0bf528SMauro Carvalho Chehab 
648041ad449SMauro Carvalho Chehab static void dib7000p_reset_stats(struct dvb_frontend *fe);
649041ad449SMauro Carvalho Chehab 
6509a0bf528SMauro Carvalho Chehab static int dib7000p_demod_reset(struct dib7000p_state *state)
6519a0bf528SMauro Carvalho Chehab {
6529a0bf528SMauro Carvalho Chehab 	dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
6539a0bf528SMauro Carvalho Chehab 
6549a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090)
6559a0bf528SMauro Carvalho Chehab 		dibx000_reset_i2c_master(&state->i2c_master);
6569a0bf528SMauro Carvalho Chehab 
6579a0bf528SMauro Carvalho Chehab 	dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
6589a0bf528SMauro Carvalho Chehab 
6599a0bf528SMauro Carvalho Chehab 	/* restart all parts */
6609a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, 0xffff);
6619a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 771, 0xffff);
6629a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 772, 0x001f);
6639a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
6649a0bf528SMauro Carvalho Chehab 
6659a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, 0);
6669a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 771, 0);
6679a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 772, 0);
6689a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1280, 0);
6699a0bf528SMauro Carvalho Chehab 
6709a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090) {
6719a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state,  898, 0x0003);
6729a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state,  898, 0);
6739a0bf528SMauro Carvalho Chehab 	}
6749a0bf528SMauro Carvalho Chehab 
6759a0bf528SMauro Carvalho Chehab 	/* default */
6769a0bf528SMauro Carvalho Chehab 	dib7000p_reset_pll(state);
6779a0bf528SMauro Carvalho Chehab 
6789a0bf528SMauro Carvalho Chehab 	if (dib7000p_reset_gpio(state) != 0)
6795a0e2a4eSMauro Carvalho Chehab 		dprintk("GPIO reset was not successful.\n");
6809a0bf528SMauro Carvalho Chehab 
6819a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090) {
6829a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 899, 0);
6839a0bf528SMauro Carvalho Chehab 
6849a0bf528SMauro Carvalho Chehab 		/* impulse noise */
6859a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
6869a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
6879a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
6889a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 273, (0<<6) | 30);
6899a0bf528SMauro Carvalho Chehab 	}
6909a0bf528SMauro Carvalho Chehab 	if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
6915a0e2a4eSMauro Carvalho Chehab 		dprintk("OUTPUT_MODE could not be reset.\n");
6929a0bf528SMauro Carvalho Chehab 
6939a0bf528SMauro Carvalho Chehab 	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
6949a0bf528SMauro Carvalho Chehab 	dib7000p_sad_calib(state);
6959a0bf528SMauro Carvalho Chehab 	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
6969a0bf528SMauro Carvalho Chehab 
6979a0bf528SMauro Carvalho Chehab 	/* unforce divstr regardless whether i2c enumeration was done or not */
6989a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
6999a0bf528SMauro Carvalho Chehab 
7009a0bf528SMauro Carvalho Chehab 	dib7000p_set_bandwidth(state, 8000);
7019a0bf528SMauro Carvalho Chehab 
7029a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090) {
7039a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 36, 0x0755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
7049a0bf528SMauro Carvalho Chehab 	} else {
7059a0bf528SMauro Carvalho Chehab 		if (state->cfg.tuner_is_baseband)
7069a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 36, 0x0755);
7079a0bf528SMauro Carvalho Chehab 		else
7089a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 36, 0x1f55);
7099a0bf528SMauro Carvalho Chehab 	}
7109a0bf528SMauro Carvalho Chehab 
7119a0bf528SMauro Carvalho Chehab 	dib7000p_write_tab(state, dib7000p_defaults);
7129a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090) {
7139a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 901, 0x0006);
7149a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
7159a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 905, 0x2c8e);
7169a0bf528SMauro Carvalho Chehab 	}
7179a0bf528SMauro Carvalho Chehab 
7189a0bf528SMauro Carvalho Chehab 	dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
7199a0bf528SMauro Carvalho Chehab 
7209a0bf528SMauro Carvalho Chehab 	return 0;
7219a0bf528SMauro Carvalho Chehab }
7229a0bf528SMauro Carvalho Chehab 
7239a0bf528SMauro Carvalho Chehab static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
7249a0bf528SMauro Carvalho Chehab {
7259a0bf528SMauro Carvalho Chehab 	u16 tmp = 0;
7269a0bf528SMauro Carvalho Chehab 	tmp = dib7000p_read_word(state, 903);
7279a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 903, (tmp | 0x1));
7289a0bf528SMauro Carvalho Chehab 	tmp = dib7000p_read_word(state, 900);
7299a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
7309a0bf528SMauro Carvalho Chehab }
7319a0bf528SMauro Carvalho Chehab 
7329a0bf528SMauro Carvalho Chehab static void dib7000p_restart_agc(struct dib7000p_state *state)
7339a0bf528SMauro Carvalho Chehab {
7349a0bf528SMauro Carvalho Chehab 	// P_restart_iqc & P_restart_agc
7359a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
7369a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, 0x0000);
7379a0bf528SMauro Carvalho Chehab }
7389a0bf528SMauro Carvalho Chehab 
7399a0bf528SMauro Carvalho Chehab static int dib7000p_update_lna(struct dib7000p_state *state)
7409a0bf528SMauro Carvalho Chehab {
7419a0bf528SMauro Carvalho Chehab 	u16 dyn_gain;
7429a0bf528SMauro Carvalho Chehab 
7439a0bf528SMauro Carvalho Chehab 	if (state->cfg.update_lna) {
7449a0bf528SMauro Carvalho Chehab 		dyn_gain = dib7000p_read_word(state, 394);
7459a0bf528SMauro Carvalho Chehab 		if (state->cfg.update_lna(&state->demod, dyn_gain)) {
7469a0bf528SMauro Carvalho Chehab 			dib7000p_restart_agc(state);
7479a0bf528SMauro Carvalho Chehab 			return 1;
7489a0bf528SMauro Carvalho Chehab 		}
7499a0bf528SMauro Carvalho Chehab 	}
7509a0bf528SMauro Carvalho Chehab 
7519a0bf528SMauro Carvalho Chehab 	return 0;
7529a0bf528SMauro Carvalho Chehab }
7539a0bf528SMauro Carvalho Chehab 
7549a0bf528SMauro Carvalho Chehab static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
7559a0bf528SMauro Carvalho Chehab {
7569a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *agc = NULL;
7579a0bf528SMauro Carvalho Chehab 	int i;
7589a0bf528SMauro Carvalho Chehab 	if (state->current_band == band && state->current_agc != NULL)
7599a0bf528SMauro Carvalho Chehab 		return 0;
7609a0bf528SMauro Carvalho Chehab 	state->current_band = band;
7619a0bf528SMauro Carvalho Chehab 
7629a0bf528SMauro Carvalho Chehab 	for (i = 0; i < state->cfg.agc_config_count; i++)
7639a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc[i].band_caps & band) {
7649a0bf528SMauro Carvalho Chehab 			agc = &state->cfg.agc[i];
7659a0bf528SMauro Carvalho Chehab 			break;
7669a0bf528SMauro Carvalho Chehab 		}
7679a0bf528SMauro Carvalho Chehab 
7689a0bf528SMauro Carvalho Chehab 	if (agc == NULL) {
7695a0e2a4eSMauro Carvalho Chehab 		dprintk("no valid AGC configuration found for band 0x%02x\n", band);
7709a0bf528SMauro Carvalho Chehab 		return -EINVAL;
7719a0bf528SMauro Carvalho Chehab 	}
7729a0bf528SMauro Carvalho Chehab 
7739a0bf528SMauro Carvalho Chehab 	state->current_agc = agc;
7749a0bf528SMauro Carvalho Chehab 
7759a0bf528SMauro Carvalho Chehab 	/* AGC */
7769a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 75, agc->setup);
7779a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 76, agc->inv_gain);
7789a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 77, agc->time_stabiliz);
7799a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
7809a0bf528SMauro Carvalho Chehab 
7819a0bf528SMauro Carvalho Chehab 	// Demod AGC loop configuration
7829a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
7839a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
7849a0bf528SMauro Carvalho Chehab 
7859a0bf528SMauro Carvalho Chehab 	/* AGC continued */
7865a0e2a4eSMauro Carvalho Chehab 	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
7879a0bf528SMauro Carvalho Chehab 		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
7889a0bf528SMauro Carvalho Chehab 
7899a0bf528SMauro Carvalho Chehab 	if (state->wbd_ref != 0)
7909a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
7919a0bf528SMauro Carvalho Chehab 	else
7929a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
7939a0bf528SMauro Carvalho Chehab 
7949a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
7959a0bf528SMauro Carvalho Chehab 
7969a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 107, agc->agc1_max);
7979a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 108, agc->agc1_min);
7989a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 109, agc->agc2_max);
7999a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 110, agc->agc2_min);
8009a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
8019a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 112, agc->agc1_pt3);
8029a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
8039a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
8049a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
8059a0bf528SMauro Carvalho Chehab 	return 0;
8069a0bf528SMauro Carvalho Chehab }
8079a0bf528SMauro Carvalho Chehab 
808*5332b626SMartin Wache static int dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
8099a0bf528SMauro Carvalho Chehab {
8109a0bf528SMauro Carvalho Chehab 	u32 internal = dib7000p_get_internal_freq(state);
811*5332b626SMartin Wache 	s32 unit_khz_dds_val;
8129a0bf528SMauro Carvalho Chehab 	u32 abs_offset_khz = ABS(offset_khz);
8139a0bf528SMauro Carvalho Chehab 	u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
8149a0bf528SMauro Carvalho Chehab 	u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
815*5332b626SMartin Wache 	if (internal == 0) {
816*5332b626SMartin Wache 		pr_warn("DIB7000P: dib7000p_get_internal_freq returned 0\n");
817*5332b626SMartin Wache 		return -1;
818*5332b626SMartin Wache 	}
819*5332b626SMartin Wache 	/* 2**26 / Fsampling is the unit 1KHz offset */
820*5332b626SMartin Wache 	unit_khz_dds_val = 67108864 / (internal);
8219a0bf528SMauro Carvalho Chehab 
8225a0e2a4eSMauro Carvalho Chehab 	dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d\n", offset_khz, internal, invert);
8239a0bf528SMauro Carvalho Chehab 
8249a0bf528SMauro Carvalho Chehab 	if (offset_khz < 0)
8259a0bf528SMauro Carvalho Chehab 		unit_khz_dds_val *= -1;
8269a0bf528SMauro Carvalho Chehab 
8279a0bf528SMauro Carvalho Chehab 	/* IF tuner */
8289a0bf528SMauro Carvalho Chehab 	if (invert)
8299a0bf528SMauro 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 */
8309a0bf528SMauro Carvalho Chehab 	else
8319a0bf528SMauro Carvalho Chehab 		dds += (abs_offset_khz * unit_khz_dds_val);
8329a0bf528SMauro Carvalho Chehab 
8339a0bf528SMauro Carvalho Chehab 	if (abs_offset_khz <= (internal / 2)) {	/* Max dds offset is the half of the demod freq */
8349a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
8359a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
8369a0bf528SMauro Carvalho Chehab 	}
837*5332b626SMartin Wache 	return 0;
8389a0bf528SMauro Carvalho Chehab }
8399a0bf528SMauro Carvalho Chehab 
8409a0bf528SMauro Carvalho Chehab static int dib7000p_agc_startup(struct dvb_frontend *demod)
8419a0bf528SMauro Carvalho Chehab {
8429a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
8439a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
8449a0bf528SMauro Carvalho Chehab 	int ret = -1;
8459a0bf528SMauro Carvalho Chehab 	u8 *agc_state = &state->agc_state;
8469a0bf528SMauro Carvalho Chehab 	u8 agc_split;
8479a0bf528SMauro Carvalho Chehab 	u16 reg;
8489a0bf528SMauro Carvalho Chehab 	u32 upd_demod_gain_period = 0x1000;
8496fe1099cSOlivier Grenie 	s32 frequency_offset = 0;
8509a0bf528SMauro Carvalho Chehab 
8519a0bf528SMauro Carvalho Chehab 	switch (state->agc_state) {
8529a0bf528SMauro Carvalho Chehab 	case 0:
8539a0bf528SMauro Carvalho Chehab 		dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
8549a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090) {
8559a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 0x79b) & 0xff00;
8569a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF);	/* lsb */
8579a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
8589a0bf528SMauro Carvalho Chehab 
8599a0bf528SMauro Carvalho Chehab 			/* enable adc i & q */
8609a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 0x780);
8619a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
8629a0bf528SMauro Carvalho Chehab 		} else {
8639a0bf528SMauro Carvalho Chehab 			dib7000p_set_adc_state(state, DIBX000_ADC_ON);
8649a0bf528SMauro Carvalho Chehab 			dib7000p_pll_clk_cfg(state);
8659a0bf528SMauro Carvalho Chehab 		}
8669a0bf528SMauro Carvalho Chehab 
8679a0bf528SMauro Carvalho Chehab 		if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
8689a0bf528SMauro Carvalho Chehab 			return -1;
8699a0bf528SMauro Carvalho Chehab 
8706fe1099cSOlivier Grenie 		if (demod->ops.tuner_ops.get_frequency) {
8716fe1099cSOlivier Grenie 			u32 frequency_tuner;
8726fe1099cSOlivier Grenie 
8736fe1099cSOlivier Grenie 			demod->ops.tuner_ops.get_frequency(demod, &frequency_tuner);
8746fe1099cSOlivier Grenie 			frequency_offset = (s32)frequency_tuner / 1000 - ch->frequency / 1000;
8756fe1099cSOlivier Grenie 		}
8766fe1099cSOlivier Grenie 
877*5332b626SMartin Wache 		if (dib7000p_set_dds(state, frequency_offset) < 0)
878*5332b626SMartin Wache 			return -1;
879*5332b626SMartin Wache 
8809a0bf528SMauro Carvalho Chehab 		ret = 7;
8819a0bf528SMauro Carvalho Chehab 		(*agc_state)++;
8829a0bf528SMauro Carvalho Chehab 		break;
8839a0bf528SMauro Carvalho Chehab 
8849a0bf528SMauro Carvalho Chehab 	case 1:
8859a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
8869a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(&state->demod, 1);
8879a0bf528SMauro Carvalho Chehab 
8889a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 78, 32768);
8899a0bf528SMauro Carvalho Chehab 		if (!state->current_agc->perform_agc_softsplit) {
8909a0bf528SMauro Carvalho Chehab 			/* we are using the wbd - so slow AGC startup */
8919a0bf528SMauro Carvalho Chehab 			/* force 0 split on WBD and restart AGC */
8929a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
8939a0bf528SMauro Carvalho Chehab 			(*agc_state)++;
8949a0bf528SMauro Carvalho Chehab 			ret = 5;
8959a0bf528SMauro Carvalho Chehab 		} else {
8969a0bf528SMauro Carvalho Chehab 			/* default AGC startup */
8979a0bf528SMauro Carvalho Chehab 			(*agc_state) = 4;
8989a0bf528SMauro Carvalho Chehab 			/* wait AGC rough lock time */
8999a0bf528SMauro Carvalho Chehab 			ret = 7;
9009a0bf528SMauro Carvalho Chehab 		}
9019a0bf528SMauro Carvalho Chehab 
9029a0bf528SMauro Carvalho Chehab 		dib7000p_restart_agc(state);
9039a0bf528SMauro Carvalho Chehab 		break;
9049a0bf528SMauro Carvalho Chehab 
9059a0bf528SMauro Carvalho Chehab 	case 2:		/* fast split search path after 5sec */
9069a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4));	/* freeze AGC loop */
9079a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8));	/* fast split search 0.25kHz */
9089a0bf528SMauro Carvalho Chehab 		(*agc_state)++;
9099a0bf528SMauro Carvalho Chehab 		ret = 14;
9109a0bf528SMauro Carvalho Chehab 		break;
9119a0bf528SMauro Carvalho Chehab 
9129a0bf528SMauro Carvalho Chehab 	case 3:		/* split search ended */
9139a0bf528SMauro Carvalho Chehab 		agc_split = (u8) dib7000p_read_word(state, 396);	/* store the split value for the next time */
9149a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 78, dib7000p_read_word(state, 394));	/* set AGC gain start value */
9159a0bf528SMauro Carvalho Chehab 
9169a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 75, state->current_agc->setup);	/* std AGC loop */
9179a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split);	/* standard split search */
9189a0bf528SMauro Carvalho Chehab 
9199a0bf528SMauro Carvalho Chehab 		dib7000p_restart_agc(state);
9209a0bf528SMauro Carvalho Chehab 
9215a0e2a4eSMauro Carvalho Chehab 		dprintk("SPLIT %p: %hd\n", demod, agc_split);
9229a0bf528SMauro Carvalho Chehab 
9239a0bf528SMauro Carvalho Chehab 		(*agc_state)++;
9249a0bf528SMauro Carvalho Chehab 		ret = 5;
9259a0bf528SMauro Carvalho Chehab 		break;
9269a0bf528SMauro Carvalho Chehab 
9279a0bf528SMauro Carvalho Chehab 	case 4:		/* LNA startup */
9289a0bf528SMauro Carvalho Chehab 		ret = 7;
9299a0bf528SMauro Carvalho Chehab 
9309a0bf528SMauro Carvalho Chehab 		if (dib7000p_update_lna(state))
9319a0bf528SMauro Carvalho Chehab 			ret = 5;
9329a0bf528SMauro Carvalho Chehab 		else
9339a0bf528SMauro Carvalho Chehab 			(*agc_state)++;
9349a0bf528SMauro Carvalho Chehab 		break;
9359a0bf528SMauro Carvalho Chehab 
9369a0bf528SMauro Carvalho Chehab 	case 5:
9379a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
9389a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(&state->demod, 0);
9399a0bf528SMauro Carvalho Chehab 		(*agc_state)++;
9409a0bf528SMauro Carvalho Chehab 		break;
9419a0bf528SMauro Carvalho Chehab 	default:
9429a0bf528SMauro Carvalho Chehab 		break;
9439a0bf528SMauro Carvalho Chehab 	}
9449a0bf528SMauro Carvalho Chehab 	return ret;
9459a0bf528SMauro Carvalho Chehab }
9469a0bf528SMauro Carvalho Chehab 
9479a0bf528SMauro Carvalho Chehab static void dib7000p_update_timf(struct dib7000p_state *state)
9489a0bf528SMauro Carvalho Chehab {
9499a0bf528SMauro Carvalho Chehab 	u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
9509a0bf528SMauro Carvalho Chehab 	state->timf = timf * 160 / (state->current_bandwidth / 50);
9519a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 23, (u16) (timf >> 16));
9529a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
9535a0e2a4eSMauro Carvalho Chehab 	dprintk("updated timf_frequency: %d (default: %d)\n", state->timf, state->cfg.bw->timf);
9549a0bf528SMauro Carvalho Chehab 
9559a0bf528SMauro Carvalho Chehab }
9569a0bf528SMauro Carvalho Chehab 
9578abe4a0aSMauro Carvalho Chehab static u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
9589a0bf528SMauro Carvalho Chehab {
9599a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
9609a0bf528SMauro Carvalho Chehab 	switch (op) {
9619a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_SET:
9629a0bf528SMauro Carvalho Chehab 		state->timf = timf;
9639a0bf528SMauro Carvalho Chehab 		break;
9649a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_UPDATE:
9659a0bf528SMauro Carvalho Chehab 		dib7000p_update_timf(state);
9669a0bf528SMauro Carvalho Chehab 		break;
9679a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_GET:
9689a0bf528SMauro Carvalho Chehab 		break;
9699a0bf528SMauro Carvalho Chehab 	}
9709a0bf528SMauro Carvalho Chehab 	dib7000p_set_bandwidth(state, state->current_bandwidth);
9719a0bf528SMauro Carvalho Chehab 	return state->timf;
9729a0bf528SMauro Carvalho Chehab }
9739a0bf528SMauro Carvalho Chehab 
9749a0bf528SMauro Carvalho Chehab static void dib7000p_set_channel(struct dib7000p_state *state,
9759a0bf528SMauro Carvalho Chehab 				 struct dtv_frontend_properties *ch, u8 seq)
9769a0bf528SMauro Carvalho Chehab {
9779a0bf528SMauro Carvalho Chehab 	u16 value, est[4];
9789a0bf528SMauro Carvalho Chehab 
9799a0bf528SMauro Carvalho Chehab 	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
9809a0bf528SMauro Carvalho Chehab 
9819a0bf528SMauro Carvalho Chehab 	/* nfft, guard, qam, alpha */
9829a0bf528SMauro Carvalho Chehab 	value = 0;
9839a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
9849a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
9859a0bf528SMauro Carvalho Chehab 		value |= (0 << 7);
9869a0bf528SMauro Carvalho Chehab 		break;
9879a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
9889a0bf528SMauro Carvalho Chehab 		value |= (2 << 7);
9899a0bf528SMauro Carvalho Chehab 		break;
9909a0bf528SMauro Carvalho Chehab 	default:
9919a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
9929a0bf528SMauro Carvalho Chehab 		value |= (1 << 7);
9939a0bf528SMauro Carvalho Chehab 		break;
9949a0bf528SMauro Carvalho Chehab 	}
9959a0bf528SMauro Carvalho Chehab 	switch (ch->guard_interval) {
9969a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_32:
9979a0bf528SMauro Carvalho Chehab 		value |= (0 << 5);
9989a0bf528SMauro Carvalho Chehab 		break;
9999a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_16:
10009a0bf528SMauro Carvalho Chehab 		value |= (1 << 5);
10019a0bf528SMauro Carvalho Chehab 		break;
10029a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_4:
10039a0bf528SMauro Carvalho Chehab 		value |= (3 << 5);
10049a0bf528SMauro Carvalho Chehab 		break;
10059a0bf528SMauro Carvalho Chehab 	default:
10069a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_8:
10079a0bf528SMauro Carvalho Chehab 		value |= (2 << 5);
10089a0bf528SMauro Carvalho Chehab 		break;
10099a0bf528SMauro Carvalho Chehab 	}
10109a0bf528SMauro Carvalho Chehab 	switch (ch->modulation) {
10119a0bf528SMauro Carvalho Chehab 	case QPSK:
10129a0bf528SMauro Carvalho Chehab 		value |= (0 << 3);
10139a0bf528SMauro Carvalho Chehab 		break;
10149a0bf528SMauro Carvalho Chehab 	case QAM_16:
10159a0bf528SMauro Carvalho Chehab 		value |= (1 << 3);
10169a0bf528SMauro Carvalho Chehab 		break;
10179a0bf528SMauro Carvalho Chehab 	default:
10189a0bf528SMauro Carvalho Chehab 	case QAM_64:
10199a0bf528SMauro Carvalho Chehab 		value |= (2 << 3);
10209a0bf528SMauro Carvalho Chehab 		break;
10219a0bf528SMauro Carvalho Chehab 	}
10229a0bf528SMauro Carvalho Chehab 	switch (HIERARCHY_1) {
10239a0bf528SMauro Carvalho Chehab 	case HIERARCHY_2:
10249a0bf528SMauro Carvalho Chehab 		value |= 2;
10259a0bf528SMauro Carvalho Chehab 		break;
10269a0bf528SMauro Carvalho Chehab 	case HIERARCHY_4:
10279a0bf528SMauro Carvalho Chehab 		value |= 4;
10289a0bf528SMauro Carvalho Chehab 		break;
10299a0bf528SMauro Carvalho Chehab 	default:
10309a0bf528SMauro Carvalho Chehab 	case HIERARCHY_1:
10319a0bf528SMauro Carvalho Chehab 		value |= 1;
10329a0bf528SMauro Carvalho Chehab 		break;
10339a0bf528SMauro Carvalho Chehab 	}
10349a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 0, value);
10359a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 5, (seq << 4) | 1);	/* do not force tps, search list 0 */
10369a0bf528SMauro Carvalho Chehab 
10379a0bf528SMauro Carvalho Chehab 	/* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
10389a0bf528SMauro Carvalho Chehab 	value = 0;
10399a0bf528SMauro Carvalho Chehab 	if (1 != 0)
10409a0bf528SMauro Carvalho Chehab 		value |= (1 << 6);
10419a0bf528SMauro Carvalho Chehab 	if (ch->hierarchy == 1)
10429a0bf528SMauro Carvalho Chehab 		value |= (1 << 4);
10439a0bf528SMauro Carvalho Chehab 	if (1 == 1)
10449a0bf528SMauro Carvalho Chehab 		value |= 1;
10459a0bf528SMauro Carvalho Chehab 	switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
10469a0bf528SMauro Carvalho Chehab 	case FEC_2_3:
10479a0bf528SMauro Carvalho Chehab 		value |= (2 << 1);
10489a0bf528SMauro Carvalho Chehab 		break;
10499a0bf528SMauro Carvalho Chehab 	case FEC_3_4:
10509a0bf528SMauro Carvalho Chehab 		value |= (3 << 1);
10519a0bf528SMauro Carvalho Chehab 		break;
10529a0bf528SMauro Carvalho Chehab 	case FEC_5_6:
10539a0bf528SMauro Carvalho Chehab 		value |= (5 << 1);
10549a0bf528SMauro Carvalho Chehab 		break;
10559a0bf528SMauro Carvalho Chehab 	case FEC_7_8:
10569a0bf528SMauro Carvalho Chehab 		value |= (7 << 1);
10579a0bf528SMauro Carvalho Chehab 		break;
10589a0bf528SMauro Carvalho Chehab 	default:
10599a0bf528SMauro Carvalho Chehab 	case FEC_1_2:
10609a0bf528SMauro Carvalho Chehab 		value |= (1 << 1);
10619a0bf528SMauro Carvalho Chehab 		break;
10629a0bf528SMauro Carvalho Chehab 	}
10639a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 208, value);
10649a0bf528SMauro Carvalho Chehab 
10659a0bf528SMauro Carvalho Chehab 	/* offset loop parameters */
10669a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 26, 0x6680);
10679a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 32, 0x0003);
10689a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 29, 0x1273);
10699a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 33, 0x0005);
10709a0bf528SMauro Carvalho Chehab 
10719a0bf528SMauro Carvalho Chehab 	/* P_dvsy_sync_wait */
10729a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
10739a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
10749a0bf528SMauro Carvalho Chehab 		value = 256;
10759a0bf528SMauro Carvalho Chehab 		break;
10769a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
10779a0bf528SMauro Carvalho Chehab 		value = 128;
10789a0bf528SMauro Carvalho Chehab 		break;
10799a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
10809a0bf528SMauro Carvalho Chehab 	default:
10819a0bf528SMauro Carvalho Chehab 		value = 64;
10829a0bf528SMauro Carvalho Chehab 		break;
10839a0bf528SMauro Carvalho Chehab 	}
10849a0bf528SMauro Carvalho Chehab 	switch (ch->guard_interval) {
10859a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_16:
10869a0bf528SMauro Carvalho Chehab 		value *= 2;
10879a0bf528SMauro Carvalho Chehab 		break;
10889a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_8:
10899a0bf528SMauro Carvalho Chehab 		value *= 4;
10909a0bf528SMauro Carvalho Chehab 		break;
10919a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_4:
10929a0bf528SMauro Carvalho Chehab 		value *= 8;
10939a0bf528SMauro Carvalho Chehab 		break;
10949a0bf528SMauro Carvalho Chehab 	default:
10959a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_32:
10969a0bf528SMauro Carvalho Chehab 		value *= 1;
10979a0bf528SMauro Carvalho Chehab 		break;
10989a0bf528SMauro Carvalho Chehab 	}
10999a0bf528SMauro Carvalho Chehab 	if (state->cfg.diversity_delay == 0)
11009a0bf528SMauro Carvalho Chehab 		state->div_sync_wait = (value * 3) / 2 + 48;
11019a0bf528SMauro Carvalho Chehab 	else
11029a0bf528SMauro Carvalho Chehab 		state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
11039a0bf528SMauro Carvalho Chehab 
11049a0bf528SMauro Carvalho Chehab 	/* deactive the possibility of diversity reception if extended interleaver */
11059a0bf528SMauro Carvalho Chehab 	state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K;
11069a0bf528SMauro Carvalho Chehab 	dib7000p_set_diversity_in(&state->demod, state->div_state);
11079a0bf528SMauro Carvalho Chehab 
11089a0bf528SMauro Carvalho Chehab 	/* channel estimation fine configuration */
11099a0bf528SMauro Carvalho Chehab 	switch (ch->modulation) {
11109a0bf528SMauro Carvalho Chehab 	case QAM_64:
11119a0bf528SMauro Carvalho Chehab 		est[0] = 0x0148;	/* P_adp_regul_cnt 0.04 */
11129a0bf528SMauro Carvalho Chehab 		est[1] = 0xfff0;	/* P_adp_noise_cnt -0.002 */
11139a0bf528SMauro Carvalho Chehab 		est[2] = 0x00a4;	/* P_adp_regul_ext 0.02 */
11149a0bf528SMauro Carvalho Chehab 		est[3] = 0xfff8;	/* P_adp_noise_ext -0.001 */
11159a0bf528SMauro Carvalho Chehab 		break;
11169a0bf528SMauro Carvalho Chehab 	case QAM_16:
11179a0bf528SMauro Carvalho Chehab 		est[0] = 0x023d;	/* P_adp_regul_cnt 0.07 */
11189a0bf528SMauro Carvalho Chehab 		est[1] = 0xffdf;	/* P_adp_noise_cnt -0.004 */
11199a0bf528SMauro Carvalho Chehab 		est[2] = 0x00a4;	/* P_adp_regul_ext 0.02 */
11209a0bf528SMauro Carvalho Chehab 		est[3] = 0xfff0;	/* P_adp_noise_ext -0.002 */
11219a0bf528SMauro Carvalho Chehab 		break;
11229a0bf528SMauro Carvalho Chehab 	default:
11239a0bf528SMauro Carvalho Chehab 		est[0] = 0x099a;	/* P_adp_regul_cnt 0.3 */
11249a0bf528SMauro Carvalho Chehab 		est[1] = 0xffae;	/* P_adp_noise_cnt -0.01 */
11259a0bf528SMauro Carvalho Chehab 		est[2] = 0x0333;	/* P_adp_regul_ext 0.1 */
11269a0bf528SMauro Carvalho Chehab 		est[3] = 0xfff8;	/* P_adp_noise_ext -0.002 */
11279a0bf528SMauro Carvalho Chehab 		break;
11289a0bf528SMauro Carvalho Chehab 	}
11299a0bf528SMauro Carvalho Chehab 	for (value = 0; value < 4; value++)
11309a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 187 + value, est[value]);
11319a0bf528SMauro Carvalho Chehab }
11329a0bf528SMauro Carvalho Chehab 
11339a0bf528SMauro Carvalho Chehab static int dib7000p_autosearch_start(struct dvb_frontend *demod)
11349a0bf528SMauro Carvalho Chehab {
11359a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
11369a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
11379a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties schan;
11389a0bf528SMauro Carvalho Chehab 	u32 value, factor;
11399a0bf528SMauro Carvalho Chehab 	u32 internal = dib7000p_get_internal_freq(state);
11409a0bf528SMauro Carvalho Chehab 
11419a0bf528SMauro Carvalho Chehab 	schan = *ch;
11429a0bf528SMauro Carvalho Chehab 	schan.modulation = QAM_64;
11439a0bf528SMauro Carvalho Chehab 	schan.guard_interval = GUARD_INTERVAL_1_32;
11449a0bf528SMauro Carvalho Chehab 	schan.transmission_mode = TRANSMISSION_MODE_8K;
11459a0bf528SMauro Carvalho Chehab 	schan.code_rate_HP = FEC_2_3;
11469a0bf528SMauro Carvalho Chehab 	schan.code_rate_LP = FEC_3_4;
11479a0bf528SMauro Carvalho Chehab 	schan.hierarchy = 0;
11489a0bf528SMauro Carvalho Chehab 
11499a0bf528SMauro Carvalho Chehab 	dib7000p_set_channel(state, &schan, 7);
11509a0bf528SMauro Carvalho Chehab 
11519a0bf528SMauro Carvalho Chehab 	factor = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
11529a0bf528SMauro Carvalho Chehab 	if (factor >= 5000) {
11539a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090)
11549a0bf528SMauro Carvalho Chehab 			factor = 2;
11559a0bf528SMauro Carvalho Chehab 		else
11569a0bf528SMauro Carvalho Chehab 			factor = 1;
11579a0bf528SMauro Carvalho Chehab 	} else
11589a0bf528SMauro Carvalho Chehab 		factor = 6;
11599a0bf528SMauro Carvalho Chehab 
11609a0bf528SMauro Carvalho Chehab 	value = 30 * internal * factor;
11619a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
11629a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 7, (u16) (value & 0xffff));
11639a0bf528SMauro Carvalho Chehab 	value = 100 * internal * factor;
11649a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
11659a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 9, (u16) (value & 0xffff));
11669a0bf528SMauro Carvalho Chehab 	value = 500 * internal * factor;
11679a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
11689a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 11, (u16) (value & 0xffff));
11699a0bf528SMauro Carvalho Chehab 
11709a0bf528SMauro Carvalho Chehab 	value = dib7000p_read_word(state, 0);
11719a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
11729a0bf528SMauro Carvalho Chehab 	dib7000p_read_word(state, 1284);
11739a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 0, (u16) value);
11749a0bf528SMauro Carvalho Chehab 
11759a0bf528SMauro Carvalho Chehab 	return 0;
11769a0bf528SMauro Carvalho Chehab }
11779a0bf528SMauro Carvalho Chehab 
11789a0bf528SMauro Carvalho Chehab static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
11799a0bf528SMauro Carvalho Chehab {
11809a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
11819a0bf528SMauro Carvalho Chehab 	u16 irq_pending = dib7000p_read_word(state, 1284);
11829a0bf528SMauro Carvalho Chehab 
11839a0bf528SMauro Carvalho Chehab 	if (irq_pending & 0x1)
11849a0bf528SMauro Carvalho Chehab 		return 1;
11859a0bf528SMauro Carvalho Chehab 
11869a0bf528SMauro Carvalho Chehab 	if (irq_pending & 0x2)
11879a0bf528SMauro Carvalho Chehab 		return 2;
11889a0bf528SMauro Carvalho Chehab 
11899a0bf528SMauro Carvalho Chehab 	return 0;
11909a0bf528SMauro Carvalho Chehab }
11919a0bf528SMauro Carvalho Chehab 
11929a0bf528SMauro Carvalho Chehab static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
11939a0bf528SMauro Carvalho Chehab {
11949a0bf528SMauro Carvalho Chehab 	static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
11959a0bf528SMauro Carvalho Chehab 	static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
11969a0bf528SMauro Carvalho Chehab 		24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
11979a0bf528SMauro Carvalho Chehab 		53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
11989a0bf528SMauro Carvalho Chehab 		82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
11999a0bf528SMauro Carvalho Chehab 		107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
12009a0bf528SMauro Carvalho Chehab 		128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
12019a0bf528SMauro Carvalho Chehab 		147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
12029a0bf528SMauro Carvalho Chehab 		166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
12039a0bf528SMauro Carvalho Chehab 		183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
12049a0bf528SMauro Carvalho Chehab 		199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
12059a0bf528SMauro Carvalho Chehab 		213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
12069a0bf528SMauro Carvalho Chehab 		225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
12079a0bf528SMauro Carvalho Chehab 		235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
12089a0bf528SMauro Carvalho Chehab 		244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
12099a0bf528SMauro Carvalho Chehab 		250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
12109a0bf528SMauro Carvalho Chehab 		254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
12119a0bf528SMauro Carvalho Chehab 		255, 255, 255, 255, 255, 255
12129a0bf528SMauro Carvalho Chehab 	};
12139a0bf528SMauro Carvalho Chehab 
12149a0bf528SMauro Carvalho Chehab 	u32 xtal = state->cfg.bw->xtal_hz / 1000;
12159a0bf528SMauro Carvalho Chehab 	int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
12169a0bf528SMauro Carvalho Chehab 	int k;
12179a0bf528SMauro Carvalho Chehab 	int coef_re[8], coef_im[8];
12189a0bf528SMauro Carvalho Chehab 	int bw_khz = bw;
12199a0bf528SMauro Carvalho Chehab 	u32 pha;
12209a0bf528SMauro Carvalho Chehab 
12215a0e2a4eSMauro Carvalho Chehab 	dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)\n", f_rel, rf_khz, xtal);
12229a0bf528SMauro Carvalho Chehab 
12239a0bf528SMauro Carvalho Chehab 	if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
12249a0bf528SMauro Carvalho Chehab 		return;
12259a0bf528SMauro Carvalho Chehab 
12269a0bf528SMauro Carvalho Chehab 	bw_khz /= 100;
12279a0bf528SMauro Carvalho Chehab 
12289a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 142, 0x0610);
12299a0bf528SMauro Carvalho Chehab 
12309a0bf528SMauro Carvalho Chehab 	for (k = 0; k < 8; k++) {
12319a0bf528SMauro Carvalho Chehab 		pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
12329a0bf528SMauro Carvalho Chehab 
12339a0bf528SMauro Carvalho Chehab 		if (pha == 0) {
12349a0bf528SMauro Carvalho Chehab 			coef_re[k] = 256;
12359a0bf528SMauro Carvalho Chehab 			coef_im[k] = 0;
12369a0bf528SMauro Carvalho Chehab 		} else if (pha < 256) {
12379a0bf528SMauro Carvalho Chehab 			coef_re[k] = sine[256 - (pha & 0xff)];
12389a0bf528SMauro Carvalho Chehab 			coef_im[k] = sine[pha & 0xff];
12399a0bf528SMauro Carvalho Chehab 		} else if (pha == 256) {
12409a0bf528SMauro Carvalho Chehab 			coef_re[k] = 0;
12419a0bf528SMauro Carvalho Chehab 			coef_im[k] = 256;
12429a0bf528SMauro Carvalho Chehab 		} else if (pha < 512) {
12439a0bf528SMauro Carvalho Chehab 			coef_re[k] = -sine[pha & 0xff];
12449a0bf528SMauro Carvalho Chehab 			coef_im[k] = sine[256 - (pha & 0xff)];
12459a0bf528SMauro Carvalho Chehab 		} else if (pha == 512) {
12469a0bf528SMauro Carvalho Chehab 			coef_re[k] = -256;
12479a0bf528SMauro Carvalho Chehab 			coef_im[k] = 0;
12489a0bf528SMauro Carvalho Chehab 		} else if (pha < 768) {
12499a0bf528SMauro Carvalho Chehab 			coef_re[k] = -sine[256 - (pha & 0xff)];
12509a0bf528SMauro Carvalho Chehab 			coef_im[k] = -sine[pha & 0xff];
12519a0bf528SMauro Carvalho Chehab 		} else if (pha == 768) {
12529a0bf528SMauro Carvalho Chehab 			coef_re[k] = 0;
12539a0bf528SMauro Carvalho Chehab 			coef_im[k] = -256;
12549a0bf528SMauro Carvalho Chehab 		} else {
12559a0bf528SMauro Carvalho Chehab 			coef_re[k] = sine[pha & 0xff];
12569a0bf528SMauro Carvalho Chehab 			coef_im[k] = -sine[256 - (pha & 0xff)];
12579a0bf528SMauro Carvalho Chehab 		}
12589a0bf528SMauro Carvalho Chehab 
12599a0bf528SMauro Carvalho Chehab 		coef_re[k] *= notch[k];
12609a0bf528SMauro Carvalho Chehab 		coef_re[k] += (1 << 14);
12619a0bf528SMauro Carvalho Chehab 		if (coef_re[k] >= (1 << 24))
12629a0bf528SMauro Carvalho Chehab 			coef_re[k] = (1 << 24) - 1;
12639a0bf528SMauro Carvalho Chehab 		coef_re[k] /= (1 << 15);
12649a0bf528SMauro Carvalho Chehab 
12659a0bf528SMauro Carvalho Chehab 		coef_im[k] *= notch[k];
12669a0bf528SMauro Carvalho Chehab 		coef_im[k] += (1 << 14);
12679a0bf528SMauro Carvalho Chehab 		if (coef_im[k] >= (1 << 24))
12689a0bf528SMauro Carvalho Chehab 			coef_im[k] = (1 << 24) - 1;
12699a0bf528SMauro Carvalho Chehab 		coef_im[k] /= (1 << 15);
12709a0bf528SMauro Carvalho Chehab 
12715a0e2a4eSMauro Carvalho Chehab 		dprintk("PALF COEF: %d re: %d im: %d\n", k, coef_re[k], coef_im[k]);
12729a0bf528SMauro Carvalho Chehab 
12739a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
12749a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
12759a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
12769a0bf528SMauro Carvalho Chehab 	}
12779a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 143, 0);
12789a0bf528SMauro Carvalho Chehab }
12799a0bf528SMauro Carvalho Chehab 
12809a0bf528SMauro Carvalho Chehab static int dib7000p_tune(struct dvb_frontend *demod)
12819a0bf528SMauro Carvalho Chehab {
12829a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
12839a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
12849a0bf528SMauro Carvalho Chehab 	u16 tmp = 0;
12859a0bf528SMauro Carvalho Chehab 
12869a0bf528SMauro Carvalho Chehab 	if (ch != NULL)
12879a0bf528SMauro Carvalho Chehab 		dib7000p_set_channel(state, ch, 0);
12889a0bf528SMauro Carvalho Chehab 	else
12899a0bf528SMauro Carvalho Chehab 		return -EINVAL;
12909a0bf528SMauro Carvalho Chehab 
12919a0bf528SMauro Carvalho Chehab 	// restart demod
12929a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, 0x4000);
12939a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, 0x0000);
12949a0bf528SMauro Carvalho Chehab 	msleep(45);
12959a0bf528SMauro Carvalho Chehab 
12969a0bf528SMauro 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 */
12979a0bf528SMauro Carvalho Chehab 	tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
12989a0bf528SMauro Carvalho Chehab 	if (state->sfn_workaround_active) {
12995a0e2a4eSMauro Carvalho Chehab 		dprintk("SFN workaround is active\n");
13009a0bf528SMauro Carvalho Chehab 		tmp |= (1 << 9);
13019a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 166, 0x4000);
13029a0bf528SMauro Carvalho Chehab 	} else {
13039a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 166, 0x0000);
13049a0bf528SMauro Carvalho Chehab 	}
13059a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 29, tmp);
13069a0bf528SMauro Carvalho Chehab 
13079a0bf528SMauro Carvalho Chehab 	// never achieved a lock with that bandwidth so far - wait for osc-freq to update
13089a0bf528SMauro Carvalho Chehab 	if (state->timf == 0)
13099a0bf528SMauro Carvalho Chehab 		msleep(200);
13109a0bf528SMauro Carvalho Chehab 
13119a0bf528SMauro Carvalho Chehab 	/* offset loop parameters */
13129a0bf528SMauro Carvalho Chehab 
13139a0bf528SMauro Carvalho Chehab 	/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
13149a0bf528SMauro Carvalho Chehab 	tmp = (6 << 8) | 0x80;
13159a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
13169a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
13179a0bf528SMauro Carvalho Chehab 		tmp |= (2 << 12);
13189a0bf528SMauro Carvalho Chehab 		break;
13199a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
13209a0bf528SMauro Carvalho Chehab 		tmp |= (3 << 12);
13219a0bf528SMauro Carvalho Chehab 		break;
13229a0bf528SMauro Carvalho Chehab 	default:
13239a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
13249a0bf528SMauro Carvalho Chehab 		tmp |= (4 << 12);
13259a0bf528SMauro Carvalho Chehab 		break;
13269a0bf528SMauro Carvalho Chehab 	}
13279a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 26, tmp);	/* timf_a(6xxx) */
13289a0bf528SMauro Carvalho Chehab 
13299a0bf528SMauro Carvalho Chehab 	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
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, 32, tmp);
13449a0bf528SMauro Carvalho Chehab 
13459a0bf528SMauro Carvalho Chehab 	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
13469a0bf528SMauro Carvalho Chehab 	tmp = (0 << 4);
13479a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
13489a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
13499a0bf528SMauro Carvalho Chehab 		tmp |= 0x6;
13509a0bf528SMauro Carvalho Chehab 		break;
13519a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
13529a0bf528SMauro Carvalho Chehab 		tmp |= 0x7;
13539a0bf528SMauro Carvalho Chehab 		break;
13549a0bf528SMauro Carvalho Chehab 	default:
13559a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
13569a0bf528SMauro Carvalho Chehab 		tmp |= 0x8;
13579a0bf528SMauro Carvalho Chehab 		break;
13589a0bf528SMauro Carvalho Chehab 	}
13599a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 33, tmp);
13609a0bf528SMauro Carvalho Chehab 
13619a0bf528SMauro Carvalho Chehab 	tmp = dib7000p_read_word(state, 509);
13629a0bf528SMauro Carvalho Chehab 	if (!((tmp >> 6) & 0x1)) {
13639a0bf528SMauro Carvalho Chehab 		/* restart the fec */
13649a0bf528SMauro Carvalho Chehab 		tmp = dib7000p_read_word(state, 771);
13659a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 771, tmp | (1 << 1));
13669a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 771, tmp);
13679a0bf528SMauro Carvalho Chehab 		msleep(40);
13689a0bf528SMauro Carvalho Chehab 		tmp = dib7000p_read_word(state, 509);
13699a0bf528SMauro Carvalho Chehab 	}
13709a0bf528SMauro Carvalho Chehab 	// we achieved a lock - it's time to update the osc freq
13719a0bf528SMauro Carvalho Chehab 	if ((tmp >> 6) & 0x1) {
13729a0bf528SMauro Carvalho Chehab 		dib7000p_update_timf(state);
13739a0bf528SMauro Carvalho Chehab 		/* P_timf_alpha += 2 */
13749a0bf528SMauro Carvalho Chehab 		tmp = dib7000p_read_word(state, 26);
13759a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
13769a0bf528SMauro Carvalho Chehab 	}
13779a0bf528SMauro Carvalho Chehab 
13789a0bf528SMauro Carvalho Chehab 	if (state->cfg.spur_protect)
13799a0bf528SMauro Carvalho Chehab 		dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
13809a0bf528SMauro Carvalho Chehab 
13819a0bf528SMauro Carvalho Chehab 	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
1382041ad449SMauro Carvalho Chehab 
1383041ad449SMauro Carvalho Chehab 	dib7000p_reset_stats(demod);
1384041ad449SMauro Carvalho Chehab 
13859a0bf528SMauro Carvalho Chehab 	return 0;
13869a0bf528SMauro Carvalho Chehab }
13879a0bf528SMauro Carvalho Chehab 
13889a0bf528SMauro Carvalho Chehab static int dib7000p_wakeup(struct dvb_frontend *demod)
13899a0bf528SMauro Carvalho Chehab {
13909a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
13919a0bf528SMauro Carvalho Chehab 	dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
13929a0bf528SMauro Carvalho Chehab 	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
13939a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090)
13949a0bf528SMauro Carvalho Chehab 		dib7000p_sad_calib(state);
13959a0bf528SMauro Carvalho Chehab 	return 0;
13969a0bf528SMauro Carvalho Chehab }
13979a0bf528SMauro Carvalho Chehab 
13989a0bf528SMauro Carvalho Chehab static int dib7000p_sleep(struct dvb_frontend *demod)
13999a0bf528SMauro Carvalho Chehab {
14009a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
14019a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090)
14029a0bf528SMauro Carvalho Chehab 		return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
14039a0bf528SMauro Carvalho Chehab 	return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
14049a0bf528SMauro Carvalho Chehab }
14059a0bf528SMauro Carvalho Chehab 
14069a0bf528SMauro Carvalho Chehab static int dib7000p_identify(struct dib7000p_state *st)
14079a0bf528SMauro Carvalho Chehab {
14089a0bf528SMauro Carvalho Chehab 	u16 value;
14095a0e2a4eSMauro Carvalho Chehab 	dprintk("checking demod on I2C address: %d (%x)\n", st->i2c_addr, st->i2c_addr);
14109a0bf528SMauro Carvalho Chehab 
14119a0bf528SMauro Carvalho Chehab 	if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
14125a0e2a4eSMauro Carvalho Chehab 		dprintk("wrong Vendor ID (read=0x%x)\n", value);
14139a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO;
14149a0bf528SMauro Carvalho Chehab 	}
14159a0bf528SMauro Carvalho Chehab 
14169a0bf528SMauro Carvalho Chehab 	if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
14175a0e2a4eSMauro Carvalho Chehab 		dprintk("wrong Device ID (%x)\n", value);
14189a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO;
14199a0bf528SMauro Carvalho Chehab 	}
14209a0bf528SMauro Carvalho Chehab 
14219a0bf528SMauro Carvalho Chehab 	return 0;
14229a0bf528SMauro Carvalho Chehab }
14239a0bf528SMauro Carvalho Chehab 
14247e3e68bcSMauro Carvalho Chehab static int dib7000p_get_frontend(struct dvb_frontend *fe,
14257e3e68bcSMauro Carvalho Chehab 				 struct dtv_frontend_properties *fep)
14269a0bf528SMauro Carvalho Chehab {
14279a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
14289a0bf528SMauro Carvalho Chehab 	u16 tps = dib7000p_read_word(state, 463);
14299a0bf528SMauro Carvalho Chehab 
14309a0bf528SMauro Carvalho Chehab 	fep->inversion = INVERSION_AUTO;
14319a0bf528SMauro Carvalho Chehab 
14329a0bf528SMauro Carvalho Chehab 	fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
14339a0bf528SMauro Carvalho Chehab 
14349a0bf528SMauro Carvalho Chehab 	switch ((tps >> 8) & 0x3) {
14359a0bf528SMauro Carvalho Chehab 	case 0:
14369a0bf528SMauro Carvalho Chehab 		fep->transmission_mode = TRANSMISSION_MODE_2K;
14379a0bf528SMauro Carvalho Chehab 		break;
14389a0bf528SMauro Carvalho Chehab 	case 1:
14399a0bf528SMauro Carvalho Chehab 		fep->transmission_mode = TRANSMISSION_MODE_8K;
14409a0bf528SMauro Carvalho Chehab 		break;
14419a0bf528SMauro Carvalho Chehab 	/* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
14429a0bf528SMauro Carvalho Chehab 	}
14439a0bf528SMauro Carvalho Chehab 
14449a0bf528SMauro Carvalho Chehab 	switch (tps & 0x3) {
14459a0bf528SMauro Carvalho Chehab 	case 0:
14469a0bf528SMauro Carvalho Chehab 		fep->guard_interval = GUARD_INTERVAL_1_32;
14479a0bf528SMauro Carvalho Chehab 		break;
14489a0bf528SMauro Carvalho Chehab 	case 1:
14499a0bf528SMauro Carvalho Chehab 		fep->guard_interval = GUARD_INTERVAL_1_16;
14509a0bf528SMauro Carvalho Chehab 		break;
14519a0bf528SMauro Carvalho Chehab 	case 2:
14529a0bf528SMauro Carvalho Chehab 		fep->guard_interval = GUARD_INTERVAL_1_8;
14539a0bf528SMauro Carvalho Chehab 		break;
14549a0bf528SMauro Carvalho Chehab 	case 3:
14559a0bf528SMauro Carvalho Chehab 		fep->guard_interval = GUARD_INTERVAL_1_4;
14569a0bf528SMauro Carvalho Chehab 		break;
14579a0bf528SMauro Carvalho Chehab 	}
14589a0bf528SMauro Carvalho Chehab 
14599a0bf528SMauro Carvalho Chehab 	switch ((tps >> 14) & 0x3) {
14609a0bf528SMauro Carvalho Chehab 	case 0:
14619a0bf528SMauro Carvalho Chehab 		fep->modulation = QPSK;
14629a0bf528SMauro Carvalho Chehab 		break;
14639a0bf528SMauro Carvalho Chehab 	case 1:
14649a0bf528SMauro Carvalho Chehab 		fep->modulation = QAM_16;
14659a0bf528SMauro Carvalho Chehab 		break;
14669a0bf528SMauro Carvalho Chehab 	case 2:
14679a0bf528SMauro Carvalho Chehab 	default:
14689a0bf528SMauro Carvalho Chehab 		fep->modulation = QAM_64;
14699a0bf528SMauro Carvalho Chehab 		break;
14709a0bf528SMauro Carvalho Chehab 	}
14719a0bf528SMauro Carvalho Chehab 
14729a0bf528SMauro Carvalho Chehab 	/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
14739a0bf528SMauro Carvalho Chehab 	/* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
14749a0bf528SMauro Carvalho Chehab 
14759a0bf528SMauro Carvalho Chehab 	fep->hierarchy = HIERARCHY_NONE;
14769a0bf528SMauro Carvalho Chehab 	switch ((tps >> 5) & 0x7) {
14779a0bf528SMauro Carvalho Chehab 	case 1:
14789a0bf528SMauro Carvalho Chehab 		fep->code_rate_HP = FEC_1_2;
14799a0bf528SMauro Carvalho Chehab 		break;
14809a0bf528SMauro Carvalho Chehab 	case 2:
14819a0bf528SMauro Carvalho Chehab 		fep->code_rate_HP = FEC_2_3;
14829a0bf528SMauro Carvalho Chehab 		break;
14839a0bf528SMauro Carvalho Chehab 	case 3:
14849a0bf528SMauro Carvalho Chehab 		fep->code_rate_HP = FEC_3_4;
14859a0bf528SMauro Carvalho Chehab 		break;
14869a0bf528SMauro Carvalho Chehab 	case 5:
14879a0bf528SMauro Carvalho Chehab 		fep->code_rate_HP = FEC_5_6;
14889a0bf528SMauro Carvalho Chehab 		break;
14899a0bf528SMauro Carvalho Chehab 	case 7:
14909a0bf528SMauro Carvalho Chehab 	default:
14919a0bf528SMauro Carvalho Chehab 		fep->code_rate_HP = FEC_7_8;
14929a0bf528SMauro Carvalho Chehab 		break;
14939a0bf528SMauro Carvalho Chehab 
14949a0bf528SMauro Carvalho Chehab 	}
14959a0bf528SMauro Carvalho Chehab 
14969a0bf528SMauro Carvalho Chehab 	switch ((tps >> 2) & 0x7) {
14979a0bf528SMauro Carvalho Chehab 	case 1:
14989a0bf528SMauro Carvalho Chehab 		fep->code_rate_LP = FEC_1_2;
14999a0bf528SMauro Carvalho Chehab 		break;
15009a0bf528SMauro Carvalho Chehab 	case 2:
15019a0bf528SMauro Carvalho Chehab 		fep->code_rate_LP = FEC_2_3;
15029a0bf528SMauro Carvalho Chehab 		break;
15039a0bf528SMauro Carvalho Chehab 	case 3:
15049a0bf528SMauro Carvalho Chehab 		fep->code_rate_LP = FEC_3_4;
15059a0bf528SMauro Carvalho Chehab 		break;
15069a0bf528SMauro Carvalho Chehab 	case 5:
15079a0bf528SMauro Carvalho Chehab 		fep->code_rate_LP = FEC_5_6;
15089a0bf528SMauro Carvalho Chehab 		break;
15099a0bf528SMauro Carvalho Chehab 	case 7:
15109a0bf528SMauro Carvalho Chehab 	default:
15119a0bf528SMauro Carvalho Chehab 		fep->code_rate_LP = FEC_7_8;
15129a0bf528SMauro Carvalho Chehab 		break;
15139a0bf528SMauro Carvalho Chehab 	}
15149a0bf528SMauro Carvalho Chehab 
15159a0bf528SMauro Carvalho Chehab 	/* native interleaver: (dib7000p_read_word(state, 464) >>  5) & 0x1 */
15169a0bf528SMauro Carvalho Chehab 
15179a0bf528SMauro Carvalho Chehab 	return 0;
15189a0bf528SMauro Carvalho Chehab }
15199a0bf528SMauro Carvalho Chehab 
15209a0bf528SMauro Carvalho Chehab static int dib7000p_set_frontend(struct dvb_frontend *fe)
15219a0bf528SMauro Carvalho Chehab {
15229a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
15239a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
15249a0bf528SMauro Carvalho Chehab 	int time, ret;
15259a0bf528SMauro Carvalho Chehab 
15269a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090)
15279a0bf528SMauro Carvalho Chehab 		dib7090_set_diversity_in(fe, 0);
15289a0bf528SMauro Carvalho Chehab 	else
15299a0bf528SMauro Carvalho Chehab 		dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
15309a0bf528SMauro Carvalho Chehab 
15319a0bf528SMauro Carvalho Chehab 	/* maybe the parameter has been changed */
15329a0bf528SMauro Carvalho Chehab 	state->sfn_workaround_active = buggy_sfn_workaround;
15339a0bf528SMauro Carvalho Chehab 
15349a0bf528SMauro Carvalho Chehab 	if (fe->ops.tuner_ops.set_params)
15359a0bf528SMauro Carvalho Chehab 		fe->ops.tuner_ops.set_params(fe);
15369a0bf528SMauro Carvalho Chehab 
15379a0bf528SMauro Carvalho Chehab 	/* start up the AGC */
15389a0bf528SMauro Carvalho Chehab 	state->agc_state = 0;
15399a0bf528SMauro Carvalho Chehab 	do {
15409a0bf528SMauro Carvalho Chehab 		time = dib7000p_agc_startup(fe);
15419a0bf528SMauro Carvalho Chehab 		if (time != -1)
15429a0bf528SMauro Carvalho Chehab 			msleep(time);
15439a0bf528SMauro Carvalho Chehab 	} while (time != -1);
15449a0bf528SMauro Carvalho Chehab 
15459a0bf528SMauro Carvalho Chehab 	if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
15469a0bf528SMauro Carvalho Chehab 		fep->guard_interval == GUARD_INTERVAL_AUTO || fep->modulation == QAM_AUTO || fep->code_rate_HP == FEC_AUTO) {
15479a0bf528SMauro Carvalho Chehab 		int i = 800, found;
15489a0bf528SMauro Carvalho Chehab 
15499a0bf528SMauro Carvalho Chehab 		dib7000p_autosearch_start(fe);
15509a0bf528SMauro Carvalho Chehab 		do {
15519a0bf528SMauro Carvalho Chehab 			msleep(1);
15529a0bf528SMauro Carvalho Chehab 			found = dib7000p_autosearch_is_irq(fe);
15539a0bf528SMauro Carvalho Chehab 		} while (found == 0 && i--);
15549a0bf528SMauro Carvalho Chehab 
15555a0e2a4eSMauro Carvalho Chehab 		dprintk("autosearch returns: %d\n", found);
15569a0bf528SMauro Carvalho Chehab 		if (found == 0 || found == 1)
15579a0bf528SMauro Carvalho Chehab 			return 0;
15589a0bf528SMauro Carvalho Chehab 
15597e3e68bcSMauro Carvalho Chehab 		dib7000p_get_frontend(fe, fep);
15609a0bf528SMauro Carvalho Chehab 	}
15619a0bf528SMauro Carvalho Chehab 
15629a0bf528SMauro Carvalho Chehab 	ret = dib7000p_tune(fe);
15639a0bf528SMauro Carvalho Chehab 
15649a0bf528SMauro Carvalho Chehab 	/* make this a config parameter */
15659a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090) {
15669a0bf528SMauro Carvalho Chehab 		dib7090_set_output_mode(fe, state->cfg.output_mode);
15679a0bf528SMauro Carvalho Chehab 		if (state->cfg.enMpegOutput == 0) {
15689a0bf528SMauro Carvalho Chehab 			dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
15699a0bf528SMauro Carvalho Chehab 			dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
15709a0bf528SMauro Carvalho Chehab 		}
15719a0bf528SMauro Carvalho Chehab 	} else
15729a0bf528SMauro Carvalho Chehab 		dib7000p_set_output_mode(state, state->cfg.output_mode);
15739a0bf528SMauro Carvalho Chehab 
15749a0bf528SMauro Carvalho Chehab 	return ret;
15759a0bf528SMauro Carvalho Chehab }
15769a0bf528SMauro Carvalho Chehab 
15770df289a2SMauro Carvalho Chehab static int dib7000p_get_stats(struct dvb_frontend *fe, enum fe_status stat);
1578041ad449SMauro Carvalho Chehab 
15790df289a2SMauro Carvalho Chehab static int dib7000p_read_status(struct dvb_frontend *fe, enum fe_status *stat)
15809a0bf528SMauro Carvalho Chehab {
15819a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
15829a0bf528SMauro Carvalho Chehab 	u16 lock = dib7000p_read_word(state, 509);
15839a0bf528SMauro Carvalho Chehab 
15849a0bf528SMauro Carvalho Chehab 	*stat = 0;
15859a0bf528SMauro Carvalho Chehab 
15869a0bf528SMauro Carvalho Chehab 	if (lock & 0x8000)
15879a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SIGNAL;
15889a0bf528SMauro Carvalho Chehab 	if (lock & 0x3000)
15899a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_CARRIER;
15909a0bf528SMauro Carvalho Chehab 	if (lock & 0x0100)
15919a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_VITERBI;
15929a0bf528SMauro Carvalho Chehab 	if (lock & 0x0010)
15939a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SYNC;
15949a0bf528SMauro Carvalho Chehab 	if ((lock & 0x0038) == 0x38)
15959a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_LOCK;
15969a0bf528SMauro Carvalho Chehab 
1597041ad449SMauro Carvalho Chehab 	dib7000p_get_stats(fe, *stat);
1598041ad449SMauro Carvalho Chehab 
15999a0bf528SMauro Carvalho Chehab 	return 0;
16009a0bf528SMauro Carvalho Chehab }
16019a0bf528SMauro Carvalho Chehab 
16029a0bf528SMauro Carvalho Chehab static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
16039a0bf528SMauro Carvalho Chehab {
16049a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
16059a0bf528SMauro Carvalho Chehab 	*ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
16069a0bf528SMauro Carvalho Chehab 	return 0;
16079a0bf528SMauro Carvalho Chehab }
16089a0bf528SMauro Carvalho Chehab 
16099a0bf528SMauro Carvalho Chehab static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
16109a0bf528SMauro Carvalho Chehab {
16119a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
16129a0bf528SMauro Carvalho Chehab 	*unc = dib7000p_read_word(state, 506);
16139a0bf528SMauro Carvalho Chehab 	return 0;
16149a0bf528SMauro Carvalho Chehab }
16159a0bf528SMauro Carvalho Chehab 
16169a0bf528SMauro Carvalho Chehab static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
16179a0bf528SMauro Carvalho Chehab {
16189a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
16199a0bf528SMauro Carvalho Chehab 	u16 val = dib7000p_read_word(state, 394);
16209a0bf528SMauro Carvalho Chehab 	*strength = 65535 - val;
16219a0bf528SMauro Carvalho Chehab 	return 0;
16229a0bf528SMauro Carvalho Chehab }
16239a0bf528SMauro Carvalho Chehab 
1624041ad449SMauro Carvalho Chehab static u32 dib7000p_get_snr(struct dvb_frontend *fe)
16259a0bf528SMauro Carvalho Chehab {
16269a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
16279a0bf528SMauro Carvalho Chehab 	u16 val;
16289a0bf528SMauro Carvalho Chehab 	s32 signal_mant, signal_exp, noise_mant, noise_exp;
16299a0bf528SMauro Carvalho Chehab 	u32 result = 0;
16309a0bf528SMauro Carvalho Chehab 
16319a0bf528SMauro Carvalho Chehab 	val = dib7000p_read_word(state, 479);
16329a0bf528SMauro Carvalho Chehab 	noise_mant = (val >> 4) & 0xff;
16339a0bf528SMauro Carvalho Chehab 	noise_exp = ((val & 0xf) << 2);
16349a0bf528SMauro Carvalho Chehab 	val = dib7000p_read_word(state, 480);
16359a0bf528SMauro Carvalho Chehab 	noise_exp += ((val >> 14) & 0x3);
16369a0bf528SMauro Carvalho Chehab 	if ((noise_exp & 0x20) != 0)
16379a0bf528SMauro Carvalho Chehab 		noise_exp -= 0x40;
16389a0bf528SMauro Carvalho Chehab 
16399a0bf528SMauro Carvalho Chehab 	signal_mant = (val >> 6) & 0xFF;
16409a0bf528SMauro Carvalho Chehab 	signal_exp = (val & 0x3F);
16419a0bf528SMauro Carvalho Chehab 	if ((signal_exp & 0x20) != 0)
16429a0bf528SMauro Carvalho Chehab 		signal_exp -= 0x40;
16439a0bf528SMauro Carvalho Chehab 
16449a0bf528SMauro Carvalho Chehab 	if (signal_mant != 0)
16459a0bf528SMauro Carvalho Chehab 		result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
16469a0bf528SMauro Carvalho Chehab 	else
16479a0bf528SMauro Carvalho Chehab 		result = intlog10(2) * 10 * signal_exp - 100;
16489a0bf528SMauro Carvalho Chehab 
16499a0bf528SMauro Carvalho Chehab 	if (noise_mant != 0)
16509a0bf528SMauro Carvalho Chehab 		result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
16519a0bf528SMauro Carvalho Chehab 	else
16529a0bf528SMauro Carvalho Chehab 		result -= intlog10(2) * 10 * noise_exp - 100;
16539a0bf528SMauro Carvalho Chehab 
1654041ad449SMauro Carvalho Chehab 	return result;
1655041ad449SMauro Carvalho Chehab }
1656041ad449SMauro Carvalho Chehab 
1657041ad449SMauro Carvalho Chehab static int dib7000p_read_snr(struct dvb_frontend *fe, u16 *snr)
1658041ad449SMauro Carvalho Chehab {
1659041ad449SMauro Carvalho Chehab 	u32 result;
1660041ad449SMauro Carvalho Chehab 
1661041ad449SMauro Carvalho Chehab 	result = dib7000p_get_snr(fe);
1662041ad449SMauro Carvalho Chehab 
16639a0bf528SMauro Carvalho Chehab 	*snr = result / ((1 << 24) / 10);
16649a0bf528SMauro Carvalho Chehab 	return 0;
16659a0bf528SMauro Carvalho Chehab }
16669a0bf528SMauro Carvalho Chehab 
1667041ad449SMauro Carvalho Chehab static void dib7000p_reset_stats(struct dvb_frontend *demod)
1668041ad449SMauro Carvalho Chehab {
1669041ad449SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
1670041ad449SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1671041ad449SMauro Carvalho Chehab 	u32 ucb;
1672041ad449SMauro Carvalho Chehab 
1673041ad449SMauro Carvalho Chehab 	memset(&c->strength, 0, sizeof(c->strength));
1674041ad449SMauro Carvalho Chehab 	memset(&c->cnr, 0, sizeof(c->cnr));
1675041ad449SMauro Carvalho Chehab 	memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
1676041ad449SMauro Carvalho Chehab 	memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
1677041ad449SMauro Carvalho Chehab 	memset(&c->block_error, 0, sizeof(c->block_error));
1678041ad449SMauro Carvalho Chehab 
1679041ad449SMauro Carvalho Chehab 	c->strength.len = 1;
1680041ad449SMauro Carvalho Chehab 	c->cnr.len = 1;
1681041ad449SMauro Carvalho Chehab 	c->block_error.len = 1;
1682041ad449SMauro Carvalho Chehab 	c->block_count.len = 1;
1683041ad449SMauro Carvalho Chehab 	c->post_bit_error.len = 1;
1684041ad449SMauro Carvalho Chehab 	c->post_bit_count.len = 1;
1685041ad449SMauro Carvalho Chehab 
1686041ad449SMauro Carvalho Chehab 	c->strength.stat[0].scale = FE_SCALE_DECIBEL;
1687041ad449SMauro Carvalho Chehab 	c->strength.stat[0].uvalue = 0;
1688041ad449SMauro Carvalho Chehab 
1689041ad449SMauro Carvalho Chehab 	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1690041ad449SMauro Carvalho Chehab 	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1691041ad449SMauro Carvalho Chehab 	c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1692041ad449SMauro Carvalho Chehab 	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1693041ad449SMauro Carvalho Chehab 	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1694041ad449SMauro Carvalho Chehab 
1695041ad449SMauro Carvalho Chehab 	dib7000p_read_unc_blocks(demod, &ucb);
1696041ad449SMauro Carvalho Chehab 
1697041ad449SMauro Carvalho Chehab 	state->old_ucb = ucb;
1698041ad449SMauro Carvalho Chehab 	state->ber_jiffies_stats = 0;
1699041ad449SMauro Carvalho Chehab 	state->per_jiffies_stats = 0;
1700041ad449SMauro Carvalho Chehab }
1701041ad449SMauro Carvalho Chehab 
1702041ad449SMauro Carvalho Chehab struct linear_segments {
1703041ad449SMauro Carvalho Chehab 	unsigned x;
1704041ad449SMauro Carvalho Chehab 	signed y;
1705041ad449SMauro Carvalho Chehab };
1706041ad449SMauro Carvalho Chehab 
1707041ad449SMauro Carvalho Chehab /*
1708041ad449SMauro Carvalho Chehab  * Table to estimate signal strength in dBm.
1709041ad449SMauro Carvalho Chehab  * This table should be empirically determinated by measuring the signal
1710041ad449SMauro Carvalho Chehab  * strength generated by a RF generator directly connected into
1711041ad449SMauro Carvalho Chehab  * a device.
17123926d91aSMauro Carvalho Chehab  * This table was determinated by measuring the signal strength generated
17133926d91aSMauro Carvalho Chehab  * by a DTA-2111 RF generator directly connected into a dib7000p device
17143926d91aSMauro Carvalho Chehab  * (a Hauppauge Nova-TD stick), using a good quality 3 meters length
17153926d91aSMauro Carvalho Chehab  * RC6 cable and good RC6 connectors, connected directly to antenna 1.
17163926d91aSMauro Carvalho Chehab  * As the minimum output power of DTA-2111 is -31dBm, a 16 dBm attenuator
17173926d91aSMauro Carvalho Chehab  * were used, for the lower power values.
17183926d91aSMauro Carvalho Chehab  * The real value can actually be on other devices, or even at the
17193926d91aSMauro Carvalho Chehab  * second antena input, depending on several factors, like if LNA
17203926d91aSMauro Carvalho Chehab  * is enabled or not, if diversity is enabled, type of connectors, etc.
17213926d91aSMauro Carvalho Chehab  * Yet, it is better to use this measure in dB than a random non-linear
17223926d91aSMauro Carvalho Chehab  * percentage value, especially for antenna adjustments.
17233926d91aSMauro Carvalho Chehab  * On my tests, the precision of the measure using this table is about
17243926d91aSMauro Carvalho Chehab  * 0.5 dB, with sounds reasonable enough to adjust antennas.
1725041ad449SMauro Carvalho Chehab  */
17263926d91aSMauro Carvalho Chehab #define DB_OFFSET 131000
1727041ad449SMauro Carvalho Chehab 
1728041ad449SMauro Carvalho Chehab static struct linear_segments strength_to_db_table[] = {
17293926d91aSMauro Carvalho Chehab 	{ 63630, DB_OFFSET - 20500},
17303926d91aSMauro Carvalho Chehab 	{ 62273, DB_OFFSET - 21000},
17313926d91aSMauro Carvalho Chehab 	{ 60162, DB_OFFSET - 22000},
17323926d91aSMauro Carvalho Chehab 	{ 58730, DB_OFFSET - 23000},
17333926d91aSMauro Carvalho Chehab 	{ 58294, DB_OFFSET - 24000},
17343926d91aSMauro Carvalho Chehab 	{ 57778, DB_OFFSET - 25000},
17353926d91aSMauro Carvalho Chehab 	{ 57320, DB_OFFSET - 26000},
17363926d91aSMauro Carvalho Chehab 	{ 56779, DB_OFFSET - 27000},
17373926d91aSMauro Carvalho Chehab 	{ 56293, DB_OFFSET - 28000},
17383926d91aSMauro Carvalho Chehab 	{ 55724, DB_OFFSET - 29000},
17393926d91aSMauro Carvalho Chehab 	{ 55145, DB_OFFSET - 30000},
17403926d91aSMauro Carvalho Chehab 	{ 54680, DB_OFFSET - 31000},
17413926d91aSMauro Carvalho Chehab 	{ 54293, DB_OFFSET - 32000},
17423926d91aSMauro Carvalho Chehab 	{ 53813, DB_OFFSET - 33000},
17433926d91aSMauro Carvalho Chehab 	{ 53427, DB_OFFSET - 34000},
17443926d91aSMauro Carvalho Chehab 	{ 52981, DB_OFFSET - 35000},
17453926d91aSMauro Carvalho Chehab 
17463926d91aSMauro Carvalho Chehab 	{ 52636, DB_OFFSET - 36000},
17473926d91aSMauro Carvalho Chehab 	{ 52014, DB_OFFSET - 37000},
17483926d91aSMauro Carvalho Chehab 	{ 51674, DB_OFFSET - 38000},
17493926d91aSMauro Carvalho Chehab 	{ 50692, DB_OFFSET - 39000},
17503926d91aSMauro Carvalho Chehab 	{ 49824, DB_OFFSET - 40000},
17513926d91aSMauro Carvalho Chehab 	{ 49052, DB_OFFSET - 41000},
17523926d91aSMauro Carvalho Chehab 	{ 48436, DB_OFFSET - 42000},
17533926d91aSMauro Carvalho Chehab 	{ 47836, DB_OFFSET - 43000},
17543926d91aSMauro Carvalho Chehab 	{ 47368, DB_OFFSET - 44000},
17553926d91aSMauro Carvalho Chehab 	{ 46468, DB_OFFSET - 45000},
17563926d91aSMauro Carvalho Chehab 	{ 45597, DB_OFFSET - 46000},
17573926d91aSMauro Carvalho Chehab 	{ 44586, DB_OFFSET - 47000},
17583926d91aSMauro Carvalho Chehab 	{ 43667, DB_OFFSET - 48000},
17593926d91aSMauro Carvalho Chehab 	{ 42673, DB_OFFSET - 49000},
17603926d91aSMauro Carvalho Chehab 	{ 41816, DB_OFFSET - 50000},
17613926d91aSMauro Carvalho Chehab 	{ 40876, DB_OFFSET - 51000},
1762041ad449SMauro Carvalho Chehab 	{     0,      0},
1763041ad449SMauro Carvalho Chehab };
1764041ad449SMauro Carvalho Chehab 
1765041ad449SMauro Carvalho Chehab static u32 interpolate_value(u32 value, struct linear_segments *segments,
1766041ad449SMauro Carvalho Chehab 			     unsigned len)
1767041ad449SMauro Carvalho Chehab {
1768041ad449SMauro Carvalho Chehab 	u64 tmp64;
1769041ad449SMauro Carvalho Chehab 	u32 dx;
1770041ad449SMauro Carvalho Chehab 	s32 dy;
1771041ad449SMauro Carvalho Chehab 	int i, ret;
1772041ad449SMauro Carvalho Chehab 
1773041ad449SMauro Carvalho Chehab 	if (value >= segments[0].x)
1774041ad449SMauro Carvalho Chehab 		return segments[0].y;
1775041ad449SMauro Carvalho Chehab 	if (value < segments[len-1].x)
1776041ad449SMauro Carvalho Chehab 		return segments[len-1].y;
1777041ad449SMauro Carvalho Chehab 
1778041ad449SMauro Carvalho Chehab 	for (i = 1; i < len - 1; i++) {
1779041ad449SMauro Carvalho Chehab 		/* If value is identical, no need to interpolate */
1780041ad449SMauro Carvalho Chehab 		if (value == segments[i].x)
1781041ad449SMauro Carvalho Chehab 			return segments[i].y;
1782041ad449SMauro Carvalho Chehab 		if (value > segments[i].x)
1783041ad449SMauro Carvalho Chehab 			break;
1784041ad449SMauro Carvalho Chehab 	}
1785041ad449SMauro Carvalho Chehab 
1786041ad449SMauro Carvalho Chehab 	/* Linear interpolation between the two (x,y) points */
1787041ad449SMauro Carvalho Chehab 	dy = segments[i - 1].y - segments[i].y;
1788041ad449SMauro Carvalho Chehab 	dx = segments[i - 1].x - segments[i].x;
1789041ad449SMauro Carvalho Chehab 
1790041ad449SMauro Carvalho Chehab 	tmp64 = value - segments[i].x;
1791041ad449SMauro Carvalho Chehab 	tmp64 *= dy;
1792041ad449SMauro Carvalho Chehab 	do_div(tmp64, dx);
1793041ad449SMauro Carvalho Chehab 	ret = segments[i].y + tmp64;
1794041ad449SMauro Carvalho Chehab 
1795041ad449SMauro Carvalho Chehab 	return ret;
1796041ad449SMauro Carvalho Chehab }
1797041ad449SMauro Carvalho Chehab 
1798041ad449SMauro Carvalho Chehab /* FIXME: may require changes - this one was borrowed from dib8000 */
1799986f1686SMauro Carvalho Chehab static u32 dib7000p_get_time_us(struct dvb_frontend *demod)
1800041ad449SMauro Carvalho Chehab {
1801041ad449SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1802041ad449SMauro Carvalho Chehab 	u64 time_us, tmp64;
1803041ad449SMauro Carvalho Chehab 	u32 tmp, denom;
1804041ad449SMauro Carvalho Chehab 	int guard, rate_num, rate_denum = 1, bits_per_symbol;
1805041ad449SMauro Carvalho Chehab 	int interleaving = 0, fft_div;
1806041ad449SMauro Carvalho Chehab 
1807041ad449SMauro Carvalho Chehab 	switch (c->guard_interval) {
1808041ad449SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_4:
1809041ad449SMauro Carvalho Chehab 		guard = 4;
1810041ad449SMauro Carvalho Chehab 		break;
1811041ad449SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_8:
1812041ad449SMauro Carvalho Chehab 		guard = 8;
1813041ad449SMauro Carvalho Chehab 		break;
1814041ad449SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_16:
1815041ad449SMauro Carvalho Chehab 		guard = 16;
1816041ad449SMauro Carvalho Chehab 		break;
1817041ad449SMauro Carvalho Chehab 	default:
1818041ad449SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_32:
1819041ad449SMauro Carvalho Chehab 		guard = 32;
1820041ad449SMauro Carvalho Chehab 		break;
1821041ad449SMauro Carvalho Chehab 	}
1822041ad449SMauro Carvalho Chehab 
1823041ad449SMauro Carvalho Chehab 	switch (c->transmission_mode) {
1824041ad449SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
1825041ad449SMauro Carvalho Chehab 		fft_div = 4;
1826041ad449SMauro Carvalho Chehab 		break;
1827041ad449SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
1828041ad449SMauro Carvalho Chehab 		fft_div = 2;
1829041ad449SMauro Carvalho Chehab 		break;
1830041ad449SMauro Carvalho Chehab 	default:
1831041ad449SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
1832041ad449SMauro Carvalho Chehab 		fft_div = 1;
1833041ad449SMauro Carvalho Chehab 		break;
1834041ad449SMauro Carvalho Chehab 	}
1835041ad449SMauro Carvalho Chehab 
1836041ad449SMauro Carvalho Chehab 	switch (c->modulation) {
1837041ad449SMauro Carvalho Chehab 	case DQPSK:
1838041ad449SMauro Carvalho Chehab 	case QPSK:
1839041ad449SMauro Carvalho Chehab 		bits_per_symbol = 2;
1840041ad449SMauro Carvalho Chehab 		break;
1841041ad449SMauro Carvalho Chehab 	case QAM_16:
1842041ad449SMauro Carvalho Chehab 		bits_per_symbol = 4;
1843041ad449SMauro Carvalho Chehab 		break;
1844041ad449SMauro Carvalho Chehab 	default:
1845041ad449SMauro Carvalho Chehab 	case QAM_64:
1846041ad449SMauro Carvalho Chehab 		bits_per_symbol = 6;
1847041ad449SMauro Carvalho Chehab 		break;
1848041ad449SMauro Carvalho Chehab 	}
1849041ad449SMauro Carvalho Chehab 
1850041ad449SMauro Carvalho Chehab 	switch ((c->hierarchy == 0 || 1 == 1) ? c->code_rate_HP : c->code_rate_LP) {
1851041ad449SMauro Carvalho Chehab 	case FEC_1_2:
1852041ad449SMauro Carvalho Chehab 		rate_num = 1;
1853041ad449SMauro Carvalho Chehab 		rate_denum = 2;
1854041ad449SMauro Carvalho Chehab 		break;
1855041ad449SMauro Carvalho Chehab 	case FEC_2_3:
1856041ad449SMauro Carvalho Chehab 		rate_num = 2;
1857041ad449SMauro Carvalho Chehab 		rate_denum = 3;
1858041ad449SMauro Carvalho Chehab 		break;
1859041ad449SMauro Carvalho Chehab 	case FEC_3_4:
1860041ad449SMauro Carvalho Chehab 		rate_num = 3;
1861041ad449SMauro Carvalho Chehab 		rate_denum = 4;
1862041ad449SMauro Carvalho Chehab 		break;
1863041ad449SMauro Carvalho Chehab 	case FEC_5_6:
1864041ad449SMauro Carvalho Chehab 		rate_num = 5;
1865041ad449SMauro Carvalho Chehab 		rate_denum = 6;
1866041ad449SMauro Carvalho Chehab 		break;
1867041ad449SMauro Carvalho Chehab 	default:
1868041ad449SMauro Carvalho Chehab 	case FEC_7_8:
1869041ad449SMauro Carvalho Chehab 		rate_num = 7;
1870041ad449SMauro Carvalho Chehab 		rate_denum = 8;
1871041ad449SMauro Carvalho Chehab 		break;
1872041ad449SMauro Carvalho Chehab 	}
1873041ad449SMauro Carvalho Chehab 
1874041ad449SMauro Carvalho Chehab 	interleaving = interleaving;
1875041ad449SMauro Carvalho Chehab 
1876041ad449SMauro Carvalho Chehab 	denom = bits_per_symbol * rate_num * fft_div * 384;
1877041ad449SMauro Carvalho Chehab 
1878041ad449SMauro Carvalho Chehab 	/* If calculus gets wrong, wait for 1s for the next stats */
1879041ad449SMauro Carvalho Chehab 	if (!denom)
1880041ad449SMauro Carvalho Chehab 		return 0;
1881041ad449SMauro Carvalho Chehab 
1882041ad449SMauro Carvalho Chehab 	/* Estimate the period for the total bit rate */
1883041ad449SMauro Carvalho Chehab 	time_us = rate_denum * (1008 * 1562500L);
1884041ad449SMauro Carvalho Chehab 	tmp64 = time_us;
1885041ad449SMauro Carvalho Chehab 	do_div(tmp64, guard);
1886041ad449SMauro Carvalho Chehab 	time_us = time_us + tmp64;
1887041ad449SMauro Carvalho Chehab 	time_us += denom / 2;
1888041ad449SMauro Carvalho Chehab 	do_div(time_us, denom);
1889041ad449SMauro Carvalho Chehab 
1890041ad449SMauro Carvalho Chehab 	tmp = 1008 * 96 * interleaving;
1891041ad449SMauro Carvalho Chehab 	time_us += tmp + tmp / guard;
1892041ad449SMauro Carvalho Chehab 
1893041ad449SMauro Carvalho Chehab 	return time_us;
1894041ad449SMauro Carvalho Chehab }
1895041ad449SMauro Carvalho Chehab 
18960df289a2SMauro Carvalho Chehab static int dib7000p_get_stats(struct dvb_frontend *demod, enum fe_status stat)
1897041ad449SMauro Carvalho Chehab {
1898041ad449SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
1899041ad449SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1900041ad449SMauro Carvalho Chehab 	int show_per_stats = 0;
1901041ad449SMauro Carvalho Chehab 	u32 time_us = 0, val, snr;
1902041ad449SMauro Carvalho Chehab 	u64 blocks, ucb;
1903041ad449SMauro Carvalho Chehab 	s32 db;
1904041ad449SMauro Carvalho Chehab 	u16 strength;
1905041ad449SMauro Carvalho Chehab 
1906041ad449SMauro Carvalho Chehab 	/* Get Signal strength */
1907041ad449SMauro Carvalho Chehab 	dib7000p_read_signal_strength(demod, &strength);
1908041ad449SMauro Carvalho Chehab 	val = strength;
1909041ad449SMauro Carvalho Chehab 	db = interpolate_value(val,
1910041ad449SMauro Carvalho Chehab 			       strength_to_db_table,
1911041ad449SMauro Carvalho Chehab 			       ARRAY_SIZE(strength_to_db_table)) - DB_OFFSET;
1912041ad449SMauro Carvalho Chehab 	c->strength.stat[0].svalue = db;
1913041ad449SMauro Carvalho Chehab 
1914041ad449SMauro Carvalho Chehab 	/* UCB/BER/CNR measures require lock */
1915041ad449SMauro Carvalho Chehab 	if (!(stat & FE_HAS_LOCK)) {
1916041ad449SMauro Carvalho Chehab 		c->cnr.len = 1;
1917041ad449SMauro Carvalho Chehab 		c->block_count.len = 1;
1918041ad449SMauro Carvalho Chehab 		c->block_error.len = 1;
1919041ad449SMauro Carvalho Chehab 		c->post_bit_error.len = 1;
1920041ad449SMauro Carvalho Chehab 		c->post_bit_count.len = 1;
1921041ad449SMauro Carvalho Chehab 		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1922041ad449SMauro Carvalho Chehab 		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1923041ad449SMauro Carvalho Chehab 		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1924041ad449SMauro Carvalho Chehab 		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1925041ad449SMauro Carvalho Chehab 		c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1926041ad449SMauro Carvalho Chehab 		return 0;
1927041ad449SMauro Carvalho Chehab 	}
1928041ad449SMauro Carvalho Chehab 
1929041ad449SMauro Carvalho Chehab 	/* Check if time for stats was elapsed */
1930041ad449SMauro Carvalho Chehab 	if (time_after(jiffies, state->per_jiffies_stats)) {
1931041ad449SMauro Carvalho Chehab 		state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
1932041ad449SMauro Carvalho Chehab 
1933041ad449SMauro Carvalho Chehab 		/* Get SNR */
1934041ad449SMauro Carvalho Chehab 		snr = dib7000p_get_snr(demod);
1935041ad449SMauro Carvalho Chehab 		if (snr)
1936041ad449SMauro Carvalho Chehab 			snr = (1000L * snr) >> 24;
1937041ad449SMauro Carvalho Chehab 		else
1938041ad449SMauro Carvalho Chehab 			snr = 0;
1939041ad449SMauro Carvalho Chehab 		c->cnr.stat[0].svalue = snr;
1940041ad449SMauro Carvalho Chehab 		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
1941041ad449SMauro Carvalho Chehab 
1942041ad449SMauro Carvalho Chehab 		/* Get UCB measures */
1943041ad449SMauro Carvalho Chehab 		dib7000p_read_unc_blocks(demod, &val);
1944041ad449SMauro Carvalho Chehab 		ucb = val - state->old_ucb;
1945041ad449SMauro Carvalho Chehab 		if (val < state->old_ucb)
1946041ad449SMauro Carvalho Chehab 			ucb += 0x100000000LL;
1947041ad449SMauro Carvalho Chehab 
1948041ad449SMauro Carvalho Chehab 		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
1949041ad449SMauro Carvalho Chehab 		c->block_error.stat[0].uvalue = ucb;
1950041ad449SMauro Carvalho Chehab 
1951041ad449SMauro Carvalho Chehab 		/* Estimate the number of packets based on bitrate */
1952041ad449SMauro Carvalho Chehab 		if (!time_us)
1953986f1686SMauro Carvalho Chehab 			time_us = dib7000p_get_time_us(demod);
1954041ad449SMauro Carvalho Chehab 
1955041ad449SMauro Carvalho Chehab 		if (time_us) {
1956041ad449SMauro Carvalho Chehab 			blocks = 1250000ULL * 1000000ULL;
1957041ad449SMauro Carvalho Chehab 			do_div(blocks, time_us * 8 * 204);
1958041ad449SMauro Carvalho Chehab 			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
1959041ad449SMauro Carvalho Chehab 			c->block_count.stat[0].uvalue += blocks;
1960041ad449SMauro Carvalho Chehab 		}
1961041ad449SMauro Carvalho Chehab 
1962041ad449SMauro Carvalho Chehab 		show_per_stats = 1;
1963041ad449SMauro Carvalho Chehab 	}
1964041ad449SMauro Carvalho Chehab 
1965041ad449SMauro Carvalho Chehab 	/* Get post-BER measures */
1966041ad449SMauro Carvalho Chehab 	if (time_after(jiffies, state->ber_jiffies_stats)) {
1967986f1686SMauro Carvalho Chehab 		time_us = dib7000p_get_time_us(demod);
1968041ad449SMauro Carvalho Chehab 		state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
1969041ad449SMauro Carvalho Chehab 
19705a0e2a4eSMauro Carvalho Chehab 		dprintk("Next all layers stats available in %u us.\n", time_us);
1971041ad449SMauro Carvalho Chehab 
1972041ad449SMauro Carvalho Chehab 		dib7000p_read_ber(demod, &val);
1973041ad449SMauro Carvalho Chehab 		c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
1974041ad449SMauro Carvalho Chehab 		c->post_bit_error.stat[0].uvalue += val;
1975041ad449SMauro Carvalho Chehab 
1976041ad449SMauro Carvalho Chehab 		c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
1977041ad449SMauro Carvalho Chehab 		c->post_bit_count.stat[0].uvalue += 100000000;
1978041ad449SMauro Carvalho Chehab 	}
1979041ad449SMauro Carvalho Chehab 
1980041ad449SMauro Carvalho Chehab 	/* Get PER measures */
1981041ad449SMauro Carvalho Chehab 	if (show_per_stats) {
1982041ad449SMauro Carvalho Chehab 		dib7000p_read_unc_blocks(demod, &val);
1983041ad449SMauro Carvalho Chehab 
1984041ad449SMauro Carvalho Chehab 		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
1985041ad449SMauro Carvalho Chehab 		c->block_error.stat[0].uvalue += val;
1986041ad449SMauro Carvalho Chehab 
1987986f1686SMauro Carvalho Chehab 		time_us = dib7000p_get_time_us(demod);
1988041ad449SMauro Carvalho Chehab 		if (time_us) {
1989041ad449SMauro Carvalho Chehab 			blocks = 1250000ULL * 1000000ULL;
1990041ad449SMauro Carvalho Chehab 			do_div(blocks, time_us * 8 * 204);
1991041ad449SMauro Carvalho Chehab 			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
1992041ad449SMauro Carvalho Chehab 			c->block_count.stat[0].uvalue += blocks;
1993041ad449SMauro Carvalho Chehab 		}
1994041ad449SMauro Carvalho Chehab 	}
1995041ad449SMauro Carvalho Chehab 	return 0;
1996041ad449SMauro Carvalho Chehab }
1997041ad449SMauro Carvalho Chehab 
19989a0bf528SMauro Carvalho Chehab static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
19999a0bf528SMauro Carvalho Chehab {
20009a0bf528SMauro Carvalho Chehab 	tune->min_delay_ms = 1000;
20019a0bf528SMauro Carvalho Chehab 	return 0;
20029a0bf528SMauro Carvalho Chehab }
20039a0bf528SMauro Carvalho Chehab 
20049a0bf528SMauro Carvalho Chehab static void dib7000p_release(struct dvb_frontend *demod)
20059a0bf528SMauro Carvalho Chehab {
20069a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *st = demod->demodulator_priv;
20079a0bf528SMauro Carvalho Chehab 	dibx000_exit_i2c_master(&st->i2c_master);
20089a0bf528SMauro Carvalho Chehab 	i2c_del_adapter(&st->dib7090_tuner_adap);
20099a0bf528SMauro Carvalho Chehab 	kfree(st);
20109a0bf528SMauro Carvalho Chehab }
20119a0bf528SMauro Carvalho Chehab 
20128abe4a0aSMauro Carvalho Chehab static int dib7000pc_detection(struct i2c_adapter *i2c_adap)
20139a0bf528SMauro Carvalho Chehab {
20149a0bf528SMauro Carvalho Chehab 	u8 *tx, *rx;
20159a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2] = {
20169a0bf528SMauro Carvalho Chehab 		{.addr = 18 >> 1, .flags = 0, .len = 2},
20179a0bf528SMauro Carvalho Chehab 		{.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
20189a0bf528SMauro Carvalho Chehab 	};
20199a0bf528SMauro Carvalho Chehab 	int ret = 0;
20209a0bf528SMauro Carvalho Chehab 
20219a0bf528SMauro Carvalho Chehab 	tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
20229a0bf528SMauro Carvalho Chehab 	if (!tx)
20239a0bf528SMauro Carvalho Chehab 		return -ENOMEM;
20249a0bf528SMauro Carvalho Chehab 	rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
20259a0bf528SMauro Carvalho Chehab 	if (!rx) {
20269a0bf528SMauro Carvalho Chehab 		ret = -ENOMEM;
20279a0bf528SMauro Carvalho Chehab 		goto rx_memory_error;
20289a0bf528SMauro Carvalho Chehab 	}
20299a0bf528SMauro Carvalho Chehab 
20309a0bf528SMauro Carvalho Chehab 	msg[0].buf = tx;
20319a0bf528SMauro Carvalho Chehab 	msg[1].buf = rx;
20329a0bf528SMauro Carvalho Chehab 
20339a0bf528SMauro Carvalho Chehab 	tx[0] = 0x03;
20349a0bf528SMauro Carvalho Chehab 	tx[1] = 0x00;
20359a0bf528SMauro Carvalho Chehab 
20369a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(i2c_adap, msg, 2) == 2)
20379a0bf528SMauro Carvalho Chehab 		if (rx[0] == 0x01 && rx[1] == 0xb3) {
20385a0e2a4eSMauro Carvalho Chehab 			dprintk("-D-  DiB7000PC detected\n");
20399a0bf528SMauro Carvalho Chehab 			return 1;
20409a0bf528SMauro Carvalho Chehab 		}
20419a0bf528SMauro Carvalho Chehab 
20429a0bf528SMauro Carvalho Chehab 	msg[0].addr = msg[1].addr = 0x40;
20439a0bf528SMauro Carvalho Chehab 
20449a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(i2c_adap, msg, 2) == 2)
20459a0bf528SMauro Carvalho Chehab 		if (rx[0] == 0x01 && rx[1] == 0xb3) {
20465a0e2a4eSMauro Carvalho Chehab 			dprintk("-D-  DiB7000PC detected\n");
20479a0bf528SMauro Carvalho Chehab 			return 1;
20489a0bf528SMauro Carvalho Chehab 		}
20499a0bf528SMauro Carvalho Chehab 
20505a0e2a4eSMauro Carvalho Chehab 	dprintk("-D-  DiB7000PC not detected\n");
20519a0bf528SMauro Carvalho Chehab 
20529a0bf528SMauro Carvalho Chehab 	kfree(rx);
20539a0bf528SMauro Carvalho Chehab rx_memory_error:
20549a0bf528SMauro Carvalho Chehab 	kfree(tx);
20559a0bf528SMauro Carvalho Chehab 	return ret;
20569a0bf528SMauro Carvalho Chehab }
20579a0bf528SMauro Carvalho Chehab 
20588abe4a0aSMauro Carvalho Chehab static struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
20599a0bf528SMauro Carvalho Chehab {
20609a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *st = demod->demodulator_priv;
20619a0bf528SMauro Carvalho Chehab 	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
20629a0bf528SMauro Carvalho Chehab }
20639a0bf528SMauro Carvalho Chehab 
20648abe4a0aSMauro Carvalho Chehab static int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
20659a0bf528SMauro Carvalho Chehab {
20669a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
20679a0bf528SMauro Carvalho Chehab 	u16 val = dib7000p_read_word(state, 235) & 0xffef;
20689a0bf528SMauro Carvalho Chehab 	val |= (onoff & 0x1) << 4;
20695a0e2a4eSMauro Carvalho Chehab 	dprintk("PID filter enabled %d\n", onoff);
20709a0bf528SMauro Carvalho Chehab 	return dib7000p_write_word(state, 235, val);
20719a0bf528SMauro Carvalho Chehab }
20729a0bf528SMauro Carvalho Chehab 
20738abe4a0aSMauro Carvalho Chehab static int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
20749a0bf528SMauro Carvalho Chehab {
20759a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
20765a0e2a4eSMauro Carvalho Chehab 	dprintk("PID filter: index %x, PID %d, OnOff %d\n", id, pid, onoff);
20779a0bf528SMauro Carvalho Chehab 	return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
20789a0bf528SMauro Carvalho Chehab }
20799a0bf528SMauro Carvalho Chehab 
20808abe4a0aSMauro Carvalho Chehab static int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
20819a0bf528SMauro Carvalho Chehab {
20829a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *dpst;
20839a0bf528SMauro Carvalho Chehab 	int k = 0;
20849a0bf528SMauro Carvalho Chehab 	u8 new_addr = 0;
20859a0bf528SMauro Carvalho Chehab 
20869a0bf528SMauro Carvalho Chehab 	dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
20879a0bf528SMauro Carvalho Chehab 	if (!dpst)
20889a0bf528SMauro Carvalho Chehab 		return -ENOMEM;
20899a0bf528SMauro Carvalho Chehab 
20909a0bf528SMauro Carvalho Chehab 	dpst->i2c_adap = i2c;
20919a0bf528SMauro Carvalho Chehab 	mutex_init(&dpst->i2c_buffer_lock);
20929a0bf528SMauro Carvalho Chehab 
20939a0bf528SMauro Carvalho Chehab 	for (k = no_of_demods - 1; k >= 0; k--) {
20949a0bf528SMauro Carvalho Chehab 		dpst->cfg = cfg[k];
20959a0bf528SMauro Carvalho Chehab 
20969a0bf528SMauro Carvalho Chehab 		/* designated i2c address */
20979a0bf528SMauro Carvalho Chehab 		if (cfg[k].default_i2c_addr != 0)
20989a0bf528SMauro Carvalho Chehab 			new_addr = cfg[k].default_i2c_addr + (k << 1);
20999a0bf528SMauro Carvalho Chehab 		else
21009a0bf528SMauro Carvalho Chehab 			new_addr = (0x40 + k) << 1;
21019a0bf528SMauro Carvalho Chehab 		dpst->i2c_addr = new_addr;
21029a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(dpst, 1287, 0x0003);	/* sram lead in, rdy */
21039a0bf528SMauro Carvalho Chehab 		if (dib7000p_identify(dpst) != 0) {
21049a0bf528SMauro Carvalho Chehab 			dpst->i2c_addr = default_addr;
21059a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(dpst, 1287, 0x0003);	/* sram lead in, rdy */
21069a0bf528SMauro Carvalho Chehab 			if (dib7000p_identify(dpst) != 0) {
21079a0bf528SMauro Carvalho Chehab 				dprintk("DiB7000P #%d: not identified\n", k);
21089a0bf528SMauro Carvalho Chehab 				kfree(dpst);
21099a0bf528SMauro Carvalho Chehab 				return -EIO;
21109a0bf528SMauro Carvalho Chehab 			}
21119a0bf528SMauro Carvalho Chehab 		}
21129a0bf528SMauro Carvalho Chehab 
21139a0bf528SMauro Carvalho Chehab 		/* start diversity to pull_down div_str - just for i2c-enumeration */
21149a0bf528SMauro Carvalho Chehab 		dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
21159a0bf528SMauro Carvalho Chehab 
21169a0bf528SMauro Carvalho Chehab 		/* set new i2c address and force divstart */
21179a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
21189a0bf528SMauro Carvalho Chehab 
21195a0e2a4eSMauro Carvalho Chehab 		dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
21209a0bf528SMauro Carvalho Chehab 	}
21219a0bf528SMauro Carvalho Chehab 
21229a0bf528SMauro Carvalho Chehab 	for (k = 0; k < no_of_demods; k++) {
21239a0bf528SMauro Carvalho Chehab 		dpst->cfg = cfg[k];
21249a0bf528SMauro Carvalho Chehab 		if (cfg[k].default_i2c_addr != 0)
21259a0bf528SMauro Carvalho Chehab 			dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
21269a0bf528SMauro Carvalho Chehab 		else
21279a0bf528SMauro Carvalho Chehab 			dpst->i2c_addr = (0x40 + k) << 1;
21289a0bf528SMauro Carvalho Chehab 
21299a0bf528SMauro Carvalho Chehab 		// unforce divstr
21309a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
21319a0bf528SMauro Carvalho Chehab 
21329a0bf528SMauro Carvalho Chehab 		/* deactivate div - it was just for i2c-enumeration */
21339a0bf528SMauro Carvalho Chehab 		dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
21349a0bf528SMauro Carvalho Chehab 	}
21359a0bf528SMauro Carvalho Chehab 
21369a0bf528SMauro Carvalho Chehab 	kfree(dpst);
21379a0bf528SMauro Carvalho Chehab 	return 0;
21389a0bf528SMauro Carvalho Chehab }
21399a0bf528SMauro Carvalho Chehab 
21409a0bf528SMauro Carvalho Chehab static const s32 lut_1000ln_mant[] = {
21419a0bf528SMauro Carvalho Chehab 	6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
21429a0bf528SMauro Carvalho Chehab };
21439a0bf528SMauro Carvalho Chehab 
21449a0bf528SMauro Carvalho Chehab static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
21459a0bf528SMauro Carvalho Chehab {
21469a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
21479a0bf528SMauro Carvalho Chehab 	u32 tmp_val = 0, exp = 0, mant = 0;
21489a0bf528SMauro Carvalho Chehab 	s32 pow_i;
21499a0bf528SMauro Carvalho Chehab 	u16 buf[2];
21509a0bf528SMauro Carvalho Chehab 	u8 ix = 0;
21519a0bf528SMauro Carvalho Chehab 
21529a0bf528SMauro Carvalho Chehab 	buf[0] = dib7000p_read_word(state, 0x184);
21539a0bf528SMauro Carvalho Chehab 	buf[1] = dib7000p_read_word(state, 0x185);
21549a0bf528SMauro Carvalho Chehab 	pow_i = (buf[0] << 16) | buf[1];
21555a0e2a4eSMauro Carvalho Chehab 	dprintk("raw pow_i = %d\n", pow_i);
21569a0bf528SMauro Carvalho Chehab 
21579a0bf528SMauro Carvalho Chehab 	tmp_val = pow_i;
21589a0bf528SMauro Carvalho Chehab 	while (tmp_val >>= 1)
21599a0bf528SMauro Carvalho Chehab 		exp++;
21609a0bf528SMauro Carvalho Chehab 
21619a0bf528SMauro Carvalho Chehab 	mant = (pow_i * 1000 / (1 << exp));
21625a0e2a4eSMauro Carvalho Chehab 	dprintk(" mant = %d exp = %d\n", mant / 1000, exp);
21639a0bf528SMauro Carvalho Chehab 
21649a0bf528SMauro Carvalho Chehab 	ix = (u8) ((mant - 1000) / 100);	/* index of the LUT */
21655a0e2a4eSMauro Carvalho Chehab 	dprintk(" ix = %d\n", ix);
21669a0bf528SMauro Carvalho Chehab 
21679a0bf528SMauro Carvalho Chehab 	pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
21689a0bf528SMauro Carvalho Chehab 	pow_i = (pow_i << 8) / 1000;
21695a0e2a4eSMauro Carvalho Chehab 	dprintk(" pow_i = %d\n", pow_i);
21709a0bf528SMauro Carvalho Chehab 
21719a0bf528SMauro Carvalho Chehab 	return pow_i;
21729a0bf528SMauro Carvalho Chehab }
21739a0bf528SMauro Carvalho Chehab 
21749a0bf528SMauro Carvalho Chehab static int map_addr_to_serpar_number(struct i2c_msg *msg)
21759a0bf528SMauro Carvalho Chehab {
21769a0bf528SMauro Carvalho Chehab 	if ((msg->buf[0] <= 15))
21779a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 1;
21789a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 17)
21799a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 15;
21809a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 16)
21819a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 17;
21829a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 19)
21839a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 16;
21849a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
21859a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 3;
21869a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 28)
21879a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 23;
21889a0bf528SMauro Carvalho Chehab 	else
21899a0bf528SMauro Carvalho Chehab 		return -EINVAL;
21909a0bf528SMauro Carvalho Chehab 	return 0;
21919a0bf528SMauro Carvalho Chehab }
21929a0bf528SMauro Carvalho Chehab 
21939a0bf528SMauro Carvalho Chehab static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
21949a0bf528SMauro Carvalho Chehab {
21959a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
21969a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1;
21979a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
21989a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
21999a0bf528SMauro Carvalho Chehab 
22009a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
22019a0bf528SMauro Carvalho Chehab 		n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
22029a0bf528SMauro Carvalho Chehab 		i--;
22039a0bf528SMauro Carvalho Chehab 		if (i == 0)
22045a0e2a4eSMauro Carvalho Chehab 			dprintk("Tuner ITF: write busy (overflow)\n");
22059a0bf528SMauro Carvalho Chehab 	}
22069a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
22079a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
22089a0bf528SMauro Carvalho Chehab 
22099a0bf528SMauro Carvalho Chehab 	return num;
22109a0bf528SMauro Carvalho Chehab }
22119a0bf528SMauro Carvalho Chehab 
22129a0bf528SMauro Carvalho Chehab static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
22139a0bf528SMauro Carvalho Chehab {
22149a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
22159a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1, n_empty = 1;
22169a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
22179a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
22189a0bf528SMauro Carvalho Chehab 	u16 read_word;
22199a0bf528SMauro Carvalho Chehab 
22209a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
22219a0bf528SMauro Carvalho Chehab 		n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
22229a0bf528SMauro Carvalho Chehab 		i--;
22239a0bf528SMauro Carvalho Chehab 		if (i == 0)
22245a0e2a4eSMauro Carvalho Chehab 			dprintk("TunerITF: read busy (overflow)\n");
22259a0bf528SMauro Carvalho Chehab 	}
22269a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
22279a0bf528SMauro Carvalho Chehab 
22289a0bf528SMauro Carvalho Chehab 	i = 1000;
22299a0bf528SMauro Carvalho Chehab 	while (n_empty == 1 && i) {
22309a0bf528SMauro Carvalho Chehab 		n_empty = dib7000p_read_word(state, 1984) & 0x1;
22319a0bf528SMauro Carvalho Chehab 		i--;
22329a0bf528SMauro Carvalho Chehab 		if (i == 0)
22335a0e2a4eSMauro Carvalho Chehab 			dprintk("TunerITF: read busy (empty)\n");
22349a0bf528SMauro Carvalho Chehab 	}
22359a0bf528SMauro Carvalho Chehab 	read_word = dib7000p_read_word(state, 1987);
22369a0bf528SMauro Carvalho Chehab 	msg[1].buf[0] = (read_word >> 8) & 0xff;
22379a0bf528SMauro Carvalho Chehab 	msg[1].buf[1] = (read_word) & 0xff;
22389a0bf528SMauro Carvalho Chehab 
22399a0bf528SMauro Carvalho Chehab 	return num;
22409a0bf528SMauro Carvalho Chehab }
22419a0bf528SMauro Carvalho Chehab 
22429a0bf528SMauro Carvalho Chehab static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
22439a0bf528SMauro Carvalho Chehab {
22449a0bf528SMauro 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... */
22459a0bf528SMauro Carvalho Chehab 		if (num == 1) {	/* write */
22469a0bf528SMauro Carvalho Chehab 			return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
22479a0bf528SMauro Carvalho Chehab 		} else {	/* read */
22489a0bf528SMauro Carvalho Chehab 			return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
22499a0bf528SMauro Carvalho Chehab 		}
22509a0bf528SMauro Carvalho Chehab 	}
22519a0bf528SMauro Carvalho Chehab 	return num;
22529a0bf528SMauro Carvalho Chehab }
22539a0bf528SMauro Carvalho Chehab 
22549a0bf528SMauro Carvalho Chehab static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
22559a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num, u16 apb_address)
22569a0bf528SMauro Carvalho Chehab {
22579a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
22589a0bf528SMauro Carvalho Chehab 	u16 word;
22599a0bf528SMauro Carvalho Chehab 
22609a0bf528SMauro Carvalho Chehab 	if (num == 1) {		/* write */
22619a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
22629a0bf528SMauro Carvalho Chehab 	} else {
22639a0bf528SMauro Carvalho Chehab 		word = dib7000p_read_word(state, apb_address);
22649a0bf528SMauro Carvalho Chehab 		msg[1].buf[0] = (word >> 8) & 0xff;
22659a0bf528SMauro Carvalho Chehab 		msg[1].buf[1] = (word) & 0xff;
22669a0bf528SMauro Carvalho Chehab 	}
22679a0bf528SMauro Carvalho Chehab 
22689a0bf528SMauro Carvalho Chehab 	return num;
22699a0bf528SMauro Carvalho Chehab }
22709a0bf528SMauro Carvalho Chehab 
22719a0bf528SMauro Carvalho Chehab static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
22729a0bf528SMauro Carvalho Chehab {
22739a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
22749a0bf528SMauro Carvalho Chehab 
22759a0bf528SMauro Carvalho Chehab 	u16 apb_address = 0, word;
22769a0bf528SMauro Carvalho Chehab 	int i = 0;
22779a0bf528SMauro Carvalho Chehab 	switch (msg[0].buf[0]) {
22789a0bf528SMauro Carvalho Chehab 	case 0x12:
22799a0bf528SMauro Carvalho Chehab 		apb_address = 1920;
22809a0bf528SMauro Carvalho Chehab 		break;
22819a0bf528SMauro Carvalho Chehab 	case 0x14:
22829a0bf528SMauro Carvalho Chehab 		apb_address = 1921;
22839a0bf528SMauro Carvalho Chehab 		break;
22849a0bf528SMauro Carvalho Chehab 	case 0x24:
22859a0bf528SMauro Carvalho Chehab 		apb_address = 1922;
22869a0bf528SMauro Carvalho Chehab 		break;
22879a0bf528SMauro Carvalho Chehab 	case 0x1a:
22889a0bf528SMauro Carvalho Chehab 		apb_address = 1923;
22899a0bf528SMauro Carvalho Chehab 		break;
22909a0bf528SMauro Carvalho Chehab 	case 0x22:
22919a0bf528SMauro Carvalho Chehab 		apb_address = 1924;
22929a0bf528SMauro Carvalho Chehab 		break;
22939a0bf528SMauro Carvalho Chehab 	case 0x33:
22949a0bf528SMauro Carvalho Chehab 		apb_address = 1926;
22959a0bf528SMauro Carvalho Chehab 		break;
22969a0bf528SMauro Carvalho Chehab 	case 0x34:
22979a0bf528SMauro Carvalho Chehab 		apb_address = 1927;
22989a0bf528SMauro Carvalho Chehab 		break;
22999a0bf528SMauro Carvalho Chehab 	case 0x35:
23009a0bf528SMauro Carvalho Chehab 		apb_address = 1928;
23019a0bf528SMauro Carvalho Chehab 		break;
23029a0bf528SMauro Carvalho Chehab 	case 0x36:
23039a0bf528SMauro Carvalho Chehab 		apb_address = 1929;
23049a0bf528SMauro Carvalho Chehab 		break;
23059a0bf528SMauro Carvalho Chehab 	case 0x37:
23069a0bf528SMauro Carvalho Chehab 		apb_address = 1930;
23079a0bf528SMauro Carvalho Chehab 		break;
23089a0bf528SMauro Carvalho Chehab 	case 0x38:
23099a0bf528SMauro Carvalho Chehab 		apb_address = 1931;
23109a0bf528SMauro Carvalho Chehab 		break;
23119a0bf528SMauro Carvalho Chehab 	case 0x39:
23129a0bf528SMauro Carvalho Chehab 		apb_address = 1932;
23139a0bf528SMauro Carvalho Chehab 		break;
23149a0bf528SMauro Carvalho Chehab 	case 0x2a:
23159a0bf528SMauro Carvalho Chehab 		apb_address = 1935;
23169a0bf528SMauro Carvalho Chehab 		break;
23179a0bf528SMauro Carvalho Chehab 	case 0x2b:
23189a0bf528SMauro Carvalho Chehab 		apb_address = 1936;
23199a0bf528SMauro Carvalho Chehab 		break;
23209a0bf528SMauro Carvalho Chehab 	case 0x2c:
23219a0bf528SMauro Carvalho Chehab 		apb_address = 1937;
23229a0bf528SMauro Carvalho Chehab 		break;
23239a0bf528SMauro Carvalho Chehab 	case 0x2d:
23249a0bf528SMauro Carvalho Chehab 		apb_address = 1938;
23259a0bf528SMauro Carvalho Chehab 		break;
23269a0bf528SMauro Carvalho Chehab 	case 0x2e:
23279a0bf528SMauro Carvalho Chehab 		apb_address = 1939;
23289a0bf528SMauro Carvalho Chehab 		break;
23299a0bf528SMauro Carvalho Chehab 	case 0x2f:
23309a0bf528SMauro Carvalho Chehab 		apb_address = 1940;
23319a0bf528SMauro Carvalho Chehab 		break;
23329a0bf528SMauro Carvalho Chehab 	case 0x30:
23339a0bf528SMauro Carvalho Chehab 		apb_address = 1941;
23349a0bf528SMauro Carvalho Chehab 		break;
23359a0bf528SMauro Carvalho Chehab 	case 0x31:
23369a0bf528SMauro Carvalho Chehab 		apb_address = 1942;
23379a0bf528SMauro Carvalho Chehab 		break;
23389a0bf528SMauro Carvalho Chehab 	case 0x32:
23399a0bf528SMauro Carvalho Chehab 		apb_address = 1943;
23409a0bf528SMauro Carvalho Chehab 		break;
23419a0bf528SMauro Carvalho Chehab 	case 0x3e:
23429a0bf528SMauro Carvalho Chehab 		apb_address = 1944;
23439a0bf528SMauro Carvalho Chehab 		break;
23449a0bf528SMauro Carvalho Chehab 	case 0x3f:
23459a0bf528SMauro Carvalho Chehab 		apb_address = 1945;
23469a0bf528SMauro Carvalho Chehab 		break;
23479a0bf528SMauro Carvalho Chehab 	case 0x40:
23489a0bf528SMauro Carvalho Chehab 		apb_address = 1948;
23499a0bf528SMauro Carvalho Chehab 		break;
23509a0bf528SMauro Carvalho Chehab 	case 0x25:
23519a0bf528SMauro Carvalho Chehab 		apb_address = 914;
23529a0bf528SMauro Carvalho Chehab 		break;
23539a0bf528SMauro Carvalho Chehab 	case 0x26:
23549a0bf528SMauro Carvalho Chehab 		apb_address = 915;
23559a0bf528SMauro Carvalho Chehab 		break;
23569a0bf528SMauro Carvalho Chehab 	case 0x27:
23579a0bf528SMauro Carvalho Chehab 		apb_address = 917;
23589a0bf528SMauro Carvalho Chehab 		break;
23599a0bf528SMauro Carvalho Chehab 	case 0x28:
23609a0bf528SMauro Carvalho Chehab 		apb_address = 916;
23619a0bf528SMauro Carvalho Chehab 		break;
23629a0bf528SMauro Carvalho Chehab 	case 0x1d:
23639a0bf528SMauro Carvalho Chehab 		i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
23649a0bf528SMauro Carvalho Chehab 		word = dib7000p_read_word(state, 384 + i);
23659a0bf528SMauro Carvalho Chehab 		msg[1].buf[0] = (word >> 8) & 0xff;
23669a0bf528SMauro Carvalho Chehab 		msg[1].buf[1] = (word) & 0xff;
23679a0bf528SMauro Carvalho Chehab 		return num;
23689a0bf528SMauro Carvalho Chehab 	case 0x1f:
23699a0bf528SMauro Carvalho Chehab 		if (num == 1) {	/* write */
23709a0bf528SMauro Carvalho Chehab 			word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
23719a0bf528SMauro Carvalho Chehab 			word &= 0x3;
23729a0bf528SMauro Carvalho Chehab 			word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
23739a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 72, word);	/* Set the proper input */
23749a0bf528SMauro Carvalho Chehab 			return num;
23759a0bf528SMauro Carvalho Chehab 		}
23769a0bf528SMauro Carvalho Chehab 	}
23779a0bf528SMauro Carvalho Chehab 
23789a0bf528SMauro Carvalho Chehab 	if (apb_address != 0)	/* R/W acces via APB */
23799a0bf528SMauro Carvalho Chehab 		return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
23809a0bf528SMauro Carvalho Chehab 	else			/* R/W access via SERPAR  */
23819a0bf528SMauro Carvalho Chehab 		return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
23829a0bf528SMauro Carvalho Chehab 
23839a0bf528SMauro Carvalho Chehab 	return 0;
23849a0bf528SMauro Carvalho Chehab }
23859a0bf528SMauro Carvalho Chehab 
23869a0bf528SMauro Carvalho Chehab static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
23879a0bf528SMauro Carvalho Chehab {
23889a0bf528SMauro Carvalho Chehab 	return I2C_FUNC_I2C;
23899a0bf528SMauro Carvalho Chehab }
23909a0bf528SMauro Carvalho Chehab 
23919a0bf528SMauro Carvalho Chehab static struct i2c_algorithm dib7090_tuner_xfer_algo = {
23929a0bf528SMauro Carvalho Chehab 	.master_xfer = dib7090_tuner_xfer,
23939a0bf528SMauro Carvalho Chehab 	.functionality = dib7000p_i2c_func,
23949a0bf528SMauro Carvalho Chehab };
23959a0bf528SMauro Carvalho Chehab 
23968abe4a0aSMauro Carvalho Chehab static struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
23979a0bf528SMauro Carvalho Chehab {
23989a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *st = fe->demodulator_priv;
23999a0bf528SMauro Carvalho Chehab 	return &st->dib7090_tuner_adap;
24009a0bf528SMauro Carvalho Chehab }
24019a0bf528SMauro Carvalho Chehab 
24029a0bf528SMauro Carvalho Chehab static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
24039a0bf528SMauro Carvalho Chehab {
24049a0bf528SMauro Carvalho Chehab 	u16 reg;
24059a0bf528SMauro Carvalho Chehab 
24069a0bf528SMauro Carvalho Chehab 	/* drive host bus 2, 3, 4 */
24079a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
24089a0bf528SMauro Carvalho Chehab 	reg |= (drive << 12) | (drive << 6) | drive;
24099a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1798, reg);
24109a0bf528SMauro Carvalho Chehab 
24119a0bf528SMauro Carvalho Chehab 	/* drive host bus 5,6 */
24129a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
24139a0bf528SMauro Carvalho Chehab 	reg |= (drive << 8) | (drive << 2);
24149a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1799, reg);
24159a0bf528SMauro Carvalho Chehab 
24169a0bf528SMauro Carvalho Chehab 	/* drive host bus 7, 8, 9 */
24179a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
24189a0bf528SMauro Carvalho Chehab 	reg |= (drive << 12) | (drive << 6) | drive;
24199a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1800, reg);
24209a0bf528SMauro Carvalho Chehab 
24219a0bf528SMauro Carvalho Chehab 	/* drive host bus 10, 11 */
24229a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
24239a0bf528SMauro Carvalho Chehab 	reg |= (drive << 8) | (drive << 2);
24249a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1801, reg);
24259a0bf528SMauro Carvalho Chehab 
24269a0bf528SMauro Carvalho Chehab 	/* drive host bus 12, 13, 14 */
24279a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
24289a0bf528SMauro Carvalho Chehab 	reg |= (drive << 12) | (drive << 6) | drive;
24299a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1802, reg);
24309a0bf528SMauro Carvalho Chehab 
24319a0bf528SMauro Carvalho Chehab 	return 0;
24329a0bf528SMauro Carvalho Chehab }
24339a0bf528SMauro Carvalho Chehab 
24349a0bf528SMauro Carvalho Chehab static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
24359a0bf528SMauro Carvalho Chehab {
24369a0bf528SMauro Carvalho Chehab 	u32 quantif = 3;
24379a0bf528SMauro Carvalho Chehab 	u32 nom = (insertExtSynchro * P_Kin + syncSize);
24389a0bf528SMauro Carvalho Chehab 	u32 denom = P_Kout;
24399a0bf528SMauro Carvalho Chehab 	u32 syncFreq = ((nom << quantif) / denom);
24409a0bf528SMauro Carvalho Chehab 
24419a0bf528SMauro Carvalho Chehab 	if ((syncFreq & ((1 << quantif) - 1)) != 0)
24429a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif) + 1;
24439a0bf528SMauro Carvalho Chehab 	else
24449a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif);
24459a0bf528SMauro Carvalho Chehab 
24469a0bf528SMauro Carvalho Chehab 	if (syncFreq != 0)
24479a0bf528SMauro Carvalho Chehab 		syncFreq = syncFreq - 1;
24489a0bf528SMauro Carvalho Chehab 
24499a0bf528SMauro Carvalho Chehab 	return syncFreq;
24509a0bf528SMauro Carvalho Chehab }
24519a0bf528SMauro Carvalho Chehab 
24529a0bf528SMauro 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)
24539a0bf528SMauro Carvalho Chehab {
24545a0e2a4eSMauro Carvalho Chehab 	dprintk("Configure DibStream Tx\n");
24559a0bf528SMauro Carvalho Chehab 
24569a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1615, 1);
24579a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1603, P_Kin);
24589a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1605, P_Kout);
24599a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1606, insertExtSynchro);
24609a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1608, synchroMode);
24619a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
24629a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1610, syncWord & 0xffff);
24639a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1612, syncSize);
24649a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1615, 0);
24659a0bf528SMauro Carvalho Chehab 
24669a0bf528SMauro Carvalho Chehab 	return 0;
24679a0bf528SMauro Carvalho Chehab }
24689a0bf528SMauro Carvalho Chehab 
24699a0bf528SMauro 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,
24709a0bf528SMauro Carvalho Chehab 		u32 dataOutRate)
24719a0bf528SMauro Carvalho Chehab {
24729a0bf528SMauro Carvalho Chehab 	u32 syncFreq;
24739a0bf528SMauro Carvalho Chehab 
24745a0e2a4eSMauro Carvalho Chehab 	dprintk("Configure DibStream Rx\n");
24759a0bf528SMauro Carvalho Chehab 	if ((P_Kin != 0) && (P_Kout != 0)) {
24769a0bf528SMauro Carvalho Chehab 		syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
24779a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1542, syncFreq);
24789a0bf528SMauro Carvalho Chehab 	}
24799a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1554, 1);
24809a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1536, P_Kin);
24819a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1537, P_Kout);
24829a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1539, synchroMode);
24839a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
24849a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1541, syncWord & 0xffff);
24859a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1543, syncSize);
24869a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1544, dataOutRate);
24879a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1554, 0);
24889a0bf528SMauro Carvalho Chehab 
24899a0bf528SMauro Carvalho Chehab 	return 0;
24909a0bf528SMauro Carvalho Chehab }
24919a0bf528SMauro Carvalho Chehab 
24929a0bf528SMauro Carvalho Chehab static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
24939a0bf528SMauro Carvalho Chehab {
24949a0bf528SMauro Carvalho Chehab 	u16 reg_1287 = dib7000p_read_word(state, 1287);
24959a0bf528SMauro Carvalho Chehab 
24969a0bf528SMauro Carvalho Chehab 	switch (onoff) {
24979a0bf528SMauro Carvalho Chehab 	case 1:
24989a0bf528SMauro Carvalho Chehab 			reg_1287 &= ~(1<<7);
24999a0bf528SMauro Carvalho Chehab 			break;
25009a0bf528SMauro Carvalho Chehab 	case 0:
25019a0bf528SMauro Carvalho Chehab 			reg_1287 |= (1<<7);
25029a0bf528SMauro Carvalho Chehab 			break;
25039a0bf528SMauro Carvalho Chehab 	}
25049a0bf528SMauro Carvalho Chehab 
25059a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1287, reg_1287);
25069a0bf528SMauro Carvalho Chehab }
25079a0bf528SMauro Carvalho Chehab 
25089a0bf528SMauro Carvalho Chehab static void dib7090_configMpegMux(struct dib7000p_state *state,
25099a0bf528SMauro Carvalho Chehab 		u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
25109a0bf528SMauro Carvalho Chehab {
25115a0e2a4eSMauro Carvalho Chehab 	dprintk("Enable Mpeg mux\n");
25129a0bf528SMauro Carvalho Chehab 
25139a0bf528SMauro Carvalho Chehab 	dib7090_enMpegMux(state, 0);
25149a0bf528SMauro Carvalho Chehab 
25159a0bf528SMauro Carvalho Chehab 	/* If the input mode is MPEG do not divide the serial clock */
25169a0bf528SMauro Carvalho Chehab 	if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
25179a0bf528SMauro Carvalho Chehab 		enSerialClkDiv2 = 0;
25189a0bf528SMauro Carvalho Chehab 
25199a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
25209a0bf528SMauro Carvalho Chehab 			| ((enSerialMode & 0x1) << 1)
25219a0bf528SMauro Carvalho Chehab 			| (enSerialClkDiv2 & 0x1));
25229a0bf528SMauro Carvalho Chehab 
25239a0bf528SMauro Carvalho Chehab 	dib7090_enMpegMux(state, 1);
25249a0bf528SMauro Carvalho Chehab }
25259a0bf528SMauro Carvalho Chehab 
25269a0bf528SMauro Carvalho Chehab static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
25279a0bf528SMauro Carvalho Chehab {
25289a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
25299a0bf528SMauro Carvalho Chehab 
25309a0bf528SMauro Carvalho Chehab 	switch (mode) {
25319a0bf528SMauro Carvalho Chehab 	case MPEG_ON_DIBTX:
25325a0e2a4eSMauro Carvalho Chehab 			dprintk("SET MPEG ON DIBSTREAM TX\n");
25339a0bf528SMauro Carvalho Chehab 			dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
25349a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<9);
25359a0bf528SMauro Carvalho Chehab 			break;
25369a0bf528SMauro Carvalho Chehab 	case DIV_ON_DIBTX:
25375a0e2a4eSMauro Carvalho Chehab 			dprintk("SET DIV_OUT ON DIBSTREAM TX\n");
25389a0bf528SMauro Carvalho Chehab 			dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
25399a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<8);
25409a0bf528SMauro Carvalho Chehab 			break;
25419a0bf528SMauro Carvalho Chehab 	case ADC_ON_DIBTX:
25425a0e2a4eSMauro Carvalho Chehab 			dprintk("SET ADC_OUT ON DIBSTREAM TX\n");
25439a0bf528SMauro Carvalho Chehab 			dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
25449a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<7);
25459a0bf528SMauro Carvalho Chehab 			break;
25469a0bf528SMauro Carvalho Chehab 	default:
25479a0bf528SMauro Carvalho Chehab 			break;
25489a0bf528SMauro Carvalho Chehab 	}
25499a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1288, reg_1288);
25509a0bf528SMauro Carvalho Chehab }
25519a0bf528SMauro Carvalho Chehab 
25529a0bf528SMauro Carvalho Chehab static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
25539a0bf528SMauro Carvalho Chehab {
25549a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
25559a0bf528SMauro Carvalho Chehab 
25569a0bf528SMauro Carvalho Chehab 	switch (mode) {
25579a0bf528SMauro Carvalho Chehab 	case DEMOUT_ON_HOSTBUS:
25585a0e2a4eSMauro Carvalho Chehab 			dprintk("SET DEM OUT OLD INTERF ON HOST BUS\n");
25599a0bf528SMauro Carvalho Chehab 			dib7090_enMpegMux(state, 0);
25609a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<6);
25619a0bf528SMauro Carvalho Chehab 			break;
25629a0bf528SMauro Carvalho Chehab 	case DIBTX_ON_HOSTBUS:
25635a0e2a4eSMauro Carvalho Chehab 			dprintk("SET DIBSTREAM TX ON HOST BUS\n");
25649a0bf528SMauro Carvalho Chehab 			dib7090_enMpegMux(state, 0);
25659a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<5);
25669a0bf528SMauro Carvalho Chehab 			break;
25679a0bf528SMauro Carvalho Chehab 	case MPEG_ON_HOSTBUS:
25685a0e2a4eSMauro Carvalho Chehab 			dprintk("SET MPEG MUX ON HOST BUS\n");
25699a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<4);
25709a0bf528SMauro Carvalho Chehab 			break;
25719a0bf528SMauro Carvalho Chehab 	default:
25729a0bf528SMauro Carvalho Chehab 			break;
25739a0bf528SMauro Carvalho Chehab 	}
25749a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1288, reg_1288);
25759a0bf528SMauro Carvalho Chehab }
25769a0bf528SMauro Carvalho Chehab 
257718ef20daSHans Verkuil static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
25789a0bf528SMauro Carvalho Chehab {
25799a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
25809a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
25819a0bf528SMauro Carvalho Chehab 
25829a0bf528SMauro Carvalho Chehab 	switch (onoff) {
25839a0bf528SMauro Carvalho Chehab 	case 0: /* only use the internal way - not the diversity input */
25845a0e2a4eSMauro Carvalho Chehab 			dprintk("%s mode OFF : by default Enable Mpeg INPUT\n", __func__);
25859a0bf528SMauro Carvalho Chehab 			dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
25869a0bf528SMauro Carvalho Chehab 
25879a0bf528SMauro Carvalho Chehab 			/* Do not divide the serial clock of MPEG MUX */
25889a0bf528SMauro Carvalho Chehab 			/* in SERIAL MODE in case input mode MPEG is used */
25899a0bf528SMauro Carvalho Chehab 			reg_1287 = dib7000p_read_word(state, 1287);
25909a0bf528SMauro Carvalho Chehab 			/* enSerialClkDiv2 == 1 ? */
25919a0bf528SMauro Carvalho Chehab 			if ((reg_1287 & 0x1) == 1) {
25929a0bf528SMauro Carvalho Chehab 				/* force enSerialClkDiv2 = 0 */
25939a0bf528SMauro Carvalho Chehab 				reg_1287 &= ~0x1;
25949a0bf528SMauro Carvalho Chehab 				dib7000p_write_word(state, 1287, reg_1287);
25959a0bf528SMauro Carvalho Chehab 			}
25969a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 1;
25979a0bf528SMauro Carvalho Chehab 			break;
25989a0bf528SMauro Carvalho Chehab 	case 1: /* both ways */
25999a0bf528SMauro Carvalho Chehab 	case 2: /* only the diversity input */
26005a0e2a4eSMauro Carvalho Chehab 			dprintk("%s ON : Enable diversity INPUT\n", __func__);
26019a0bf528SMauro Carvalho Chehab 			dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
26029a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 0;
26039a0bf528SMauro Carvalho Chehab 			break;
26049a0bf528SMauro Carvalho Chehab 	}
26059a0bf528SMauro Carvalho Chehab 
26069a0bf528SMauro Carvalho Chehab 	dib7000p_set_diversity_in(&state->demod, onoff);
26079a0bf528SMauro Carvalho Chehab 	return 0;
26089a0bf528SMauro Carvalho Chehab }
26099a0bf528SMauro Carvalho Chehab 
26109a0bf528SMauro Carvalho Chehab static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
26119a0bf528SMauro Carvalho Chehab {
26129a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
26139a0bf528SMauro Carvalho Chehab 
26149a0bf528SMauro Carvalho Chehab 	u16 outreg, smo_mode, fifo_threshold;
26159a0bf528SMauro Carvalho Chehab 	u8 prefer_mpeg_mux_use = 1;
26169a0bf528SMauro Carvalho Chehab 	int ret = 0;
26179a0bf528SMauro Carvalho Chehab 
26189a0bf528SMauro Carvalho Chehab 	dib7090_host_bus_drive(state, 1);
26199a0bf528SMauro Carvalho Chehab 
26209a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
26219a0bf528SMauro Carvalho Chehab 	smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
26229a0bf528SMauro Carvalho Chehab 	outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
26239a0bf528SMauro Carvalho Chehab 
26249a0bf528SMauro Carvalho Chehab 	switch (mode) {
26259a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:
26269a0bf528SMauro Carvalho Chehab 		outreg = 0;
26279a0bf528SMauro Carvalho Chehab 		break;
26289a0bf528SMauro Carvalho Chehab 
26299a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:
26309a0bf528SMauro Carvalho Chehab 		if (prefer_mpeg_mux_use) {
26315a0e2a4eSMauro Carvalho Chehab 			dprintk("setting output mode TS_SERIAL using Mpeg Mux\n");
26329a0bf528SMauro Carvalho Chehab 			dib7090_configMpegMux(state, 3, 1, 1);
26339a0bf528SMauro Carvalho Chehab 			dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
26349a0bf528SMauro Carvalho Chehab 		} else {/* Use Smooth block */
26355a0e2a4eSMauro Carvalho Chehab 			dprintk("setting output mode TS_SERIAL using Smooth bloc\n");
26369a0bf528SMauro Carvalho Chehab 			dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
26379a0bf528SMauro Carvalho Chehab 			outreg |= (2<<6) | (0 << 1);
26389a0bf528SMauro Carvalho Chehab 		}
26399a0bf528SMauro Carvalho Chehab 		break;
26409a0bf528SMauro Carvalho Chehab 
26419a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:
26429a0bf528SMauro Carvalho Chehab 		if (prefer_mpeg_mux_use) {
26435a0e2a4eSMauro Carvalho Chehab 			dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux\n");
26449a0bf528SMauro Carvalho Chehab 			dib7090_configMpegMux(state, 2, 0, 0);
26459a0bf528SMauro Carvalho Chehab 			dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
26469a0bf528SMauro Carvalho Chehab 		} else { /* Use Smooth block */
26475a0e2a4eSMauro Carvalho Chehab 			dprintk("setting output mode TS_PARALLEL_GATED using Smooth block\n");
26489a0bf528SMauro Carvalho Chehab 			dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
26499a0bf528SMauro Carvalho Chehab 			outreg |= (0<<6);
26509a0bf528SMauro Carvalho Chehab 		}
26519a0bf528SMauro Carvalho Chehab 		break;
26529a0bf528SMauro Carvalho Chehab 
26539a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK:	/* Using Smooth block only */
26545a0e2a4eSMauro Carvalho Chehab 		dprintk("setting output mode TS_PARALLEL_CONT using Smooth block\n");
26559a0bf528SMauro Carvalho Chehab 		dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
26569a0bf528SMauro Carvalho Chehab 		outreg |= (1<<6);
26579a0bf528SMauro Carvalho Chehab 		break;
26589a0bf528SMauro Carvalho Chehab 
26599a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:	/* Using Smooth block because not supported by new Mpeg Mux bloc */
26605a0e2a4eSMauro Carvalho Chehab 		dprintk("setting output mode TS_FIFO using Smooth block\n");
26619a0bf528SMauro Carvalho Chehab 		dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
26629a0bf528SMauro Carvalho Chehab 		outreg |= (5<<6);
26639a0bf528SMauro Carvalho Chehab 		smo_mode |= (3 << 1);
26649a0bf528SMauro Carvalho Chehab 		fifo_threshold = 512;
26659a0bf528SMauro Carvalho Chehab 		break;
26669a0bf528SMauro Carvalho Chehab 
26679a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
26685a0e2a4eSMauro Carvalho Chehab 		dprintk("setting output mode MODE_DIVERSITY\n");
26699a0bf528SMauro Carvalho Chehab 		dib7090_setDibTxMux(state, DIV_ON_DIBTX);
26709a0bf528SMauro Carvalho Chehab 		dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
26719a0bf528SMauro Carvalho Chehab 		break;
26729a0bf528SMauro Carvalho Chehab 
26739a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
26745a0e2a4eSMauro Carvalho Chehab 		dprintk("setting output mode MODE_ANALOG_ADC\n");
26759a0bf528SMauro Carvalho Chehab 		dib7090_setDibTxMux(state, ADC_ON_DIBTX);
26769a0bf528SMauro Carvalho Chehab 		dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
26779a0bf528SMauro Carvalho Chehab 		break;
26789a0bf528SMauro Carvalho Chehab 	}
26799a0bf528SMauro Carvalho Chehab 	if (mode != OUTMODE_HIGH_Z)
26809a0bf528SMauro Carvalho Chehab 		outreg |= (1 << 10);
26819a0bf528SMauro Carvalho Chehab 
26829a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
26839a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
26849a0bf528SMauro Carvalho Chehab 
26859a0bf528SMauro Carvalho Chehab 	ret |= dib7000p_write_word(state, 235, smo_mode);
26869a0bf528SMauro Carvalho Chehab 	ret |= dib7000p_write_word(state, 236, fifo_threshold);	/* synchronous fread */
26879a0bf528SMauro Carvalho Chehab 	ret |= dib7000p_write_word(state, 1286, outreg);
26889a0bf528SMauro Carvalho Chehab 
26899a0bf528SMauro Carvalho Chehab 	return ret;
26909a0bf528SMauro Carvalho Chehab }
26919a0bf528SMauro Carvalho Chehab 
26928abe4a0aSMauro Carvalho Chehab static int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
26939a0bf528SMauro Carvalho Chehab {
26949a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
26959a0bf528SMauro Carvalho Chehab 	u16 en_cur_state;
26969a0bf528SMauro Carvalho Chehab 
26975a0e2a4eSMauro Carvalho Chehab 	dprintk("sleep dib7090: %d\n", onoff);
26989a0bf528SMauro Carvalho Chehab 
26999a0bf528SMauro Carvalho Chehab 	en_cur_state = dib7000p_read_word(state, 1922);
27009a0bf528SMauro Carvalho Chehab 
27019a0bf528SMauro Carvalho Chehab 	if (en_cur_state > 0xff)
27029a0bf528SMauro Carvalho Chehab 		state->tuner_enable = en_cur_state;
27039a0bf528SMauro Carvalho Chehab 
27049a0bf528SMauro Carvalho Chehab 	if (onoff)
27059a0bf528SMauro Carvalho Chehab 		en_cur_state &= 0x00ff;
27069a0bf528SMauro Carvalho Chehab 	else {
27079a0bf528SMauro Carvalho Chehab 		if (state->tuner_enable != 0)
27089a0bf528SMauro Carvalho Chehab 			en_cur_state = state->tuner_enable;
27099a0bf528SMauro Carvalho Chehab 	}
27109a0bf528SMauro Carvalho Chehab 
27119a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1922, en_cur_state);
27129a0bf528SMauro Carvalho Chehab 
27139a0bf528SMauro Carvalho Chehab 	return 0;
27149a0bf528SMauro Carvalho Chehab }
27159a0bf528SMauro Carvalho Chehab 
27168abe4a0aSMauro Carvalho Chehab static int dib7090_get_adc_power(struct dvb_frontend *fe)
27179a0bf528SMauro Carvalho Chehab {
27189a0bf528SMauro Carvalho Chehab 	return dib7000p_get_adc_power(fe);
27199a0bf528SMauro Carvalho Chehab }
27209a0bf528SMauro Carvalho Chehab 
27218abe4a0aSMauro Carvalho Chehab static int dib7090_slave_reset(struct dvb_frontend *fe)
27229a0bf528SMauro Carvalho Chehab {
27239a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
27249a0bf528SMauro Carvalho Chehab 	u16 reg;
27259a0bf528SMauro Carvalho Chehab 
27269a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1794);
27279a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1794, reg | (4 << 12));
27289a0bf528SMauro Carvalho Chehab 
27299a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1032, 0xffff);
27309a0bf528SMauro Carvalho Chehab 	return 0;
27319a0bf528SMauro Carvalho Chehab }
27329a0bf528SMauro Carvalho Chehab 
2733bd336e63SMax Kellermann static const struct dvb_frontend_ops dib7000p_ops;
27348abe4a0aSMauro Carvalho Chehab static struct dvb_frontend *dib7000p_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
27359a0bf528SMauro Carvalho Chehab {
27369a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *demod;
27379a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *st;
27389a0bf528SMauro Carvalho Chehab 	st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
27399a0bf528SMauro Carvalho Chehab 	if (st == NULL)
27409a0bf528SMauro Carvalho Chehab 		return NULL;
27419a0bf528SMauro Carvalho Chehab 
27429a0bf528SMauro Carvalho Chehab 	memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
27439a0bf528SMauro Carvalho Chehab 	st->i2c_adap = i2c_adap;
27449a0bf528SMauro Carvalho Chehab 	st->i2c_addr = i2c_addr;
27459a0bf528SMauro Carvalho Chehab 	st->gpio_val = cfg->gpio_val;
27469a0bf528SMauro Carvalho Chehab 	st->gpio_dir = cfg->gpio_dir;
27479a0bf528SMauro Carvalho Chehab 
27489a0bf528SMauro Carvalho Chehab 	/* Ensure the output mode remains at the previous default if it's
27499a0bf528SMauro Carvalho Chehab 	 * not specifically set by the caller.
27509a0bf528SMauro Carvalho Chehab 	 */
27519a0bf528SMauro Carvalho Chehab 	if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
27529a0bf528SMauro Carvalho Chehab 		st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
27539a0bf528SMauro Carvalho Chehab 
27549a0bf528SMauro Carvalho Chehab 	demod = &st->demod;
27559a0bf528SMauro Carvalho Chehab 	demod->demodulator_priv = st;
27569a0bf528SMauro Carvalho Chehab 	memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
27579a0bf528SMauro Carvalho Chehab 	mutex_init(&st->i2c_buffer_lock);
27589a0bf528SMauro Carvalho Chehab 
27599a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1287, 0x0003);	/* sram lead in, rdy */
27609a0bf528SMauro Carvalho Chehab 
27619a0bf528SMauro Carvalho Chehab 	if (dib7000p_identify(st) != 0)
27629a0bf528SMauro Carvalho Chehab 		goto error;
27639a0bf528SMauro Carvalho Chehab 
27649a0bf528SMauro Carvalho Chehab 	st->version = dib7000p_read_word(st, 897);
27659a0bf528SMauro Carvalho Chehab 
27669a0bf528SMauro Carvalho Chehab 	/* FIXME: make sure the dev.parent field is initialized, or else
27679a0bf528SMauro Carvalho Chehab 	   request_firmware() will hit an OOPS (this should be moved somewhere
27689a0bf528SMauro Carvalho Chehab 	   more common) */
27699a0bf528SMauro Carvalho Chehab 	st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
27709a0bf528SMauro Carvalho Chehab 
27719a0bf528SMauro Carvalho Chehab 	dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
27729a0bf528SMauro Carvalho Chehab 
27739a0bf528SMauro Carvalho Chehab 	/* init 7090 tuner adapter */
27749a0bf528SMauro Carvalho Chehab 	strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
27759a0bf528SMauro Carvalho Chehab 	st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
27769a0bf528SMauro Carvalho Chehab 	st->dib7090_tuner_adap.algo_data = NULL;
27779a0bf528SMauro Carvalho Chehab 	st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
27789a0bf528SMauro Carvalho Chehab 	i2c_set_adapdata(&st->dib7090_tuner_adap, st);
27799a0bf528SMauro Carvalho Chehab 	i2c_add_adapter(&st->dib7090_tuner_adap);
27809a0bf528SMauro Carvalho Chehab 
27819a0bf528SMauro Carvalho Chehab 	dib7000p_demod_reset(st);
27829a0bf528SMauro Carvalho Chehab 
2783041ad449SMauro Carvalho Chehab 	dib7000p_reset_stats(demod);
2784041ad449SMauro Carvalho Chehab 
27859a0bf528SMauro Carvalho Chehab 	if (st->version == SOC7090) {
27869a0bf528SMauro Carvalho Chehab 		dib7090_set_output_mode(demod, st->cfg.output_mode);
27879a0bf528SMauro Carvalho Chehab 		dib7090_set_diversity_in(demod, 0);
27889a0bf528SMauro Carvalho Chehab 	}
27899a0bf528SMauro Carvalho Chehab 
27909a0bf528SMauro Carvalho Chehab 	return demod;
27919a0bf528SMauro Carvalho Chehab 
27929a0bf528SMauro Carvalho Chehab error:
27939a0bf528SMauro Carvalho Chehab 	kfree(st);
27949a0bf528SMauro Carvalho Chehab 	return NULL;
27959a0bf528SMauro Carvalho Chehab }
27968abe4a0aSMauro Carvalho Chehab 
27978abe4a0aSMauro Carvalho Chehab void *dib7000p_attach(struct dib7000p_ops *ops)
27988abe4a0aSMauro Carvalho Chehab {
27998abe4a0aSMauro Carvalho Chehab 	if (!ops)
28008abe4a0aSMauro Carvalho Chehab 		return NULL;
28018abe4a0aSMauro Carvalho Chehab 
28028abe4a0aSMauro Carvalho Chehab 	ops->slave_reset = dib7090_slave_reset;
28038abe4a0aSMauro Carvalho Chehab 	ops->get_adc_power = dib7090_get_adc_power;
28048abe4a0aSMauro Carvalho Chehab 	ops->dib7000pc_detection = dib7000pc_detection;
28058abe4a0aSMauro Carvalho Chehab 	ops->get_i2c_tuner = dib7090_get_i2c_tuner;
28068abe4a0aSMauro Carvalho Chehab 	ops->tuner_sleep = dib7090_tuner_sleep;
28078abe4a0aSMauro Carvalho Chehab 	ops->init = dib7000p_init;
28088abe4a0aSMauro Carvalho Chehab 	ops->set_agc1_min = dib7000p_set_agc1_min;
28098abe4a0aSMauro Carvalho Chehab 	ops->set_gpio = dib7000p_set_gpio;
28108abe4a0aSMauro Carvalho Chehab 	ops->i2c_enumeration = dib7000p_i2c_enumeration;
28118abe4a0aSMauro Carvalho Chehab 	ops->pid_filter = dib7000p_pid_filter;
28128abe4a0aSMauro Carvalho Chehab 	ops->pid_filter_ctrl = dib7000p_pid_filter_ctrl;
28138abe4a0aSMauro Carvalho Chehab 	ops->get_i2c_master = dib7000p_get_i2c_master;
28148abe4a0aSMauro Carvalho Chehab 	ops->update_pll = dib7000p_update_pll;
28158abe4a0aSMauro Carvalho Chehab 	ops->ctrl_timf = dib7000p_ctrl_timf;
28168abe4a0aSMauro Carvalho Chehab 	ops->get_agc_values = dib7000p_get_agc_values;
28178abe4a0aSMauro Carvalho Chehab 	ops->set_wbd_ref = dib7000p_set_wbd_ref;
28188abe4a0aSMauro Carvalho Chehab 
28198abe4a0aSMauro Carvalho Chehab 	return ops;
28208abe4a0aSMauro Carvalho Chehab }
28218abe4a0aSMauro Carvalho Chehab EXPORT_SYMBOL(dib7000p_attach);
28229a0bf528SMauro Carvalho Chehab 
2823bd336e63SMax Kellermann static const struct dvb_frontend_ops dib7000p_ops = {
28249a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_DVBT },
28259a0bf528SMauro Carvalho Chehab 	.info = {
28269a0bf528SMauro Carvalho Chehab 		 .name = "DiBcom 7000PC",
28279a0bf528SMauro Carvalho Chehab 		 .frequency_min = 44250000,
28289a0bf528SMauro Carvalho Chehab 		 .frequency_max = 867250000,
28299a0bf528SMauro Carvalho Chehab 		 .frequency_stepsize = 62500,
28309a0bf528SMauro Carvalho Chehab 		 .caps = FE_CAN_INVERSION_AUTO |
28319a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
28329a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
28339a0bf528SMauro Carvalho Chehab 		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
28349a0bf528SMauro Carvalho Chehab 		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
28359a0bf528SMauro Carvalho Chehab 		 },
28369a0bf528SMauro Carvalho Chehab 
28379a0bf528SMauro Carvalho Chehab 	.release = dib7000p_release,
28389a0bf528SMauro Carvalho Chehab 
28399a0bf528SMauro Carvalho Chehab 	.init = dib7000p_wakeup,
28409a0bf528SMauro Carvalho Chehab 	.sleep = dib7000p_sleep,
28419a0bf528SMauro Carvalho Chehab 
28429a0bf528SMauro Carvalho Chehab 	.set_frontend = dib7000p_set_frontend,
28439a0bf528SMauro Carvalho Chehab 	.get_tune_settings = dib7000p_fe_get_tune_settings,
28449a0bf528SMauro Carvalho Chehab 	.get_frontend = dib7000p_get_frontend,
28459a0bf528SMauro Carvalho Chehab 
28469a0bf528SMauro Carvalho Chehab 	.read_status = dib7000p_read_status,
28479a0bf528SMauro Carvalho Chehab 	.read_ber = dib7000p_read_ber,
28489a0bf528SMauro Carvalho Chehab 	.read_signal_strength = dib7000p_read_signal_strength,
28499a0bf528SMauro Carvalho Chehab 	.read_snr = dib7000p_read_snr,
28509a0bf528SMauro Carvalho Chehab 	.read_ucblocks = dib7000p_read_unc_blocks,
28519a0bf528SMauro Carvalho Chehab };
28529a0bf528SMauro Carvalho Chehab 
285399e44da7SPatrick Boettcher MODULE_AUTHOR("Olivier Grenie <olivie.grenie@parrot.com>");
285499e44da7SPatrick Boettcher MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
28559a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
28569a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
2857