xref: /openbmc/linux/drivers/media/dvb-frontends/dib7000p.c (revision 8abe4a0a3f6d4217b16a1a3f68cd5c72ab5a058e)
19a0bf528SMauro Carvalho Chehab /*
29a0bf528SMauro Carvalho Chehab  * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
39a0bf528SMauro Carvalho Chehab  *
49a0bf528SMauro Carvalho Chehab  * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
59a0bf528SMauro Carvalho Chehab  *
69a0bf528SMauro Carvalho Chehab  * This program is free software; you can redistribute it and/or
79a0bf528SMauro Carvalho Chehab  *	modify it under the terms of the GNU General Public License as
89a0bf528SMauro Carvalho Chehab  *	published by the Free Software Foundation, version 2.
99a0bf528SMauro Carvalho Chehab  */
109a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
119a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
129a0bf528SMauro Carvalho Chehab #include <linux/i2c.h>
139a0bf528SMauro Carvalho Chehab #include <linux/mutex.h>
149a0bf528SMauro Carvalho Chehab 
159a0bf528SMauro Carvalho Chehab #include "dvb_math.h"
169a0bf528SMauro Carvalho Chehab #include "dvb_frontend.h"
179a0bf528SMauro Carvalho Chehab 
189a0bf528SMauro Carvalho Chehab #include "dib7000p.h"
199a0bf528SMauro Carvalho Chehab 
209a0bf528SMauro Carvalho Chehab static int debug;
219a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
229a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
239a0bf528SMauro Carvalho Chehab 
249a0bf528SMauro Carvalho Chehab static int buggy_sfn_workaround;
259a0bf528SMauro Carvalho Chehab module_param(buggy_sfn_workaround, int, 0644);
269a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
279a0bf528SMauro Carvalho Chehab 
289a0bf528SMauro Carvalho Chehab #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
299a0bf528SMauro Carvalho Chehab 
309a0bf528SMauro Carvalho Chehab struct i2c_device {
319a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *i2c_adap;
329a0bf528SMauro Carvalho Chehab 	u8 i2c_addr;
339a0bf528SMauro Carvalho Chehab };
349a0bf528SMauro Carvalho Chehab 
359a0bf528SMauro Carvalho Chehab struct dib7000p_state {
369a0bf528SMauro Carvalho Chehab 	struct dvb_frontend demod;
379a0bf528SMauro Carvalho Chehab 	struct dib7000p_config cfg;
389a0bf528SMauro Carvalho Chehab 
399a0bf528SMauro Carvalho Chehab 	u8 i2c_addr;
409a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *i2c_adap;
419a0bf528SMauro Carvalho Chehab 
429a0bf528SMauro Carvalho Chehab 	struct dibx000_i2c_master i2c_master;
439a0bf528SMauro Carvalho Chehab 
449a0bf528SMauro Carvalho Chehab 	u16 wbd_ref;
459a0bf528SMauro Carvalho Chehab 
469a0bf528SMauro Carvalho Chehab 	u8 current_band;
479a0bf528SMauro Carvalho Chehab 	u32 current_bandwidth;
489a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *current_agc;
499a0bf528SMauro Carvalho Chehab 	u32 timf;
509a0bf528SMauro Carvalho Chehab 
519a0bf528SMauro Carvalho Chehab 	u8 div_force_off:1;
529a0bf528SMauro Carvalho Chehab 	u8 div_state:1;
539a0bf528SMauro Carvalho Chehab 	u16 div_sync_wait;
549a0bf528SMauro Carvalho Chehab 
559a0bf528SMauro Carvalho Chehab 	u8 agc_state;
569a0bf528SMauro Carvalho Chehab 
579a0bf528SMauro Carvalho Chehab 	u16 gpio_dir;
589a0bf528SMauro Carvalho Chehab 	u16 gpio_val;
599a0bf528SMauro Carvalho Chehab 
609a0bf528SMauro Carvalho Chehab 	u8 sfn_workaround_active:1;
619a0bf528SMauro Carvalho Chehab 
629a0bf528SMauro Carvalho Chehab #define SOC7090 0x7090
639a0bf528SMauro Carvalho Chehab 	u16 version;
649a0bf528SMauro Carvalho Chehab 
659a0bf528SMauro Carvalho Chehab 	u16 tuner_enable;
669a0bf528SMauro Carvalho Chehab 	struct i2c_adapter dib7090_tuner_adap;
679a0bf528SMauro Carvalho Chehab 
689a0bf528SMauro Carvalho Chehab 	/* for the I2C transfer */
699a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2];
709a0bf528SMauro Carvalho Chehab 	u8 i2c_write_buffer[4];
719a0bf528SMauro Carvalho Chehab 	u8 i2c_read_buffer[2];
729a0bf528SMauro Carvalho Chehab 	struct mutex i2c_buffer_lock;
739a0bf528SMauro Carvalho Chehab 
749a0bf528SMauro Carvalho Chehab 	u8 input_mode_mpeg;
759a0bf528SMauro Carvalho Chehab };
769a0bf528SMauro Carvalho Chehab 
779a0bf528SMauro Carvalho Chehab enum dib7000p_power_mode {
789a0bf528SMauro Carvalho Chehab 	DIB7000P_POWER_ALL = 0,
799a0bf528SMauro Carvalho Chehab 	DIB7000P_POWER_ANALOG_ADC,
809a0bf528SMauro Carvalho Chehab 	DIB7000P_POWER_INTERFACE_ONLY,
819a0bf528SMauro Carvalho Chehab };
829a0bf528SMauro Carvalho Chehab 
839a0bf528SMauro Carvalho Chehab /* dib7090 specific fonctions */
849a0bf528SMauro Carvalho Chehab static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
859a0bf528SMauro Carvalho Chehab static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
869a0bf528SMauro Carvalho Chehab static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode);
879a0bf528SMauro Carvalho Chehab static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode);
889a0bf528SMauro Carvalho Chehab 
899a0bf528SMauro Carvalho Chehab static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
909a0bf528SMauro Carvalho Chehab {
919a0bf528SMauro Carvalho Chehab 	u16 ret;
929a0bf528SMauro Carvalho Chehab 
939a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
949a0bf528SMauro Carvalho Chehab 		dprintk("could not acquire lock");
959a0bf528SMauro Carvalho Chehab 		return 0;
969a0bf528SMauro Carvalho Chehab 	}
979a0bf528SMauro Carvalho Chehab 
989a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = reg >> 8;
999a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
1009a0bf528SMauro Carvalho Chehab 
1019a0bf528SMauro Carvalho Chehab 	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
1029a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c_addr >> 1;
1039a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
1049a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
1059a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 2;
1069a0bf528SMauro Carvalho Chehab 	state->msg[1].addr = state->i2c_addr >> 1;
1079a0bf528SMauro Carvalho Chehab 	state->msg[1].flags = I2C_M_RD;
1089a0bf528SMauro Carvalho Chehab 	state->msg[1].buf = state->i2c_read_buffer;
1099a0bf528SMauro Carvalho Chehab 	state->msg[1].len = 2;
1109a0bf528SMauro Carvalho Chehab 
1119a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
1129a0bf528SMauro Carvalho Chehab 		dprintk("i2c read error on %d", reg);
1139a0bf528SMauro Carvalho Chehab 
1149a0bf528SMauro Carvalho Chehab 	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
1159a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
1169a0bf528SMauro Carvalho Chehab 	return ret;
1179a0bf528SMauro Carvalho Chehab }
1189a0bf528SMauro Carvalho Chehab 
1199a0bf528SMauro Carvalho Chehab static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
1209a0bf528SMauro Carvalho Chehab {
1219a0bf528SMauro Carvalho Chehab 	int ret;
1229a0bf528SMauro Carvalho Chehab 
1239a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
1249a0bf528SMauro Carvalho Chehab 		dprintk("could not acquire lock");
1259a0bf528SMauro Carvalho Chehab 		return -EINVAL;
1269a0bf528SMauro Carvalho Chehab 	}
1279a0bf528SMauro Carvalho Chehab 
1289a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
1299a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
1309a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
1319a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[3] = val & 0xff;
1329a0bf528SMauro Carvalho Chehab 
1339a0bf528SMauro Carvalho Chehab 	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
1349a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c_addr >> 1;
1359a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
1369a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
1379a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 4;
1389a0bf528SMauro Carvalho Chehab 
1399a0bf528SMauro Carvalho Chehab 	ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
1409a0bf528SMauro Carvalho Chehab 			-EREMOTEIO : 0);
1419a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
1429a0bf528SMauro Carvalho Chehab 	return ret;
1439a0bf528SMauro Carvalho Chehab }
1449a0bf528SMauro Carvalho Chehab 
1459a0bf528SMauro Carvalho Chehab static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
1469a0bf528SMauro Carvalho Chehab {
1479a0bf528SMauro Carvalho Chehab 	u16 l = 0, r, *n;
1489a0bf528SMauro Carvalho Chehab 	n = buf;
1499a0bf528SMauro Carvalho Chehab 	l = *n++;
1509a0bf528SMauro Carvalho Chehab 	while (l) {
1519a0bf528SMauro Carvalho Chehab 		r = *n++;
1529a0bf528SMauro Carvalho Chehab 
1539a0bf528SMauro Carvalho Chehab 		do {
1549a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, r, *n++);
1559a0bf528SMauro Carvalho Chehab 			r++;
1569a0bf528SMauro Carvalho Chehab 		} while (--l);
1579a0bf528SMauro Carvalho Chehab 		l = *n++;
1589a0bf528SMauro Carvalho Chehab 	}
1599a0bf528SMauro Carvalho Chehab }
1609a0bf528SMauro Carvalho Chehab 
1619a0bf528SMauro Carvalho Chehab static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
1629a0bf528SMauro Carvalho Chehab {
1639a0bf528SMauro Carvalho Chehab 	int ret = 0;
1649a0bf528SMauro Carvalho Chehab 	u16 outreg, fifo_threshold, smo_mode;
1659a0bf528SMauro Carvalho Chehab 
1669a0bf528SMauro Carvalho Chehab 	outreg = 0;
1679a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
1689a0bf528SMauro Carvalho Chehab 	smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
1699a0bf528SMauro Carvalho Chehab 
1709a0bf528SMauro Carvalho Chehab 	dprintk("setting output mode for demod %p to %d", &state->demod, mode);
1719a0bf528SMauro Carvalho Chehab 
1729a0bf528SMauro Carvalho Chehab 	switch (mode) {
1739a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:
1749a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10);	/* 0x0400 */
1759a0bf528SMauro Carvalho Chehab 		break;
1769a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK:
1779a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (1 << 6);	/* 0x0440 */
1789a0bf528SMauro Carvalho Chehab 		break;
1799a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:
1809a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (2 << 6) | (0 << 1);	/* 0x0480 */
1819a0bf528SMauro Carvalho Chehab 		break;
1829a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
1839a0bf528SMauro Carvalho Chehab 		if (state->cfg.hostbus_diversity)
1849a0bf528SMauro Carvalho Chehab 			outreg = (1 << 10) | (4 << 6);	/* 0x0500 */
1859a0bf528SMauro Carvalho Chehab 		else
1869a0bf528SMauro Carvalho Chehab 			outreg = (1 << 11);
1879a0bf528SMauro Carvalho Chehab 		break;
1889a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:
1899a0bf528SMauro Carvalho Chehab 		smo_mode |= (3 << 1);
1909a0bf528SMauro Carvalho Chehab 		fifo_threshold = 512;
1919a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (5 << 6);
1929a0bf528SMauro Carvalho Chehab 		break;
1939a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
1949a0bf528SMauro Carvalho Chehab 		outreg = (1 << 10) | (3 << 6);
1959a0bf528SMauro Carvalho Chehab 		break;
1969a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:
1979a0bf528SMauro Carvalho Chehab 		outreg = 0;
1989a0bf528SMauro Carvalho Chehab 		break;
1999a0bf528SMauro Carvalho Chehab 	default:
2009a0bf528SMauro Carvalho Chehab 		dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod);
2019a0bf528SMauro Carvalho Chehab 		break;
2029a0bf528SMauro Carvalho Chehab 	}
2039a0bf528SMauro Carvalho Chehab 
2049a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
2059a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
2069a0bf528SMauro Carvalho Chehab 
2079a0bf528SMauro Carvalho Chehab 	ret |= dib7000p_write_word(state, 235, smo_mode);
2089a0bf528SMauro Carvalho Chehab 	ret |= dib7000p_write_word(state, 236, fifo_threshold);	/* synchronous fread */
2099a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090)
2109a0bf528SMauro Carvalho Chehab 		ret |= dib7000p_write_word(state, 1286, outreg);	/* P_Div_active */
2119a0bf528SMauro Carvalho Chehab 
2129a0bf528SMauro Carvalho Chehab 	return ret;
2139a0bf528SMauro Carvalho Chehab }
2149a0bf528SMauro Carvalho Chehab 
2159a0bf528SMauro Carvalho Chehab static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
2169a0bf528SMauro Carvalho Chehab {
2179a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
2189a0bf528SMauro Carvalho Chehab 
2199a0bf528SMauro Carvalho Chehab 	if (state->div_force_off) {
2209a0bf528SMauro Carvalho Chehab 		dprintk("diversity combination deactivated - forced by COFDM parameters");
2219a0bf528SMauro Carvalho Chehab 		onoff = 0;
2229a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 207, 0);
2239a0bf528SMauro Carvalho Chehab 	} else
2249a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
2259a0bf528SMauro Carvalho Chehab 
2269a0bf528SMauro Carvalho Chehab 	state->div_state = (u8) onoff;
2279a0bf528SMauro Carvalho Chehab 
2289a0bf528SMauro Carvalho Chehab 	if (onoff) {
2299a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 204, 6);
2309a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 205, 16);
2319a0bf528SMauro Carvalho Chehab 		/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
2329a0bf528SMauro Carvalho Chehab 	} else {
2339a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 204, 1);
2349a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 205, 0);
2359a0bf528SMauro Carvalho Chehab 	}
2369a0bf528SMauro Carvalho Chehab 
2379a0bf528SMauro Carvalho Chehab 	return 0;
2389a0bf528SMauro Carvalho Chehab }
2399a0bf528SMauro Carvalho Chehab 
2409a0bf528SMauro Carvalho Chehab static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
2419a0bf528SMauro Carvalho Chehab {
2429a0bf528SMauro Carvalho Chehab 	/* by default everything is powered off */
2439a0bf528SMauro Carvalho Chehab 	u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
2449a0bf528SMauro Carvalho Chehab 
2459a0bf528SMauro Carvalho Chehab 	/* now, depending on the requested mode, we power on */
2469a0bf528SMauro Carvalho Chehab 	switch (mode) {
2479a0bf528SMauro Carvalho Chehab 		/* power up everything in the demod */
2489a0bf528SMauro Carvalho Chehab 	case DIB7000P_POWER_ALL:
2499a0bf528SMauro Carvalho Chehab 		reg_774 = 0x0000;
2509a0bf528SMauro Carvalho Chehab 		reg_775 = 0x0000;
2519a0bf528SMauro Carvalho Chehab 		reg_776 = 0x0;
2529a0bf528SMauro Carvalho Chehab 		reg_899 = 0x0;
2539a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090)
2549a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x001f;
2559a0bf528SMauro Carvalho Chehab 		else
2569a0bf528SMauro Carvalho Chehab 			reg_1280 &= 0x01ff;
2579a0bf528SMauro Carvalho Chehab 		break;
2589a0bf528SMauro Carvalho Chehab 
2599a0bf528SMauro Carvalho Chehab 	case DIB7000P_POWER_ANALOG_ADC:
2609a0bf528SMauro Carvalho Chehab 		/* dem, cfg, iqc, sad, agc */
2619a0bf528SMauro Carvalho Chehab 		reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
2629a0bf528SMauro Carvalho Chehab 		/* nud */
2639a0bf528SMauro Carvalho Chehab 		reg_776 &= ~((1 << 0));
2649a0bf528SMauro Carvalho Chehab 		/* Dout */
2659a0bf528SMauro Carvalho Chehab 		if (state->version != SOC7090)
2669a0bf528SMauro Carvalho Chehab 			reg_1280 &= ~((1 << 11));
2679a0bf528SMauro Carvalho Chehab 		reg_1280 &= ~(1 << 6);
2689a0bf528SMauro Carvalho Chehab 		/* fall through wanted to enable the interfaces */
2699a0bf528SMauro Carvalho Chehab 
2709a0bf528SMauro Carvalho Chehab 		/* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
2719a0bf528SMauro Carvalho Chehab 	case DIB7000P_POWER_INTERFACE_ONLY:	/* TODO power up either SDIO or I2C */
2729a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090)
2739a0bf528SMauro Carvalho Chehab 			reg_1280 &= ~((1 << 7) | (1 << 5));
2749a0bf528SMauro Carvalho Chehab 		else
2759a0bf528SMauro Carvalho Chehab 			reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
2769a0bf528SMauro Carvalho Chehab 		break;
2779a0bf528SMauro Carvalho Chehab 
2789a0bf528SMauro Carvalho Chehab /* TODO following stuff is just converted from the dib7000-driver - check when is used what */
2799a0bf528SMauro Carvalho Chehab 	}
2809a0bf528SMauro Carvalho Chehab 
2819a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 774, reg_774);
2829a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 775, reg_775);
2839a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 776, reg_776);
2849a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1280, reg_1280);
2859a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090)
2869a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 899, reg_899);
2879a0bf528SMauro Carvalho Chehab 
2889a0bf528SMauro Carvalho Chehab 	return 0;
2899a0bf528SMauro Carvalho Chehab }
2909a0bf528SMauro Carvalho Chehab 
2919a0bf528SMauro Carvalho Chehab static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
2929a0bf528SMauro Carvalho Chehab {
2939a0bf528SMauro Carvalho Chehab 	u16 reg_908 = 0, reg_909 = 0;
2949a0bf528SMauro Carvalho Chehab 	u16 reg;
2959a0bf528SMauro Carvalho Chehab 
2969a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090) {
2979a0bf528SMauro Carvalho Chehab 		reg_908 = dib7000p_read_word(state, 908);
2989a0bf528SMauro Carvalho Chehab 		reg_909 = dib7000p_read_word(state, 909);
2999a0bf528SMauro Carvalho Chehab 	}
3009a0bf528SMauro Carvalho Chehab 
3019a0bf528SMauro Carvalho Chehab 	switch (no) {
3029a0bf528SMauro Carvalho Chehab 	case DIBX000_SLOW_ADC_ON:
3039a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090) {
3049a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 1925);
3059a0bf528SMauro Carvalho Chehab 
3069a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2));	/* en_slowAdc = 1 & reset_sladc = 1 */
3079a0bf528SMauro Carvalho Chehab 
3089a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 1925);	/* read acces to make it works... strange ... */
3099a0bf528SMauro Carvalho Chehab 			msleep(200);
3109a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 1925, reg & ~(1 << 4));	/* en_slowAdc = 1 & reset_sladc = 0 */
3119a0bf528SMauro Carvalho Chehab 
3129a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
3139a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524);	/* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
3149a0bf528SMauro Carvalho Chehab 		} else {
3159a0bf528SMauro Carvalho Chehab 			reg_909 |= (1 << 1) | (1 << 0);
3169a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 909, reg_909);
3179a0bf528SMauro Carvalho Chehab 			reg_909 &= ~(1 << 1);
3189a0bf528SMauro Carvalho Chehab 		}
3199a0bf528SMauro Carvalho Chehab 		break;
3209a0bf528SMauro Carvalho Chehab 
3219a0bf528SMauro Carvalho Chehab 	case DIBX000_SLOW_ADC_OFF:
3229a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090) {
3239a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 1925);
3249a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4));	/* reset_sladc = 1 en_slowAdc = 0 */
3259a0bf528SMauro Carvalho Chehab 		} else
3269a0bf528SMauro Carvalho Chehab 			reg_909 |= (1 << 1) | (1 << 0);
3279a0bf528SMauro Carvalho Chehab 		break;
3289a0bf528SMauro Carvalho Chehab 
3299a0bf528SMauro Carvalho Chehab 	case DIBX000_ADC_ON:
3309a0bf528SMauro Carvalho Chehab 		reg_908 &= 0x0fff;
3319a0bf528SMauro Carvalho Chehab 		reg_909 &= 0x0003;
3329a0bf528SMauro Carvalho Chehab 		break;
3339a0bf528SMauro Carvalho Chehab 
3349a0bf528SMauro Carvalho Chehab 	case DIBX000_ADC_OFF:
3359a0bf528SMauro Carvalho Chehab 		reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
3369a0bf528SMauro Carvalho Chehab 		reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
3379a0bf528SMauro Carvalho Chehab 		break;
3389a0bf528SMauro Carvalho Chehab 
3399a0bf528SMauro Carvalho Chehab 	case DIBX000_VBG_ENABLE:
3409a0bf528SMauro Carvalho Chehab 		reg_908 &= ~(1 << 15);
3419a0bf528SMauro Carvalho Chehab 		break;
3429a0bf528SMauro Carvalho Chehab 
3439a0bf528SMauro Carvalho Chehab 	case DIBX000_VBG_DISABLE:
3449a0bf528SMauro Carvalho Chehab 		reg_908 |= (1 << 15);
3459a0bf528SMauro Carvalho Chehab 		break;
3469a0bf528SMauro Carvalho Chehab 
3479a0bf528SMauro Carvalho Chehab 	default:
3489a0bf528SMauro Carvalho Chehab 		break;
3499a0bf528SMauro Carvalho Chehab 	}
3509a0bf528SMauro Carvalho Chehab 
3519a0bf528SMauro Carvalho Chehab //	dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
3529a0bf528SMauro Carvalho Chehab 
3539a0bf528SMauro Carvalho Chehab 	reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
3549a0bf528SMauro Carvalho Chehab 	reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
3559a0bf528SMauro Carvalho Chehab 
3569a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090) {
3579a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 908, reg_908);
3589a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 909, reg_909);
3599a0bf528SMauro Carvalho Chehab 	}
3609a0bf528SMauro Carvalho Chehab }
3619a0bf528SMauro Carvalho Chehab 
3629a0bf528SMauro Carvalho Chehab static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
3639a0bf528SMauro Carvalho Chehab {
3649a0bf528SMauro Carvalho Chehab 	u32 timf;
3659a0bf528SMauro Carvalho Chehab 
3669a0bf528SMauro Carvalho Chehab 	// store the current bandwidth for later use
3679a0bf528SMauro Carvalho Chehab 	state->current_bandwidth = bw;
3689a0bf528SMauro Carvalho Chehab 
3699a0bf528SMauro Carvalho Chehab 	if (state->timf == 0) {
3709a0bf528SMauro Carvalho Chehab 		dprintk("using default timf");
3719a0bf528SMauro Carvalho Chehab 		timf = state->cfg.bw->timf;
3729a0bf528SMauro Carvalho Chehab 	} else {
3739a0bf528SMauro Carvalho Chehab 		dprintk("using updated timf");
3749a0bf528SMauro Carvalho Chehab 		timf = state->timf;
3759a0bf528SMauro Carvalho Chehab 	}
3769a0bf528SMauro Carvalho Chehab 
3779a0bf528SMauro Carvalho Chehab 	timf = timf * (bw / 50) / 160;
3789a0bf528SMauro Carvalho Chehab 
3799a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
3809a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
3819a0bf528SMauro Carvalho Chehab 
3829a0bf528SMauro Carvalho Chehab 	return 0;
3839a0bf528SMauro Carvalho Chehab }
3849a0bf528SMauro Carvalho Chehab 
3859a0bf528SMauro Carvalho Chehab static int dib7000p_sad_calib(struct dib7000p_state *state)
3869a0bf528SMauro Carvalho Chehab {
3879a0bf528SMauro Carvalho Chehab /* internal */
3889a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
3899a0bf528SMauro Carvalho Chehab 
3909a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090)
3919a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 74, 2048);
3929a0bf528SMauro Carvalho Chehab 	else
3939a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 74, 776);
3949a0bf528SMauro Carvalho Chehab 
3959a0bf528SMauro Carvalho Chehab 	/* do the calibration */
3969a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 73, (1 << 0));
3979a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 73, (0 << 0));
3989a0bf528SMauro Carvalho Chehab 
3999a0bf528SMauro Carvalho Chehab 	msleep(1);
4009a0bf528SMauro Carvalho Chehab 
4019a0bf528SMauro Carvalho Chehab 	return 0;
4029a0bf528SMauro Carvalho Chehab }
4039a0bf528SMauro Carvalho Chehab 
404*8abe4a0aSMauro Carvalho Chehab static int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
4059a0bf528SMauro Carvalho Chehab {
4069a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
4079a0bf528SMauro Carvalho Chehab 	if (value > 4095)
4089a0bf528SMauro Carvalho Chehab 		value = 4095;
4099a0bf528SMauro Carvalho Chehab 	state->wbd_ref = value;
4109a0bf528SMauro Carvalho Chehab 	return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
4119a0bf528SMauro Carvalho Chehab }
4129a0bf528SMauro Carvalho Chehab 
413*8abe4a0aSMauro Carvalho Chehab static int dib7000p_get_agc_values(struct dvb_frontend *fe,
4149a0bf528SMauro Carvalho Chehab 		u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
4159a0bf528SMauro Carvalho Chehab {
4169a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
4179a0bf528SMauro Carvalho Chehab 
4189a0bf528SMauro Carvalho Chehab 	if (agc_global != NULL)
4199a0bf528SMauro Carvalho Chehab 		*agc_global = dib7000p_read_word(state, 394);
4209a0bf528SMauro Carvalho Chehab 	if (agc1 != NULL)
4219a0bf528SMauro Carvalho Chehab 		*agc1 = dib7000p_read_word(state, 392);
4229a0bf528SMauro Carvalho Chehab 	if (agc2 != NULL)
4239a0bf528SMauro Carvalho Chehab 		*agc2 = dib7000p_read_word(state, 393);
4249a0bf528SMauro Carvalho Chehab 	if (wbd != NULL)
4259a0bf528SMauro Carvalho Chehab 		*wbd = dib7000p_read_word(state, 397);
4269a0bf528SMauro Carvalho Chehab 
4279a0bf528SMauro Carvalho Chehab 	return 0;
4289a0bf528SMauro Carvalho Chehab }
4299a0bf528SMauro Carvalho Chehab 
430*8abe4a0aSMauro Carvalho Chehab static int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
4316fe1099cSOlivier Grenie {
4326fe1099cSOlivier Grenie 	struct dib7000p_state *state = fe->demodulator_priv;
4336fe1099cSOlivier Grenie 	return dib7000p_write_word(state, 108,  v);
4346fe1099cSOlivier Grenie }
4356fe1099cSOlivier Grenie 
4369a0bf528SMauro Carvalho Chehab static void dib7000p_reset_pll(struct dib7000p_state *state)
4379a0bf528SMauro Carvalho Chehab {
4389a0bf528SMauro Carvalho Chehab 	struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
4399a0bf528SMauro Carvalho Chehab 	u16 clk_cfg0;
4409a0bf528SMauro Carvalho Chehab 
4419a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090) {
4429a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1856, (!bw->pll_reset << 13) | (bw->pll_range << 12) | (bw->pll_ratio << 6) | (bw->pll_prediv));
4439a0bf528SMauro Carvalho Chehab 
4449a0bf528SMauro Carvalho Chehab 		while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
4459a0bf528SMauro Carvalho Chehab 			;
4469a0bf528SMauro Carvalho Chehab 
4479a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
4489a0bf528SMauro Carvalho Chehab 	} else {
4499a0bf528SMauro Carvalho Chehab 		/* force PLL bypass */
4509a0bf528SMauro Carvalho Chehab 		clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
4519a0bf528SMauro Carvalho Chehab 			(bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
4529a0bf528SMauro Carvalho Chehab 
4539a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 900, clk_cfg0);
4549a0bf528SMauro Carvalho Chehab 
4559a0bf528SMauro Carvalho Chehab 		/* P_pll_cfg */
4569a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
4579a0bf528SMauro Carvalho Chehab 		clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
4589a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 900, clk_cfg0);
4599a0bf528SMauro Carvalho Chehab 	}
4609a0bf528SMauro Carvalho Chehab 
4619a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
4629a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
4639a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
4649a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
4659a0bf528SMauro Carvalho Chehab 
4669a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 72, bw->sad_cfg);
4679a0bf528SMauro Carvalho Chehab }
4689a0bf528SMauro Carvalho Chehab 
4699a0bf528SMauro Carvalho Chehab static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
4709a0bf528SMauro Carvalho Chehab {
4719a0bf528SMauro Carvalho Chehab 	u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
4729a0bf528SMauro Carvalho Chehab 	internal |= (u32) dib7000p_read_word(state, 19);
4739a0bf528SMauro Carvalho Chehab 	internal /= 1000;
4749a0bf528SMauro Carvalho Chehab 
4759a0bf528SMauro Carvalho Chehab 	return internal;
4769a0bf528SMauro Carvalho Chehab }
4779a0bf528SMauro Carvalho Chehab 
478*8abe4a0aSMauro Carvalho Chehab static int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
4799a0bf528SMauro Carvalho Chehab {
4809a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
4819a0bf528SMauro Carvalho Chehab 	u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
4829a0bf528SMauro Carvalho Chehab 	u8 loopdiv, prediv;
4839a0bf528SMauro Carvalho Chehab 	u32 internal, xtal;
4849a0bf528SMauro Carvalho Chehab 
4859a0bf528SMauro Carvalho Chehab 	/* get back old values */
4869a0bf528SMauro Carvalho Chehab 	prediv = reg_1856 & 0x3f;
4879a0bf528SMauro Carvalho Chehab 	loopdiv = (reg_1856 >> 6) & 0x3f;
4889a0bf528SMauro Carvalho Chehab 
4899a0bf528SMauro Carvalho Chehab 	if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
4909a0bf528SMauro Carvalho Chehab 		dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
4919a0bf528SMauro Carvalho Chehab 		reg_1856 &= 0xf000;
4929a0bf528SMauro Carvalho Chehab 		reg_1857 = dib7000p_read_word(state, 1857);
4939a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
4949a0bf528SMauro Carvalho Chehab 
4959a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
4969a0bf528SMauro Carvalho Chehab 
4979a0bf528SMauro Carvalho Chehab 		/* write new system clk into P_sec_len */
4989a0bf528SMauro Carvalho Chehab 		internal = dib7000p_get_internal_freq(state);
4999a0bf528SMauro Carvalho Chehab 		xtal = (internal / loopdiv) * prediv;
5009a0bf528SMauro Carvalho Chehab 		internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio;	/* new internal */
5019a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
5029a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
5039a0bf528SMauro Carvalho Chehab 
5049a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
5059a0bf528SMauro Carvalho Chehab 
5069a0bf528SMauro Carvalho Chehab 		while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
5079a0bf528SMauro Carvalho Chehab 			dprintk("Waiting for PLL to lock");
5089a0bf528SMauro Carvalho Chehab 
5099a0bf528SMauro Carvalho Chehab 		return 0;
5109a0bf528SMauro Carvalho Chehab 	}
5119a0bf528SMauro Carvalho Chehab 	return -EIO;
5129a0bf528SMauro Carvalho Chehab }
5139a0bf528SMauro Carvalho Chehab 
5149a0bf528SMauro Carvalho Chehab static int dib7000p_reset_gpio(struct dib7000p_state *st)
5159a0bf528SMauro Carvalho Chehab {
5169a0bf528SMauro Carvalho Chehab 	/* reset the GPIOs */
5179a0bf528SMauro Carvalho Chehab 	dprintk("gpio dir: %x: val: %x, pwm_pos: %x", st->gpio_dir, st->gpio_val, st->cfg.gpio_pwm_pos);
5189a0bf528SMauro Carvalho Chehab 
5199a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1029, st->gpio_dir);
5209a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1030, st->gpio_val);
5219a0bf528SMauro Carvalho Chehab 
5229a0bf528SMauro Carvalho Chehab 	/* TODO 1031 is P_gpio_od */
5239a0bf528SMauro Carvalho Chehab 
5249a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
5259a0bf528SMauro Carvalho Chehab 
5269a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
5279a0bf528SMauro Carvalho Chehab 	return 0;
5289a0bf528SMauro Carvalho Chehab }
5299a0bf528SMauro Carvalho Chehab 
5309a0bf528SMauro Carvalho Chehab static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
5319a0bf528SMauro Carvalho Chehab {
5329a0bf528SMauro Carvalho Chehab 	st->gpio_dir = dib7000p_read_word(st, 1029);
5339a0bf528SMauro Carvalho Chehab 	st->gpio_dir &= ~(1 << num);	/* reset the direction bit */
5349a0bf528SMauro Carvalho Chehab 	st->gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
5359a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1029, st->gpio_dir);
5369a0bf528SMauro Carvalho Chehab 
5379a0bf528SMauro Carvalho Chehab 	st->gpio_val = dib7000p_read_word(st, 1030);
5389a0bf528SMauro Carvalho Chehab 	st->gpio_val &= ~(1 << num);	/* reset the direction bit */
5399a0bf528SMauro Carvalho Chehab 	st->gpio_val |= (val & 0x01) << num;	/* set the new value */
5409a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1030, st->gpio_val);
5419a0bf528SMauro Carvalho Chehab 
5429a0bf528SMauro Carvalho Chehab 	return 0;
5439a0bf528SMauro Carvalho Chehab }
5449a0bf528SMauro Carvalho Chehab 
545*8abe4a0aSMauro Carvalho Chehab static int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
5469a0bf528SMauro Carvalho Chehab {
5479a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
5489a0bf528SMauro Carvalho Chehab 	return dib7000p_cfg_gpio(state, num, dir, val);
5499a0bf528SMauro Carvalho Chehab }
5509a0bf528SMauro Carvalho Chehab 
5519a0bf528SMauro Carvalho Chehab static u16 dib7000p_defaults[] = {
5529a0bf528SMauro Carvalho Chehab 	// auto search configuration
5539a0bf528SMauro Carvalho Chehab 	3, 2,
5549a0bf528SMauro Carvalho Chehab 	0x0004,
5559a0bf528SMauro Carvalho Chehab 	(1<<3)|(1<<11)|(1<<12)|(1<<13),
5569a0bf528SMauro Carvalho Chehab 	0x0814,			/* Equal Lock */
5579a0bf528SMauro Carvalho Chehab 
5589a0bf528SMauro Carvalho Chehab 	12, 6,
5599a0bf528SMauro Carvalho Chehab 	0x001b,
5609a0bf528SMauro Carvalho Chehab 	0x7740,
5619a0bf528SMauro Carvalho Chehab 	0x005b,
5629a0bf528SMauro Carvalho Chehab 	0x8d80,
5639a0bf528SMauro Carvalho Chehab 	0x01c9,
5649a0bf528SMauro Carvalho Chehab 	0xc380,
5659a0bf528SMauro Carvalho Chehab 	0x0000,
5669a0bf528SMauro Carvalho Chehab 	0x0080,
5679a0bf528SMauro Carvalho Chehab 	0x0000,
5689a0bf528SMauro Carvalho Chehab 	0x0090,
5699a0bf528SMauro Carvalho Chehab 	0x0001,
5709a0bf528SMauro Carvalho Chehab 	0xd4c0,
5719a0bf528SMauro Carvalho Chehab 
5729a0bf528SMauro Carvalho Chehab 	1, 26,
5739a0bf528SMauro Carvalho Chehab 	0x6680,
5749a0bf528SMauro Carvalho Chehab 
5759a0bf528SMauro Carvalho Chehab 	/* set ADC level to -16 */
5769a0bf528SMauro Carvalho Chehab 	11, 79,
5779a0bf528SMauro Carvalho Chehab 	(1 << 13) - 825 - 117,
5789a0bf528SMauro Carvalho Chehab 	(1 << 13) - 837 - 117,
5799a0bf528SMauro Carvalho Chehab 	(1 << 13) - 811 - 117,
5809a0bf528SMauro Carvalho Chehab 	(1 << 13) - 766 - 117,
5819a0bf528SMauro Carvalho Chehab 	(1 << 13) - 737 - 117,
5829a0bf528SMauro Carvalho Chehab 	(1 << 13) - 693 - 117,
5839a0bf528SMauro Carvalho Chehab 	(1 << 13) - 648 - 117,
5849a0bf528SMauro Carvalho Chehab 	(1 << 13) - 619 - 117,
5859a0bf528SMauro Carvalho Chehab 	(1 << 13) - 575 - 117,
5869a0bf528SMauro Carvalho Chehab 	(1 << 13) - 531 - 117,
5879a0bf528SMauro Carvalho Chehab 	(1 << 13) - 501 - 117,
5889a0bf528SMauro Carvalho Chehab 
5899a0bf528SMauro Carvalho Chehab 	1, 142,
5909a0bf528SMauro Carvalho Chehab 	0x0410,
5919a0bf528SMauro Carvalho Chehab 
5929a0bf528SMauro Carvalho Chehab 	/* disable power smoothing */
5939a0bf528SMauro Carvalho Chehab 	8, 145,
5949a0bf528SMauro Carvalho Chehab 	0,
5959a0bf528SMauro Carvalho Chehab 	0,
5969a0bf528SMauro Carvalho Chehab 	0,
5979a0bf528SMauro Carvalho Chehab 	0,
5989a0bf528SMauro Carvalho Chehab 	0,
5999a0bf528SMauro Carvalho Chehab 	0,
6009a0bf528SMauro Carvalho Chehab 	0,
6019a0bf528SMauro Carvalho Chehab 	0,
6029a0bf528SMauro Carvalho Chehab 
6039a0bf528SMauro Carvalho Chehab 	1, 154,
6049a0bf528SMauro Carvalho Chehab 	1 << 13,
6059a0bf528SMauro Carvalho Chehab 
6069a0bf528SMauro Carvalho Chehab 	1, 168,
6079a0bf528SMauro Carvalho Chehab 	0x0ccd,
6089a0bf528SMauro Carvalho Chehab 
6099a0bf528SMauro Carvalho Chehab 	1, 183,
6109a0bf528SMauro Carvalho Chehab 	0x200f,
6119a0bf528SMauro Carvalho Chehab 
6129a0bf528SMauro Carvalho Chehab 	1, 212,
6139a0bf528SMauro Carvalho Chehab 		0x169,
6149a0bf528SMauro Carvalho Chehab 
6159a0bf528SMauro Carvalho Chehab 	5, 187,
6169a0bf528SMauro Carvalho Chehab 	0x023d,
6179a0bf528SMauro Carvalho Chehab 	0x00a4,
6189a0bf528SMauro Carvalho Chehab 	0x00a4,
6199a0bf528SMauro Carvalho Chehab 	0x7ff0,
6209a0bf528SMauro Carvalho Chehab 	0x3ccc,
6219a0bf528SMauro Carvalho Chehab 
6229a0bf528SMauro Carvalho Chehab 	1, 198,
6239a0bf528SMauro Carvalho Chehab 	0x800,
6249a0bf528SMauro Carvalho Chehab 
6259a0bf528SMauro Carvalho Chehab 	1, 222,
6269a0bf528SMauro Carvalho Chehab 	0x0010,
6279a0bf528SMauro Carvalho Chehab 
6289a0bf528SMauro Carvalho Chehab 	1, 235,
6299a0bf528SMauro Carvalho Chehab 	0x0062,
6309a0bf528SMauro Carvalho Chehab 
6319a0bf528SMauro Carvalho Chehab 	0,
6329a0bf528SMauro Carvalho Chehab };
6339a0bf528SMauro Carvalho Chehab 
6349a0bf528SMauro Carvalho Chehab static int dib7000p_demod_reset(struct dib7000p_state *state)
6359a0bf528SMauro Carvalho Chehab {
6369a0bf528SMauro Carvalho Chehab 	dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
6379a0bf528SMauro Carvalho Chehab 
6389a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090)
6399a0bf528SMauro Carvalho Chehab 		dibx000_reset_i2c_master(&state->i2c_master);
6409a0bf528SMauro Carvalho Chehab 
6419a0bf528SMauro Carvalho Chehab 	dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
6429a0bf528SMauro Carvalho Chehab 
6439a0bf528SMauro Carvalho Chehab 	/* restart all parts */
6449a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, 0xffff);
6459a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 771, 0xffff);
6469a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 772, 0x001f);
6479a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
6489a0bf528SMauro Carvalho Chehab 
6499a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, 0);
6509a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 771, 0);
6519a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 772, 0);
6529a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1280, 0);
6539a0bf528SMauro Carvalho Chehab 
6549a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090) {
6559a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state,  898, 0x0003);
6569a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state,  898, 0);
6579a0bf528SMauro Carvalho Chehab 	}
6589a0bf528SMauro Carvalho Chehab 
6599a0bf528SMauro Carvalho Chehab 	/* default */
6609a0bf528SMauro Carvalho Chehab 	dib7000p_reset_pll(state);
6619a0bf528SMauro Carvalho Chehab 
6629a0bf528SMauro Carvalho Chehab 	if (dib7000p_reset_gpio(state) != 0)
6639a0bf528SMauro Carvalho Chehab 		dprintk("GPIO reset was not successful.");
6649a0bf528SMauro Carvalho Chehab 
6659a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090) {
6669a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 899, 0);
6679a0bf528SMauro Carvalho Chehab 
6689a0bf528SMauro Carvalho Chehab 		/* impulse noise */
6699a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
6709a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
6719a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
6729a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 273, (0<<6) | 30);
6739a0bf528SMauro Carvalho Chehab 	}
6749a0bf528SMauro Carvalho Chehab 	if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
6759a0bf528SMauro Carvalho Chehab 		dprintk("OUTPUT_MODE could not be reset.");
6769a0bf528SMauro Carvalho Chehab 
6779a0bf528SMauro Carvalho Chehab 	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
6789a0bf528SMauro Carvalho Chehab 	dib7000p_sad_calib(state);
6799a0bf528SMauro Carvalho Chehab 	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
6809a0bf528SMauro Carvalho Chehab 
6819a0bf528SMauro Carvalho Chehab 	/* unforce divstr regardless whether i2c enumeration was done or not */
6829a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
6839a0bf528SMauro Carvalho Chehab 
6849a0bf528SMauro Carvalho Chehab 	dib7000p_set_bandwidth(state, 8000);
6859a0bf528SMauro Carvalho Chehab 
6869a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090) {
6879a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 36, 0x0755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
6889a0bf528SMauro Carvalho Chehab 	} else {
6899a0bf528SMauro Carvalho Chehab 		if (state->cfg.tuner_is_baseband)
6909a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 36, 0x0755);
6919a0bf528SMauro Carvalho Chehab 		else
6929a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 36, 0x1f55);
6939a0bf528SMauro Carvalho Chehab 	}
6949a0bf528SMauro Carvalho Chehab 
6959a0bf528SMauro Carvalho Chehab 	dib7000p_write_tab(state, dib7000p_defaults);
6969a0bf528SMauro Carvalho Chehab 	if (state->version != SOC7090) {
6979a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 901, 0x0006);
6989a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
6999a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 905, 0x2c8e);
7009a0bf528SMauro Carvalho Chehab 	}
7019a0bf528SMauro Carvalho Chehab 
7029a0bf528SMauro Carvalho Chehab 	dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
7039a0bf528SMauro Carvalho Chehab 
7049a0bf528SMauro Carvalho Chehab 	return 0;
7059a0bf528SMauro Carvalho Chehab }
7069a0bf528SMauro Carvalho Chehab 
7079a0bf528SMauro Carvalho Chehab static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
7089a0bf528SMauro Carvalho Chehab {
7099a0bf528SMauro Carvalho Chehab 	u16 tmp = 0;
7109a0bf528SMauro Carvalho Chehab 	tmp = dib7000p_read_word(state, 903);
7119a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 903, (tmp | 0x1));
7129a0bf528SMauro Carvalho Chehab 	tmp = dib7000p_read_word(state, 900);
7139a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
7149a0bf528SMauro Carvalho Chehab }
7159a0bf528SMauro Carvalho Chehab 
7169a0bf528SMauro Carvalho Chehab static void dib7000p_restart_agc(struct dib7000p_state *state)
7179a0bf528SMauro Carvalho Chehab {
7189a0bf528SMauro Carvalho Chehab 	// P_restart_iqc & P_restart_agc
7199a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
7209a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, 0x0000);
7219a0bf528SMauro Carvalho Chehab }
7229a0bf528SMauro Carvalho Chehab 
7239a0bf528SMauro Carvalho Chehab static int dib7000p_update_lna(struct dib7000p_state *state)
7249a0bf528SMauro Carvalho Chehab {
7259a0bf528SMauro Carvalho Chehab 	u16 dyn_gain;
7269a0bf528SMauro Carvalho Chehab 
7279a0bf528SMauro Carvalho Chehab 	if (state->cfg.update_lna) {
7289a0bf528SMauro Carvalho Chehab 		dyn_gain = dib7000p_read_word(state, 394);
7299a0bf528SMauro Carvalho Chehab 		if (state->cfg.update_lna(&state->demod, dyn_gain)) {
7309a0bf528SMauro Carvalho Chehab 			dib7000p_restart_agc(state);
7319a0bf528SMauro Carvalho Chehab 			return 1;
7329a0bf528SMauro Carvalho Chehab 		}
7339a0bf528SMauro Carvalho Chehab 	}
7349a0bf528SMauro Carvalho Chehab 
7359a0bf528SMauro Carvalho Chehab 	return 0;
7369a0bf528SMauro Carvalho Chehab }
7379a0bf528SMauro Carvalho Chehab 
7389a0bf528SMauro Carvalho Chehab static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
7399a0bf528SMauro Carvalho Chehab {
7409a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *agc = NULL;
7419a0bf528SMauro Carvalho Chehab 	int i;
7429a0bf528SMauro Carvalho Chehab 	if (state->current_band == band && state->current_agc != NULL)
7439a0bf528SMauro Carvalho Chehab 		return 0;
7449a0bf528SMauro Carvalho Chehab 	state->current_band = band;
7459a0bf528SMauro Carvalho Chehab 
7469a0bf528SMauro Carvalho Chehab 	for (i = 0; i < state->cfg.agc_config_count; i++)
7479a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc[i].band_caps & band) {
7489a0bf528SMauro Carvalho Chehab 			agc = &state->cfg.agc[i];
7499a0bf528SMauro Carvalho Chehab 			break;
7509a0bf528SMauro Carvalho Chehab 		}
7519a0bf528SMauro Carvalho Chehab 
7529a0bf528SMauro Carvalho Chehab 	if (agc == NULL) {
7539a0bf528SMauro Carvalho Chehab 		dprintk("no valid AGC configuration found for band 0x%02x", band);
7549a0bf528SMauro Carvalho Chehab 		return -EINVAL;
7559a0bf528SMauro Carvalho Chehab 	}
7569a0bf528SMauro Carvalho Chehab 
7579a0bf528SMauro Carvalho Chehab 	state->current_agc = agc;
7589a0bf528SMauro Carvalho Chehab 
7599a0bf528SMauro Carvalho Chehab 	/* AGC */
7609a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 75, agc->setup);
7619a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 76, agc->inv_gain);
7629a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 77, agc->time_stabiliz);
7639a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
7649a0bf528SMauro Carvalho Chehab 
7659a0bf528SMauro Carvalho Chehab 	// Demod AGC loop configuration
7669a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
7679a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
7689a0bf528SMauro Carvalho Chehab 
7699a0bf528SMauro Carvalho Chehab 	/* AGC continued */
7709a0bf528SMauro Carvalho Chehab 	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
7719a0bf528SMauro Carvalho Chehab 		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
7729a0bf528SMauro Carvalho Chehab 
7739a0bf528SMauro Carvalho Chehab 	if (state->wbd_ref != 0)
7749a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
7759a0bf528SMauro Carvalho Chehab 	else
7769a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
7779a0bf528SMauro Carvalho Chehab 
7789a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
7799a0bf528SMauro Carvalho Chehab 
7809a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 107, agc->agc1_max);
7819a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 108, agc->agc1_min);
7829a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 109, agc->agc2_max);
7839a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 110, agc->agc2_min);
7849a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
7859a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 112, agc->agc1_pt3);
7869a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
7879a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
7889a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
7899a0bf528SMauro Carvalho Chehab 	return 0;
7909a0bf528SMauro Carvalho Chehab }
7919a0bf528SMauro Carvalho Chehab 
7929a0bf528SMauro Carvalho Chehab static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
7939a0bf528SMauro Carvalho Chehab {
7949a0bf528SMauro Carvalho Chehab 	u32 internal = dib7000p_get_internal_freq(state);
7959a0bf528SMauro Carvalho Chehab 	s32 unit_khz_dds_val = 67108864 / (internal);	/* 2**26 / Fsampling is the unit 1KHz offset */
7969a0bf528SMauro Carvalho Chehab 	u32 abs_offset_khz = ABS(offset_khz);
7979a0bf528SMauro Carvalho Chehab 	u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
7989a0bf528SMauro Carvalho Chehab 	u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
7999a0bf528SMauro Carvalho Chehab 
8009a0bf528SMauro Carvalho Chehab 	dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert);
8019a0bf528SMauro Carvalho Chehab 
8029a0bf528SMauro Carvalho Chehab 	if (offset_khz < 0)
8039a0bf528SMauro Carvalho Chehab 		unit_khz_dds_val *= -1;
8049a0bf528SMauro Carvalho Chehab 
8059a0bf528SMauro Carvalho Chehab 	/* IF tuner */
8069a0bf528SMauro Carvalho Chehab 	if (invert)
8079a0bf528SMauro 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 */
8089a0bf528SMauro Carvalho Chehab 	else
8099a0bf528SMauro Carvalho Chehab 		dds += (abs_offset_khz * unit_khz_dds_val);
8109a0bf528SMauro Carvalho Chehab 
8119a0bf528SMauro Carvalho Chehab 	if (abs_offset_khz <= (internal / 2)) {	/* Max dds offset is the half of the demod freq */
8129a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
8139a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
8149a0bf528SMauro Carvalho Chehab 	}
8159a0bf528SMauro Carvalho Chehab }
8169a0bf528SMauro Carvalho Chehab 
8179a0bf528SMauro Carvalho Chehab static int dib7000p_agc_startup(struct dvb_frontend *demod)
8189a0bf528SMauro Carvalho Chehab {
8199a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
8209a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
8219a0bf528SMauro Carvalho Chehab 	int ret = -1;
8229a0bf528SMauro Carvalho Chehab 	u8 *agc_state = &state->agc_state;
8239a0bf528SMauro Carvalho Chehab 	u8 agc_split;
8249a0bf528SMauro Carvalho Chehab 	u16 reg;
8259a0bf528SMauro Carvalho Chehab 	u32 upd_demod_gain_period = 0x1000;
8266fe1099cSOlivier Grenie 	s32 frequency_offset = 0;
8279a0bf528SMauro Carvalho Chehab 
8289a0bf528SMauro Carvalho Chehab 	switch (state->agc_state) {
8299a0bf528SMauro Carvalho Chehab 	case 0:
8309a0bf528SMauro Carvalho Chehab 		dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
8319a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090) {
8329a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 0x79b) & 0xff00;
8339a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF);	/* lsb */
8349a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
8359a0bf528SMauro Carvalho Chehab 
8369a0bf528SMauro Carvalho Chehab 			/* enable adc i & q */
8379a0bf528SMauro Carvalho Chehab 			reg = dib7000p_read_word(state, 0x780);
8389a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
8399a0bf528SMauro Carvalho Chehab 		} else {
8409a0bf528SMauro Carvalho Chehab 			dib7000p_set_adc_state(state, DIBX000_ADC_ON);
8419a0bf528SMauro Carvalho Chehab 			dib7000p_pll_clk_cfg(state);
8429a0bf528SMauro Carvalho Chehab 		}
8439a0bf528SMauro Carvalho Chehab 
8449a0bf528SMauro Carvalho Chehab 		if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
8459a0bf528SMauro Carvalho Chehab 			return -1;
8469a0bf528SMauro Carvalho Chehab 
8476fe1099cSOlivier Grenie 		if (demod->ops.tuner_ops.get_frequency) {
8486fe1099cSOlivier Grenie 			u32 frequency_tuner;
8496fe1099cSOlivier Grenie 
8506fe1099cSOlivier Grenie 			demod->ops.tuner_ops.get_frequency(demod, &frequency_tuner);
8516fe1099cSOlivier Grenie 			frequency_offset = (s32)frequency_tuner / 1000 - ch->frequency / 1000;
8526fe1099cSOlivier Grenie 		}
8536fe1099cSOlivier Grenie 
8546fe1099cSOlivier Grenie 		dib7000p_set_dds(state, frequency_offset);
8559a0bf528SMauro Carvalho Chehab 		ret = 7;
8569a0bf528SMauro Carvalho Chehab 		(*agc_state)++;
8579a0bf528SMauro Carvalho Chehab 		break;
8589a0bf528SMauro Carvalho Chehab 
8599a0bf528SMauro Carvalho Chehab 	case 1:
8609a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
8619a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(&state->demod, 1);
8629a0bf528SMauro Carvalho Chehab 
8639a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 78, 32768);
8649a0bf528SMauro Carvalho Chehab 		if (!state->current_agc->perform_agc_softsplit) {
8659a0bf528SMauro Carvalho Chehab 			/* we are using the wbd - so slow AGC startup */
8669a0bf528SMauro Carvalho Chehab 			/* force 0 split on WBD and restart AGC */
8679a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
8689a0bf528SMauro Carvalho Chehab 			(*agc_state)++;
8699a0bf528SMauro Carvalho Chehab 			ret = 5;
8709a0bf528SMauro Carvalho Chehab 		} else {
8719a0bf528SMauro Carvalho Chehab 			/* default AGC startup */
8729a0bf528SMauro Carvalho Chehab 			(*agc_state) = 4;
8739a0bf528SMauro Carvalho Chehab 			/* wait AGC rough lock time */
8749a0bf528SMauro Carvalho Chehab 			ret = 7;
8759a0bf528SMauro Carvalho Chehab 		}
8769a0bf528SMauro Carvalho Chehab 
8779a0bf528SMauro Carvalho Chehab 		dib7000p_restart_agc(state);
8789a0bf528SMauro Carvalho Chehab 		break;
8799a0bf528SMauro Carvalho Chehab 
8809a0bf528SMauro Carvalho Chehab 	case 2:		/* fast split search path after 5sec */
8819a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4));	/* freeze AGC loop */
8829a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8));	/* fast split search 0.25kHz */
8839a0bf528SMauro Carvalho Chehab 		(*agc_state)++;
8849a0bf528SMauro Carvalho Chehab 		ret = 14;
8859a0bf528SMauro Carvalho Chehab 		break;
8869a0bf528SMauro Carvalho Chehab 
8879a0bf528SMauro Carvalho Chehab 	case 3:		/* split search ended */
8889a0bf528SMauro Carvalho Chehab 		agc_split = (u8) dib7000p_read_word(state, 396);	/* store the split value for the next time */
8899a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 78, dib7000p_read_word(state, 394));	/* set AGC gain start value */
8909a0bf528SMauro Carvalho Chehab 
8919a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 75, state->current_agc->setup);	/* std AGC loop */
8929a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split);	/* standard split search */
8939a0bf528SMauro Carvalho Chehab 
8949a0bf528SMauro Carvalho Chehab 		dib7000p_restart_agc(state);
8959a0bf528SMauro Carvalho Chehab 
8969a0bf528SMauro Carvalho Chehab 		dprintk("SPLIT %p: %hd", demod, agc_split);
8979a0bf528SMauro Carvalho Chehab 
8989a0bf528SMauro Carvalho Chehab 		(*agc_state)++;
8999a0bf528SMauro Carvalho Chehab 		ret = 5;
9009a0bf528SMauro Carvalho Chehab 		break;
9019a0bf528SMauro Carvalho Chehab 
9029a0bf528SMauro Carvalho Chehab 	case 4:		/* LNA startup */
9039a0bf528SMauro Carvalho Chehab 		ret = 7;
9049a0bf528SMauro Carvalho Chehab 
9059a0bf528SMauro Carvalho Chehab 		if (dib7000p_update_lna(state))
9069a0bf528SMauro Carvalho Chehab 			ret = 5;
9079a0bf528SMauro Carvalho Chehab 		else
9089a0bf528SMauro Carvalho Chehab 			(*agc_state)++;
9099a0bf528SMauro Carvalho Chehab 		break;
9109a0bf528SMauro Carvalho Chehab 
9119a0bf528SMauro Carvalho Chehab 	case 5:
9129a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc_control)
9139a0bf528SMauro Carvalho Chehab 			state->cfg.agc_control(&state->demod, 0);
9149a0bf528SMauro Carvalho Chehab 		(*agc_state)++;
9159a0bf528SMauro Carvalho Chehab 		break;
9169a0bf528SMauro Carvalho Chehab 	default:
9179a0bf528SMauro Carvalho Chehab 		break;
9189a0bf528SMauro Carvalho Chehab 	}
9199a0bf528SMauro Carvalho Chehab 	return ret;
9209a0bf528SMauro Carvalho Chehab }
9219a0bf528SMauro Carvalho Chehab 
9229a0bf528SMauro Carvalho Chehab static void dib7000p_update_timf(struct dib7000p_state *state)
9239a0bf528SMauro Carvalho Chehab {
9249a0bf528SMauro Carvalho Chehab 	u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
9259a0bf528SMauro Carvalho Chehab 	state->timf = timf * 160 / (state->current_bandwidth / 50);
9269a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 23, (u16) (timf >> 16));
9279a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
9289a0bf528SMauro Carvalho Chehab 	dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf);
9299a0bf528SMauro Carvalho Chehab 
9309a0bf528SMauro Carvalho Chehab }
9319a0bf528SMauro Carvalho Chehab 
932*8abe4a0aSMauro Carvalho Chehab static u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
9339a0bf528SMauro Carvalho Chehab {
9349a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
9359a0bf528SMauro Carvalho Chehab 	switch (op) {
9369a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_SET:
9379a0bf528SMauro Carvalho Chehab 		state->timf = timf;
9389a0bf528SMauro Carvalho Chehab 		break;
9399a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_UPDATE:
9409a0bf528SMauro Carvalho Chehab 		dib7000p_update_timf(state);
9419a0bf528SMauro Carvalho Chehab 		break;
9429a0bf528SMauro Carvalho Chehab 	case DEMOD_TIMF_GET:
9439a0bf528SMauro Carvalho Chehab 		break;
9449a0bf528SMauro Carvalho Chehab 	}
9459a0bf528SMauro Carvalho Chehab 	dib7000p_set_bandwidth(state, state->current_bandwidth);
9469a0bf528SMauro Carvalho Chehab 	return state->timf;
9479a0bf528SMauro Carvalho Chehab }
9489a0bf528SMauro Carvalho Chehab 
9499a0bf528SMauro Carvalho Chehab static void dib7000p_set_channel(struct dib7000p_state *state,
9509a0bf528SMauro Carvalho Chehab 				 struct dtv_frontend_properties *ch, u8 seq)
9519a0bf528SMauro Carvalho Chehab {
9529a0bf528SMauro Carvalho Chehab 	u16 value, est[4];
9539a0bf528SMauro Carvalho Chehab 
9549a0bf528SMauro Carvalho Chehab 	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
9559a0bf528SMauro Carvalho Chehab 
9569a0bf528SMauro Carvalho Chehab 	/* nfft, guard, qam, alpha */
9579a0bf528SMauro Carvalho Chehab 	value = 0;
9589a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
9599a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
9609a0bf528SMauro Carvalho Chehab 		value |= (0 << 7);
9619a0bf528SMauro Carvalho Chehab 		break;
9629a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
9639a0bf528SMauro Carvalho Chehab 		value |= (2 << 7);
9649a0bf528SMauro Carvalho Chehab 		break;
9659a0bf528SMauro Carvalho Chehab 	default:
9669a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
9679a0bf528SMauro Carvalho Chehab 		value |= (1 << 7);
9689a0bf528SMauro Carvalho Chehab 		break;
9699a0bf528SMauro Carvalho Chehab 	}
9709a0bf528SMauro Carvalho Chehab 	switch (ch->guard_interval) {
9719a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_32:
9729a0bf528SMauro Carvalho Chehab 		value |= (0 << 5);
9739a0bf528SMauro Carvalho Chehab 		break;
9749a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_16:
9759a0bf528SMauro Carvalho Chehab 		value |= (1 << 5);
9769a0bf528SMauro Carvalho Chehab 		break;
9779a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_4:
9789a0bf528SMauro Carvalho Chehab 		value |= (3 << 5);
9799a0bf528SMauro Carvalho Chehab 		break;
9809a0bf528SMauro Carvalho Chehab 	default:
9819a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_8:
9829a0bf528SMauro Carvalho Chehab 		value |= (2 << 5);
9839a0bf528SMauro Carvalho Chehab 		break;
9849a0bf528SMauro Carvalho Chehab 	}
9859a0bf528SMauro Carvalho Chehab 	switch (ch->modulation) {
9869a0bf528SMauro Carvalho Chehab 	case QPSK:
9879a0bf528SMauro Carvalho Chehab 		value |= (0 << 3);
9889a0bf528SMauro Carvalho Chehab 		break;
9899a0bf528SMauro Carvalho Chehab 	case QAM_16:
9909a0bf528SMauro Carvalho Chehab 		value |= (1 << 3);
9919a0bf528SMauro Carvalho Chehab 		break;
9929a0bf528SMauro Carvalho Chehab 	default:
9939a0bf528SMauro Carvalho Chehab 	case QAM_64:
9949a0bf528SMauro Carvalho Chehab 		value |= (2 << 3);
9959a0bf528SMauro Carvalho Chehab 		break;
9969a0bf528SMauro Carvalho Chehab 	}
9979a0bf528SMauro Carvalho Chehab 	switch (HIERARCHY_1) {
9989a0bf528SMauro Carvalho Chehab 	case HIERARCHY_2:
9999a0bf528SMauro Carvalho Chehab 		value |= 2;
10009a0bf528SMauro Carvalho Chehab 		break;
10019a0bf528SMauro Carvalho Chehab 	case HIERARCHY_4:
10029a0bf528SMauro Carvalho Chehab 		value |= 4;
10039a0bf528SMauro Carvalho Chehab 		break;
10049a0bf528SMauro Carvalho Chehab 	default:
10059a0bf528SMauro Carvalho Chehab 	case HIERARCHY_1:
10069a0bf528SMauro Carvalho Chehab 		value |= 1;
10079a0bf528SMauro Carvalho Chehab 		break;
10089a0bf528SMauro Carvalho Chehab 	}
10099a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 0, value);
10109a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 5, (seq << 4) | 1);	/* do not force tps, search list 0 */
10119a0bf528SMauro Carvalho Chehab 
10129a0bf528SMauro Carvalho Chehab 	/* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
10139a0bf528SMauro Carvalho Chehab 	value = 0;
10149a0bf528SMauro Carvalho Chehab 	if (1 != 0)
10159a0bf528SMauro Carvalho Chehab 		value |= (1 << 6);
10169a0bf528SMauro Carvalho Chehab 	if (ch->hierarchy == 1)
10179a0bf528SMauro Carvalho Chehab 		value |= (1 << 4);
10189a0bf528SMauro Carvalho Chehab 	if (1 == 1)
10199a0bf528SMauro Carvalho Chehab 		value |= 1;
10209a0bf528SMauro Carvalho Chehab 	switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
10219a0bf528SMauro Carvalho Chehab 	case FEC_2_3:
10229a0bf528SMauro Carvalho Chehab 		value |= (2 << 1);
10239a0bf528SMauro Carvalho Chehab 		break;
10249a0bf528SMauro Carvalho Chehab 	case FEC_3_4:
10259a0bf528SMauro Carvalho Chehab 		value |= (3 << 1);
10269a0bf528SMauro Carvalho Chehab 		break;
10279a0bf528SMauro Carvalho Chehab 	case FEC_5_6:
10289a0bf528SMauro Carvalho Chehab 		value |= (5 << 1);
10299a0bf528SMauro Carvalho Chehab 		break;
10309a0bf528SMauro Carvalho Chehab 	case FEC_7_8:
10319a0bf528SMauro Carvalho Chehab 		value |= (7 << 1);
10329a0bf528SMauro Carvalho Chehab 		break;
10339a0bf528SMauro Carvalho Chehab 	default:
10349a0bf528SMauro Carvalho Chehab 	case FEC_1_2:
10359a0bf528SMauro Carvalho Chehab 		value |= (1 << 1);
10369a0bf528SMauro Carvalho Chehab 		break;
10379a0bf528SMauro Carvalho Chehab 	}
10389a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 208, value);
10399a0bf528SMauro Carvalho Chehab 
10409a0bf528SMauro Carvalho Chehab 	/* offset loop parameters */
10419a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 26, 0x6680);
10429a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 32, 0x0003);
10439a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 29, 0x1273);
10449a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 33, 0x0005);
10459a0bf528SMauro Carvalho Chehab 
10469a0bf528SMauro Carvalho Chehab 	/* P_dvsy_sync_wait */
10479a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
10489a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
10499a0bf528SMauro Carvalho Chehab 		value = 256;
10509a0bf528SMauro Carvalho Chehab 		break;
10519a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
10529a0bf528SMauro Carvalho Chehab 		value = 128;
10539a0bf528SMauro Carvalho Chehab 		break;
10549a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
10559a0bf528SMauro Carvalho Chehab 	default:
10569a0bf528SMauro Carvalho Chehab 		value = 64;
10579a0bf528SMauro Carvalho Chehab 		break;
10589a0bf528SMauro Carvalho Chehab 	}
10599a0bf528SMauro Carvalho Chehab 	switch (ch->guard_interval) {
10609a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_16:
10619a0bf528SMauro Carvalho Chehab 		value *= 2;
10629a0bf528SMauro Carvalho Chehab 		break;
10639a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_8:
10649a0bf528SMauro Carvalho Chehab 		value *= 4;
10659a0bf528SMauro Carvalho Chehab 		break;
10669a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_4:
10679a0bf528SMauro Carvalho Chehab 		value *= 8;
10689a0bf528SMauro Carvalho Chehab 		break;
10699a0bf528SMauro Carvalho Chehab 	default:
10709a0bf528SMauro Carvalho Chehab 	case GUARD_INTERVAL_1_32:
10719a0bf528SMauro Carvalho Chehab 		value *= 1;
10729a0bf528SMauro Carvalho Chehab 		break;
10739a0bf528SMauro Carvalho Chehab 	}
10749a0bf528SMauro Carvalho Chehab 	if (state->cfg.diversity_delay == 0)
10759a0bf528SMauro Carvalho Chehab 		state->div_sync_wait = (value * 3) / 2 + 48;
10769a0bf528SMauro Carvalho Chehab 	else
10779a0bf528SMauro Carvalho Chehab 		state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
10789a0bf528SMauro Carvalho Chehab 
10799a0bf528SMauro Carvalho Chehab 	/* deactive the possibility of diversity reception if extended interleaver */
10809a0bf528SMauro Carvalho Chehab 	state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K;
10819a0bf528SMauro Carvalho Chehab 	dib7000p_set_diversity_in(&state->demod, state->div_state);
10829a0bf528SMauro Carvalho Chehab 
10839a0bf528SMauro Carvalho Chehab 	/* channel estimation fine configuration */
10849a0bf528SMauro Carvalho Chehab 	switch (ch->modulation) {
10859a0bf528SMauro Carvalho Chehab 	case QAM_64:
10869a0bf528SMauro Carvalho Chehab 		est[0] = 0x0148;	/* P_adp_regul_cnt 0.04 */
10879a0bf528SMauro Carvalho Chehab 		est[1] = 0xfff0;	/* P_adp_noise_cnt -0.002 */
10889a0bf528SMauro Carvalho Chehab 		est[2] = 0x00a4;	/* P_adp_regul_ext 0.02 */
10899a0bf528SMauro Carvalho Chehab 		est[3] = 0xfff8;	/* P_adp_noise_ext -0.001 */
10909a0bf528SMauro Carvalho Chehab 		break;
10919a0bf528SMauro Carvalho Chehab 	case QAM_16:
10929a0bf528SMauro Carvalho Chehab 		est[0] = 0x023d;	/* P_adp_regul_cnt 0.07 */
10939a0bf528SMauro Carvalho Chehab 		est[1] = 0xffdf;	/* P_adp_noise_cnt -0.004 */
10949a0bf528SMauro Carvalho Chehab 		est[2] = 0x00a4;	/* P_adp_regul_ext 0.02 */
10959a0bf528SMauro Carvalho Chehab 		est[3] = 0xfff0;	/* P_adp_noise_ext -0.002 */
10969a0bf528SMauro Carvalho Chehab 		break;
10979a0bf528SMauro Carvalho Chehab 	default:
10989a0bf528SMauro Carvalho Chehab 		est[0] = 0x099a;	/* P_adp_regul_cnt 0.3 */
10999a0bf528SMauro Carvalho Chehab 		est[1] = 0xffae;	/* P_adp_noise_cnt -0.01 */
11009a0bf528SMauro Carvalho Chehab 		est[2] = 0x0333;	/* P_adp_regul_ext 0.1 */
11019a0bf528SMauro Carvalho Chehab 		est[3] = 0xfff8;	/* P_adp_noise_ext -0.002 */
11029a0bf528SMauro Carvalho Chehab 		break;
11039a0bf528SMauro Carvalho Chehab 	}
11049a0bf528SMauro Carvalho Chehab 	for (value = 0; value < 4; value++)
11059a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 187 + value, est[value]);
11069a0bf528SMauro Carvalho Chehab }
11079a0bf528SMauro Carvalho Chehab 
11089a0bf528SMauro Carvalho Chehab static int dib7000p_autosearch_start(struct dvb_frontend *demod)
11099a0bf528SMauro Carvalho Chehab {
11109a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
11119a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
11129a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties schan;
11139a0bf528SMauro Carvalho Chehab 	u32 value, factor;
11149a0bf528SMauro Carvalho Chehab 	u32 internal = dib7000p_get_internal_freq(state);
11159a0bf528SMauro Carvalho Chehab 
11169a0bf528SMauro Carvalho Chehab 	schan = *ch;
11179a0bf528SMauro Carvalho Chehab 	schan.modulation = QAM_64;
11189a0bf528SMauro Carvalho Chehab 	schan.guard_interval = GUARD_INTERVAL_1_32;
11199a0bf528SMauro Carvalho Chehab 	schan.transmission_mode = TRANSMISSION_MODE_8K;
11209a0bf528SMauro Carvalho Chehab 	schan.code_rate_HP = FEC_2_3;
11219a0bf528SMauro Carvalho Chehab 	schan.code_rate_LP = FEC_3_4;
11229a0bf528SMauro Carvalho Chehab 	schan.hierarchy = 0;
11239a0bf528SMauro Carvalho Chehab 
11249a0bf528SMauro Carvalho Chehab 	dib7000p_set_channel(state, &schan, 7);
11259a0bf528SMauro Carvalho Chehab 
11269a0bf528SMauro Carvalho Chehab 	factor = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
11279a0bf528SMauro Carvalho Chehab 	if (factor >= 5000) {
11289a0bf528SMauro Carvalho Chehab 		if (state->version == SOC7090)
11299a0bf528SMauro Carvalho Chehab 			factor = 2;
11309a0bf528SMauro Carvalho Chehab 		else
11319a0bf528SMauro Carvalho Chehab 			factor = 1;
11329a0bf528SMauro Carvalho Chehab 	} else
11339a0bf528SMauro Carvalho Chehab 		factor = 6;
11349a0bf528SMauro Carvalho Chehab 
11359a0bf528SMauro Carvalho Chehab 	value = 30 * internal * factor;
11369a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
11379a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 7, (u16) (value & 0xffff));
11389a0bf528SMauro Carvalho Chehab 	value = 100 * internal * factor;
11399a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
11409a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 9, (u16) (value & 0xffff));
11419a0bf528SMauro Carvalho Chehab 	value = 500 * internal * factor;
11429a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
11439a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 11, (u16) (value & 0xffff));
11449a0bf528SMauro Carvalho Chehab 
11459a0bf528SMauro Carvalho Chehab 	value = dib7000p_read_word(state, 0);
11469a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
11479a0bf528SMauro Carvalho Chehab 	dib7000p_read_word(state, 1284);
11489a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 0, (u16) value);
11499a0bf528SMauro Carvalho Chehab 
11509a0bf528SMauro Carvalho Chehab 	return 0;
11519a0bf528SMauro Carvalho Chehab }
11529a0bf528SMauro Carvalho Chehab 
11539a0bf528SMauro Carvalho Chehab static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
11549a0bf528SMauro Carvalho Chehab {
11559a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
11569a0bf528SMauro Carvalho Chehab 	u16 irq_pending = dib7000p_read_word(state, 1284);
11579a0bf528SMauro Carvalho Chehab 
11589a0bf528SMauro Carvalho Chehab 	if (irq_pending & 0x1)
11599a0bf528SMauro Carvalho Chehab 		return 1;
11609a0bf528SMauro Carvalho Chehab 
11619a0bf528SMauro Carvalho Chehab 	if (irq_pending & 0x2)
11629a0bf528SMauro Carvalho Chehab 		return 2;
11639a0bf528SMauro Carvalho Chehab 
11649a0bf528SMauro Carvalho Chehab 	return 0;
11659a0bf528SMauro Carvalho Chehab }
11669a0bf528SMauro Carvalho Chehab 
11679a0bf528SMauro Carvalho Chehab static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
11689a0bf528SMauro Carvalho Chehab {
11699a0bf528SMauro Carvalho Chehab 	static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
11709a0bf528SMauro Carvalho Chehab 	static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
11719a0bf528SMauro Carvalho Chehab 		24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
11729a0bf528SMauro Carvalho Chehab 		53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
11739a0bf528SMauro Carvalho Chehab 		82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
11749a0bf528SMauro Carvalho Chehab 		107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
11759a0bf528SMauro Carvalho Chehab 		128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
11769a0bf528SMauro Carvalho Chehab 		147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
11779a0bf528SMauro Carvalho Chehab 		166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
11789a0bf528SMauro Carvalho Chehab 		183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
11799a0bf528SMauro Carvalho Chehab 		199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
11809a0bf528SMauro Carvalho Chehab 		213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
11819a0bf528SMauro Carvalho Chehab 		225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
11829a0bf528SMauro Carvalho Chehab 		235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
11839a0bf528SMauro Carvalho Chehab 		244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
11849a0bf528SMauro Carvalho Chehab 		250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
11859a0bf528SMauro Carvalho Chehab 		254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
11869a0bf528SMauro Carvalho Chehab 		255, 255, 255, 255, 255, 255
11879a0bf528SMauro Carvalho Chehab 	};
11889a0bf528SMauro Carvalho Chehab 
11899a0bf528SMauro Carvalho Chehab 	u32 xtal = state->cfg.bw->xtal_hz / 1000;
11909a0bf528SMauro Carvalho Chehab 	int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
11919a0bf528SMauro Carvalho Chehab 	int k;
11929a0bf528SMauro Carvalho Chehab 	int coef_re[8], coef_im[8];
11939a0bf528SMauro Carvalho Chehab 	int bw_khz = bw;
11949a0bf528SMauro Carvalho Chehab 	u32 pha;
11959a0bf528SMauro Carvalho Chehab 
11969a0bf528SMauro Carvalho Chehab 	dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
11979a0bf528SMauro Carvalho Chehab 
11989a0bf528SMauro Carvalho Chehab 	if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
11999a0bf528SMauro Carvalho Chehab 		return;
12009a0bf528SMauro Carvalho Chehab 
12019a0bf528SMauro Carvalho Chehab 	bw_khz /= 100;
12029a0bf528SMauro Carvalho Chehab 
12039a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 142, 0x0610);
12049a0bf528SMauro Carvalho Chehab 
12059a0bf528SMauro Carvalho Chehab 	for (k = 0; k < 8; k++) {
12069a0bf528SMauro Carvalho Chehab 		pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
12079a0bf528SMauro Carvalho Chehab 
12089a0bf528SMauro Carvalho Chehab 		if (pha == 0) {
12099a0bf528SMauro Carvalho Chehab 			coef_re[k] = 256;
12109a0bf528SMauro Carvalho Chehab 			coef_im[k] = 0;
12119a0bf528SMauro Carvalho Chehab 		} else if (pha < 256) {
12129a0bf528SMauro Carvalho Chehab 			coef_re[k] = sine[256 - (pha & 0xff)];
12139a0bf528SMauro Carvalho Chehab 			coef_im[k] = sine[pha & 0xff];
12149a0bf528SMauro Carvalho Chehab 		} else if (pha == 256) {
12159a0bf528SMauro Carvalho Chehab 			coef_re[k] = 0;
12169a0bf528SMauro Carvalho Chehab 			coef_im[k] = 256;
12179a0bf528SMauro Carvalho Chehab 		} else if (pha < 512) {
12189a0bf528SMauro Carvalho Chehab 			coef_re[k] = -sine[pha & 0xff];
12199a0bf528SMauro Carvalho Chehab 			coef_im[k] = sine[256 - (pha & 0xff)];
12209a0bf528SMauro Carvalho Chehab 		} else if (pha == 512) {
12219a0bf528SMauro Carvalho Chehab 			coef_re[k] = -256;
12229a0bf528SMauro Carvalho Chehab 			coef_im[k] = 0;
12239a0bf528SMauro Carvalho Chehab 		} else if (pha < 768) {
12249a0bf528SMauro Carvalho Chehab 			coef_re[k] = -sine[256 - (pha & 0xff)];
12259a0bf528SMauro Carvalho Chehab 			coef_im[k] = -sine[pha & 0xff];
12269a0bf528SMauro Carvalho Chehab 		} else if (pha == 768) {
12279a0bf528SMauro Carvalho Chehab 			coef_re[k] = 0;
12289a0bf528SMauro Carvalho Chehab 			coef_im[k] = -256;
12299a0bf528SMauro Carvalho Chehab 		} else {
12309a0bf528SMauro Carvalho Chehab 			coef_re[k] = sine[pha & 0xff];
12319a0bf528SMauro Carvalho Chehab 			coef_im[k] = -sine[256 - (pha & 0xff)];
12329a0bf528SMauro Carvalho Chehab 		}
12339a0bf528SMauro Carvalho Chehab 
12349a0bf528SMauro Carvalho Chehab 		coef_re[k] *= notch[k];
12359a0bf528SMauro Carvalho Chehab 		coef_re[k] += (1 << 14);
12369a0bf528SMauro Carvalho Chehab 		if (coef_re[k] >= (1 << 24))
12379a0bf528SMauro Carvalho Chehab 			coef_re[k] = (1 << 24) - 1;
12389a0bf528SMauro Carvalho Chehab 		coef_re[k] /= (1 << 15);
12399a0bf528SMauro Carvalho Chehab 
12409a0bf528SMauro Carvalho Chehab 		coef_im[k] *= notch[k];
12419a0bf528SMauro Carvalho Chehab 		coef_im[k] += (1 << 14);
12429a0bf528SMauro Carvalho Chehab 		if (coef_im[k] >= (1 << 24))
12439a0bf528SMauro Carvalho Chehab 			coef_im[k] = (1 << 24) - 1;
12449a0bf528SMauro Carvalho Chehab 		coef_im[k] /= (1 << 15);
12459a0bf528SMauro Carvalho Chehab 
12469a0bf528SMauro Carvalho Chehab 		dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
12479a0bf528SMauro Carvalho Chehab 
12489a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
12499a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
12509a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
12519a0bf528SMauro Carvalho Chehab 	}
12529a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 143, 0);
12539a0bf528SMauro Carvalho Chehab }
12549a0bf528SMauro Carvalho Chehab 
12559a0bf528SMauro Carvalho Chehab static int dib7000p_tune(struct dvb_frontend *demod)
12569a0bf528SMauro Carvalho Chehab {
12579a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
12589a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
12599a0bf528SMauro Carvalho Chehab 	u16 tmp = 0;
12609a0bf528SMauro Carvalho Chehab 
12619a0bf528SMauro Carvalho Chehab 	if (ch != NULL)
12629a0bf528SMauro Carvalho Chehab 		dib7000p_set_channel(state, ch, 0);
12639a0bf528SMauro Carvalho Chehab 	else
12649a0bf528SMauro Carvalho Chehab 		return -EINVAL;
12659a0bf528SMauro Carvalho Chehab 
12669a0bf528SMauro Carvalho Chehab 	// restart demod
12679a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, 0x4000);
12689a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 770, 0x0000);
12699a0bf528SMauro Carvalho Chehab 	msleep(45);
12709a0bf528SMauro Carvalho Chehab 
12719a0bf528SMauro 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 */
12729a0bf528SMauro Carvalho Chehab 	tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
12739a0bf528SMauro Carvalho Chehab 	if (state->sfn_workaround_active) {
12749a0bf528SMauro Carvalho Chehab 		dprintk("SFN workaround is active");
12759a0bf528SMauro Carvalho Chehab 		tmp |= (1 << 9);
12769a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 166, 0x4000);
12779a0bf528SMauro Carvalho Chehab 	} else {
12789a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 166, 0x0000);
12799a0bf528SMauro Carvalho Chehab 	}
12809a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 29, tmp);
12819a0bf528SMauro Carvalho Chehab 
12829a0bf528SMauro Carvalho Chehab 	// never achieved a lock with that bandwidth so far - wait for osc-freq to update
12839a0bf528SMauro Carvalho Chehab 	if (state->timf == 0)
12849a0bf528SMauro Carvalho Chehab 		msleep(200);
12859a0bf528SMauro Carvalho Chehab 
12869a0bf528SMauro Carvalho Chehab 	/* offset loop parameters */
12879a0bf528SMauro Carvalho Chehab 
12889a0bf528SMauro Carvalho Chehab 	/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
12899a0bf528SMauro Carvalho Chehab 	tmp = (6 << 8) | 0x80;
12909a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
12919a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
12929a0bf528SMauro Carvalho Chehab 		tmp |= (2 << 12);
12939a0bf528SMauro Carvalho Chehab 		break;
12949a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
12959a0bf528SMauro Carvalho Chehab 		tmp |= (3 << 12);
12969a0bf528SMauro Carvalho Chehab 		break;
12979a0bf528SMauro Carvalho Chehab 	default:
12989a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
12999a0bf528SMauro Carvalho Chehab 		tmp |= (4 << 12);
13009a0bf528SMauro Carvalho Chehab 		break;
13019a0bf528SMauro Carvalho Chehab 	}
13029a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 26, tmp);	/* timf_a(6xxx) */
13039a0bf528SMauro Carvalho Chehab 
13049a0bf528SMauro Carvalho Chehab 	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
13059a0bf528SMauro Carvalho Chehab 	tmp = (0 << 4);
13069a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
13079a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
13089a0bf528SMauro Carvalho Chehab 		tmp |= 0x6;
13099a0bf528SMauro Carvalho Chehab 		break;
13109a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
13119a0bf528SMauro Carvalho Chehab 		tmp |= 0x7;
13129a0bf528SMauro Carvalho Chehab 		break;
13139a0bf528SMauro Carvalho Chehab 	default:
13149a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
13159a0bf528SMauro Carvalho Chehab 		tmp |= 0x8;
13169a0bf528SMauro Carvalho Chehab 		break;
13179a0bf528SMauro Carvalho Chehab 	}
13189a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 32, tmp);
13199a0bf528SMauro Carvalho Chehab 
13209a0bf528SMauro Carvalho Chehab 	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
13219a0bf528SMauro Carvalho Chehab 	tmp = (0 << 4);
13229a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
13239a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_2K:
13249a0bf528SMauro Carvalho Chehab 		tmp |= 0x6;
13259a0bf528SMauro Carvalho Chehab 		break;
13269a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_4K:
13279a0bf528SMauro Carvalho Chehab 		tmp |= 0x7;
13289a0bf528SMauro Carvalho Chehab 		break;
13299a0bf528SMauro Carvalho Chehab 	default:
13309a0bf528SMauro Carvalho Chehab 	case TRANSMISSION_MODE_8K:
13319a0bf528SMauro Carvalho Chehab 		tmp |= 0x8;
13329a0bf528SMauro Carvalho Chehab 		break;
13339a0bf528SMauro Carvalho Chehab 	}
13349a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 33, tmp);
13359a0bf528SMauro Carvalho Chehab 
13369a0bf528SMauro Carvalho Chehab 	tmp = dib7000p_read_word(state, 509);
13379a0bf528SMauro Carvalho Chehab 	if (!((tmp >> 6) & 0x1)) {
13389a0bf528SMauro Carvalho Chehab 		/* restart the fec */
13399a0bf528SMauro Carvalho Chehab 		tmp = dib7000p_read_word(state, 771);
13409a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 771, tmp | (1 << 1));
13419a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 771, tmp);
13429a0bf528SMauro Carvalho Chehab 		msleep(40);
13439a0bf528SMauro Carvalho Chehab 		tmp = dib7000p_read_word(state, 509);
13449a0bf528SMauro Carvalho Chehab 	}
13459a0bf528SMauro Carvalho Chehab 	// we achieved a lock - it's time to update the osc freq
13469a0bf528SMauro Carvalho Chehab 	if ((tmp >> 6) & 0x1) {
13479a0bf528SMauro Carvalho Chehab 		dib7000p_update_timf(state);
13489a0bf528SMauro Carvalho Chehab 		/* P_timf_alpha += 2 */
13499a0bf528SMauro Carvalho Chehab 		tmp = dib7000p_read_word(state, 26);
13509a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
13519a0bf528SMauro Carvalho Chehab 	}
13529a0bf528SMauro Carvalho Chehab 
13539a0bf528SMauro Carvalho Chehab 	if (state->cfg.spur_protect)
13549a0bf528SMauro Carvalho Chehab 		dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
13559a0bf528SMauro Carvalho Chehab 
13569a0bf528SMauro Carvalho Chehab 	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
13579a0bf528SMauro Carvalho Chehab 	return 0;
13589a0bf528SMauro Carvalho Chehab }
13599a0bf528SMauro Carvalho Chehab 
13609a0bf528SMauro Carvalho Chehab static int dib7000p_wakeup(struct dvb_frontend *demod)
13619a0bf528SMauro Carvalho Chehab {
13629a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
13639a0bf528SMauro Carvalho Chehab 	dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
13649a0bf528SMauro Carvalho Chehab 	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
13659a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090)
13669a0bf528SMauro Carvalho Chehab 		dib7000p_sad_calib(state);
13679a0bf528SMauro Carvalho Chehab 	return 0;
13689a0bf528SMauro Carvalho Chehab }
13699a0bf528SMauro Carvalho Chehab 
13709a0bf528SMauro Carvalho Chehab static int dib7000p_sleep(struct dvb_frontend *demod)
13719a0bf528SMauro Carvalho Chehab {
13729a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = demod->demodulator_priv;
13739a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090)
13749a0bf528SMauro Carvalho Chehab 		return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
13759a0bf528SMauro Carvalho Chehab 	return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
13769a0bf528SMauro Carvalho Chehab }
13779a0bf528SMauro Carvalho Chehab 
13789a0bf528SMauro Carvalho Chehab static int dib7000p_identify(struct dib7000p_state *st)
13799a0bf528SMauro Carvalho Chehab {
13809a0bf528SMauro Carvalho Chehab 	u16 value;
13819a0bf528SMauro Carvalho Chehab 	dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr);
13829a0bf528SMauro Carvalho Chehab 
13839a0bf528SMauro Carvalho Chehab 	if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
13849a0bf528SMauro Carvalho Chehab 		dprintk("wrong Vendor ID (read=0x%x)", value);
13859a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO;
13869a0bf528SMauro Carvalho Chehab 	}
13879a0bf528SMauro Carvalho Chehab 
13889a0bf528SMauro Carvalho Chehab 	if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
13899a0bf528SMauro Carvalho Chehab 		dprintk("wrong Device ID (%x)", value);
13909a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO;
13919a0bf528SMauro Carvalho Chehab 	}
13929a0bf528SMauro Carvalho Chehab 
13939a0bf528SMauro Carvalho Chehab 	return 0;
13949a0bf528SMauro Carvalho Chehab }
13959a0bf528SMauro Carvalho Chehab 
13969a0bf528SMauro Carvalho Chehab static int dib7000p_get_frontend(struct dvb_frontend *fe)
13979a0bf528SMauro Carvalho Chehab {
13989a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
13999a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
14009a0bf528SMauro Carvalho Chehab 	u16 tps = dib7000p_read_word(state, 463);
14019a0bf528SMauro Carvalho Chehab 
14029a0bf528SMauro Carvalho Chehab 	fep->inversion = INVERSION_AUTO;
14039a0bf528SMauro Carvalho Chehab 
14049a0bf528SMauro Carvalho Chehab 	fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
14059a0bf528SMauro Carvalho Chehab 
14069a0bf528SMauro Carvalho Chehab 	switch ((tps >> 8) & 0x3) {
14079a0bf528SMauro Carvalho Chehab 	case 0:
14089a0bf528SMauro Carvalho Chehab 		fep->transmission_mode = TRANSMISSION_MODE_2K;
14099a0bf528SMauro Carvalho Chehab 		break;
14109a0bf528SMauro Carvalho Chehab 	case 1:
14119a0bf528SMauro Carvalho Chehab 		fep->transmission_mode = TRANSMISSION_MODE_8K;
14129a0bf528SMauro Carvalho Chehab 		break;
14139a0bf528SMauro Carvalho Chehab 	/* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
14149a0bf528SMauro Carvalho Chehab 	}
14159a0bf528SMauro Carvalho Chehab 
14169a0bf528SMauro Carvalho Chehab 	switch (tps & 0x3) {
14179a0bf528SMauro Carvalho Chehab 	case 0:
14189a0bf528SMauro Carvalho Chehab 		fep->guard_interval = GUARD_INTERVAL_1_32;
14199a0bf528SMauro Carvalho Chehab 		break;
14209a0bf528SMauro Carvalho Chehab 	case 1:
14219a0bf528SMauro Carvalho Chehab 		fep->guard_interval = GUARD_INTERVAL_1_16;
14229a0bf528SMauro Carvalho Chehab 		break;
14239a0bf528SMauro Carvalho Chehab 	case 2:
14249a0bf528SMauro Carvalho Chehab 		fep->guard_interval = GUARD_INTERVAL_1_8;
14259a0bf528SMauro Carvalho Chehab 		break;
14269a0bf528SMauro Carvalho Chehab 	case 3:
14279a0bf528SMauro Carvalho Chehab 		fep->guard_interval = GUARD_INTERVAL_1_4;
14289a0bf528SMauro Carvalho Chehab 		break;
14299a0bf528SMauro Carvalho Chehab 	}
14309a0bf528SMauro Carvalho Chehab 
14319a0bf528SMauro Carvalho Chehab 	switch ((tps >> 14) & 0x3) {
14329a0bf528SMauro Carvalho Chehab 	case 0:
14339a0bf528SMauro Carvalho Chehab 		fep->modulation = QPSK;
14349a0bf528SMauro Carvalho Chehab 		break;
14359a0bf528SMauro Carvalho Chehab 	case 1:
14369a0bf528SMauro Carvalho Chehab 		fep->modulation = QAM_16;
14379a0bf528SMauro Carvalho Chehab 		break;
14389a0bf528SMauro Carvalho Chehab 	case 2:
14399a0bf528SMauro Carvalho Chehab 	default:
14409a0bf528SMauro Carvalho Chehab 		fep->modulation = QAM_64;
14419a0bf528SMauro Carvalho Chehab 		break;
14429a0bf528SMauro Carvalho Chehab 	}
14439a0bf528SMauro Carvalho Chehab 
14449a0bf528SMauro Carvalho Chehab 	/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
14459a0bf528SMauro Carvalho Chehab 	/* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
14469a0bf528SMauro Carvalho Chehab 
14479a0bf528SMauro Carvalho Chehab 	fep->hierarchy = HIERARCHY_NONE;
14489a0bf528SMauro Carvalho Chehab 	switch ((tps >> 5) & 0x7) {
14499a0bf528SMauro Carvalho Chehab 	case 1:
14509a0bf528SMauro Carvalho Chehab 		fep->code_rate_HP = FEC_1_2;
14519a0bf528SMauro Carvalho Chehab 		break;
14529a0bf528SMauro Carvalho Chehab 	case 2:
14539a0bf528SMauro Carvalho Chehab 		fep->code_rate_HP = FEC_2_3;
14549a0bf528SMauro Carvalho Chehab 		break;
14559a0bf528SMauro Carvalho Chehab 	case 3:
14569a0bf528SMauro Carvalho Chehab 		fep->code_rate_HP = FEC_3_4;
14579a0bf528SMauro Carvalho Chehab 		break;
14589a0bf528SMauro Carvalho Chehab 	case 5:
14599a0bf528SMauro Carvalho Chehab 		fep->code_rate_HP = FEC_5_6;
14609a0bf528SMauro Carvalho Chehab 		break;
14619a0bf528SMauro Carvalho Chehab 	case 7:
14629a0bf528SMauro Carvalho Chehab 	default:
14639a0bf528SMauro Carvalho Chehab 		fep->code_rate_HP = FEC_7_8;
14649a0bf528SMauro Carvalho Chehab 		break;
14659a0bf528SMauro Carvalho Chehab 
14669a0bf528SMauro Carvalho Chehab 	}
14679a0bf528SMauro Carvalho Chehab 
14689a0bf528SMauro Carvalho Chehab 	switch ((tps >> 2) & 0x7) {
14699a0bf528SMauro Carvalho Chehab 	case 1:
14709a0bf528SMauro Carvalho Chehab 		fep->code_rate_LP = FEC_1_2;
14719a0bf528SMauro Carvalho Chehab 		break;
14729a0bf528SMauro Carvalho Chehab 	case 2:
14739a0bf528SMauro Carvalho Chehab 		fep->code_rate_LP = FEC_2_3;
14749a0bf528SMauro Carvalho Chehab 		break;
14759a0bf528SMauro Carvalho Chehab 	case 3:
14769a0bf528SMauro Carvalho Chehab 		fep->code_rate_LP = FEC_3_4;
14779a0bf528SMauro Carvalho Chehab 		break;
14789a0bf528SMauro Carvalho Chehab 	case 5:
14799a0bf528SMauro Carvalho Chehab 		fep->code_rate_LP = FEC_5_6;
14809a0bf528SMauro Carvalho Chehab 		break;
14819a0bf528SMauro Carvalho Chehab 	case 7:
14829a0bf528SMauro Carvalho Chehab 	default:
14839a0bf528SMauro Carvalho Chehab 		fep->code_rate_LP = FEC_7_8;
14849a0bf528SMauro Carvalho Chehab 		break;
14859a0bf528SMauro Carvalho Chehab 	}
14869a0bf528SMauro Carvalho Chehab 
14879a0bf528SMauro Carvalho Chehab 	/* native interleaver: (dib7000p_read_word(state, 464) >>  5) & 0x1 */
14889a0bf528SMauro Carvalho Chehab 
14899a0bf528SMauro Carvalho Chehab 	return 0;
14909a0bf528SMauro Carvalho Chehab }
14919a0bf528SMauro Carvalho Chehab 
14929a0bf528SMauro Carvalho Chehab static int dib7000p_set_frontend(struct dvb_frontend *fe)
14939a0bf528SMauro Carvalho Chehab {
14949a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
14959a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
14969a0bf528SMauro Carvalho Chehab 	int time, ret;
14979a0bf528SMauro Carvalho Chehab 
14989a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090)
14999a0bf528SMauro Carvalho Chehab 		dib7090_set_diversity_in(fe, 0);
15009a0bf528SMauro Carvalho Chehab 	else
15019a0bf528SMauro Carvalho Chehab 		dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
15029a0bf528SMauro Carvalho Chehab 
15039a0bf528SMauro Carvalho Chehab 	/* maybe the parameter has been changed */
15049a0bf528SMauro Carvalho Chehab 	state->sfn_workaround_active = buggy_sfn_workaround;
15059a0bf528SMauro Carvalho Chehab 
15069a0bf528SMauro Carvalho Chehab 	if (fe->ops.tuner_ops.set_params)
15079a0bf528SMauro Carvalho Chehab 		fe->ops.tuner_ops.set_params(fe);
15089a0bf528SMauro Carvalho Chehab 
15099a0bf528SMauro Carvalho Chehab 	/* start up the AGC */
15109a0bf528SMauro Carvalho Chehab 	state->agc_state = 0;
15119a0bf528SMauro Carvalho Chehab 	do {
15129a0bf528SMauro Carvalho Chehab 		time = dib7000p_agc_startup(fe);
15139a0bf528SMauro Carvalho Chehab 		if (time != -1)
15149a0bf528SMauro Carvalho Chehab 			msleep(time);
15159a0bf528SMauro Carvalho Chehab 	} while (time != -1);
15169a0bf528SMauro Carvalho Chehab 
15179a0bf528SMauro Carvalho Chehab 	if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
15189a0bf528SMauro Carvalho Chehab 		fep->guard_interval == GUARD_INTERVAL_AUTO || fep->modulation == QAM_AUTO || fep->code_rate_HP == FEC_AUTO) {
15199a0bf528SMauro Carvalho Chehab 		int i = 800, found;
15209a0bf528SMauro Carvalho Chehab 
15219a0bf528SMauro Carvalho Chehab 		dib7000p_autosearch_start(fe);
15229a0bf528SMauro Carvalho Chehab 		do {
15239a0bf528SMauro Carvalho Chehab 			msleep(1);
15249a0bf528SMauro Carvalho Chehab 			found = dib7000p_autosearch_is_irq(fe);
15259a0bf528SMauro Carvalho Chehab 		} while (found == 0 && i--);
15269a0bf528SMauro Carvalho Chehab 
15279a0bf528SMauro Carvalho Chehab 		dprintk("autosearch returns: %d", found);
15289a0bf528SMauro Carvalho Chehab 		if (found == 0 || found == 1)
15299a0bf528SMauro Carvalho Chehab 			return 0;
15309a0bf528SMauro Carvalho Chehab 
15319a0bf528SMauro Carvalho Chehab 		dib7000p_get_frontend(fe);
15329a0bf528SMauro Carvalho Chehab 	}
15339a0bf528SMauro Carvalho Chehab 
15349a0bf528SMauro Carvalho Chehab 	ret = dib7000p_tune(fe);
15359a0bf528SMauro Carvalho Chehab 
15369a0bf528SMauro Carvalho Chehab 	/* make this a config parameter */
15379a0bf528SMauro Carvalho Chehab 	if (state->version == SOC7090) {
15389a0bf528SMauro Carvalho Chehab 		dib7090_set_output_mode(fe, state->cfg.output_mode);
15399a0bf528SMauro Carvalho Chehab 		if (state->cfg.enMpegOutput == 0) {
15409a0bf528SMauro Carvalho Chehab 			dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
15419a0bf528SMauro Carvalho Chehab 			dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
15429a0bf528SMauro Carvalho Chehab 		}
15439a0bf528SMauro Carvalho Chehab 	} else
15449a0bf528SMauro Carvalho Chehab 		dib7000p_set_output_mode(state, state->cfg.output_mode);
15459a0bf528SMauro Carvalho Chehab 
15469a0bf528SMauro Carvalho Chehab 	return ret;
15479a0bf528SMauro Carvalho Chehab }
15489a0bf528SMauro Carvalho Chehab 
15499a0bf528SMauro Carvalho Chehab static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
15509a0bf528SMauro Carvalho Chehab {
15519a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
15529a0bf528SMauro Carvalho Chehab 	u16 lock = dib7000p_read_word(state, 509);
15539a0bf528SMauro Carvalho Chehab 
15549a0bf528SMauro Carvalho Chehab 	*stat = 0;
15559a0bf528SMauro Carvalho Chehab 
15569a0bf528SMauro Carvalho Chehab 	if (lock & 0x8000)
15579a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SIGNAL;
15589a0bf528SMauro Carvalho Chehab 	if (lock & 0x3000)
15599a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_CARRIER;
15609a0bf528SMauro Carvalho Chehab 	if (lock & 0x0100)
15619a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_VITERBI;
15629a0bf528SMauro Carvalho Chehab 	if (lock & 0x0010)
15639a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SYNC;
15649a0bf528SMauro Carvalho Chehab 	if ((lock & 0x0038) == 0x38)
15659a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_LOCK;
15669a0bf528SMauro Carvalho Chehab 
15679a0bf528SMauro Carvalho Chehab 	return 0;
15689a0bf528SMauro Carvalho Chehab }
15699a0bf528SMauro Carvalho Chehab 
15709a0bf528SMauro Carvalho Chehab static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
15719a0bf528SMauro Carvalho Chehab {
15729a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
15739a0bf528SMauro Carvalho Chehab 	*ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
15749a0bf528SMauro Carvalho Chehab 	return 0;
15759a0bf528SMauro Carvalho Chehab }
15769a0bf528SMauro Carvalho Chehab 
15779a0bf528SMauro Carvalho Chehab static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
15789a0bf528SMauro Carvalho Chehab {
15799a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
15809a0bf528SMauro Carvalho Chehab 	*unc = dib7000p_read_word(state, 506);
15819a0bf528SMauro Carvalho Chehab 	return 0;
15829a0bf528SMauro Carvalho Chehab }
15839a0bf528SMauro Carvalho Chehab 
15849a0bf528SMauro Carvalho Chehab static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
15859a0bf528SMauro Carvalho Chehab {
15869a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
15879a0bf528SMauro Carvalho Chehab 	u16 val = dib7000p_read_word(state, 394);
15889a0bf528SMauro Carvalho Chehab 	*strength = 65535 - val;
15899a0bf528SMauro Carvalho Chehab 	return 0;
15909a0bf528SMauro Carvalho Chehab }
15919a0bf528SMauro Carvalho Chehab 
15929a0bf528SMauro Carvalho Chehab static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
15939a0bf528SMauro Carvalho Chehab {
15949a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
15959a0bf528SMauro Carvalho Chehab 	u16 val;
15969a0bf528SMauro Carvalho Chehab 	s32 signal_mant, signal_exp, noise_mant, noise_exp;
15979a0bf528SMauro Carvalho Chehab 	u32 result = 0;
15989a0bf528SMauro Carvalho Chehab 
15999a0bf528SMauro Carvalho Chehab 	val = dib7000p_read_word(state, 479);
16009a0bf528SMauro Carvalho Chehab 	noise_mant = (val >> 4) & 0xff;
16019a0bf528SMauro Carvalho Chehab 	noise_exp = ((val & 0xf) << 2);
16029a0bf528SMauro Carvalho Chehab 	val = dib7000p_read_word(state, 480);
16039a0bf528SMauro Carvalho Chehab 	noise_exp += ((val >> 14) & 0x3);
16049a0bf528SMauro Carvalho Chehab 	if ((noise_exp & 0x20) != 0)
16059a0bf528SMauro Carvalho Chehab 		noise_exp -= 0x40;
16069a0bf528SMauro Carvalho Chehab 
16079a0bf528SMauro Carvalho Chehab 	signal_mant = (val >> 6) & 0xFF;
16089a0bf528SMauro Carvalho Chehab 	signal_exp = (val & 0x3F);
16099a0bf528SMauro Carvalho Chehab 	if ((signal_exp & 0x20) != 0)
16109a0bf528SMauro Carvalho Chehab 		signal_exp -= 0x40;
16119a0bf528SMauro Carvalho Chehab 
16129a0bf528SMauro Carvalho Chehab 	if (signal_mant != 0)
16139a0bf528SMauro Carvalho Chehab 		result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
16149a0bf528SMauro Carvalho Chehab 	else
16159a0bf528SMauro Carvalho Chehab 		result = intlog10(2) * 10 * signal_exp - 100;
16169a0bf528SMauro Carvalho Chehab 
16179a0bf528SMauro Carvalho Chehab 	if (noise_mant != 0)
16189a0bf528SMauro Carvalho Chehab 		result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
16199a0bf528SMauro Carvalho Chehab 	else
16209a0bf528SMauro Carvalho Chehab 		result -= intlog10(2) * 10 * noise_exp - 100;
16219a0bf528SMauro Carvalho Chehab 
16229a0bf528SMauro Carvalho Chehab 	*snr = result / ((1 << 24) / 10);
16239a0bf528SMauro Carvalho Chehab 	return 0;
16249a0bf528SMauro Carvalho Chehab }
16259a0bf528SMauro Carvalho Chehab 
16269a0bf528SMauro Carvalho Chehab static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
16279a0bf528SMauro Carvalho Chehab {
16289a0bf528SMauro Carvalho Chehab 	tune->min_delay_ms = 1000;
16299a0bf528SMauro Carvalho Chehab 	return 0;
16309a0bf528SMauro Carvalho Chehab }
16319a0bf528SMauro Carvalho Chehab 
16329a0bf528SMauro Carvalho Chehab static void dib7000p_release(struct dvb_frontend *demod)
16339a0bf528SMauro Carvalho Chehab {
16349a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *st = demod->demodulator_priv;
16359a0bf528SMauro Carvalho Chehab 	dibx000_exit_i2c_master(&st->i2c_master);
16369a0bf528SMauro Carvalho Chehab 	i2c_del_adapter(&st->dib7090_tuner_adap);
16379a0bf528SMauro Carvalho Chehab 	kfree(st);
16389a0bf528SMauro Carvalho Chehab }
16399a0bf528SMauro Carvalho Chehab 
1640*8abe4a0aSMauro Carvalho Chehab static int dib7000pc_detection(struct i2c_adapter *i2c_adap)
16419a0bf528SMauro Carvalho Chehab {
16429a0bf528SMauro Carvalho Chehab 	u8 *tx, *rx;
16439a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2] = {
16449a0bf528SMauro Carvalho Chehab 		{.addr = 18 >> 1, .flags = 0, .len = 2},
16459a0bf528SMauro Carvalho Chehab 		{.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
16469a0bf528SMauro Carvalho Chehab 	};
16479a0bf528SMauro Carvalho Chehab 	int ret = 0;
16489a0bf528SMauro Carvalho Chehab 
16499a0bf528SMauro Carvalho Chehab 	tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
16509a0bf528SMauro Carvalho Chehab 	if (!tx)
16519a0bf528SMauro Carvalho Chehab 		return -ENOMEM;
16529a0bf528SMauro Carvalho Chehab 	rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
16539a0bf528SMauro Carvalho Chehab 	if (!rx) {
16549a0bf528SMauro Carvalho Chehab 		ret = -ENOMEM;
16559a0bf528SMauro Carvalho Chehab 		goto rx_memory_error;
16569a0bf528SMauro Carvalho Chehab 	}
16579a0bf528SMauro Carvalho Chehab 
16589a0bf528SMauro Carvalho Chehab 	msg[0].buf = tx;
16599a0bf528SMauro Carvalho Chehab 	msg[1].buf = rx;
16609a0bf528SMauro Carvalho Chehab 
16619a0bf528SMauro Carvalho Chehab 	tx[0] = 0x03;
16629a0bf528SMauro Carvalho Chehab 	tx[1] = 0x00;
16639a0bf528SMauro Carvalho Chehab 
16649a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(i2c_adap, msg, 2) == 2)
16659a0bf528SMauro Carvalho Chehab 		if (rx[0] == 0x01 && rx[1] == 0xb3) {
16669a0bf528SMauro Carvalho Chehab 			dprintk("-D-  DiB7000PC detected");
16679a0bf528SMauro Carvalho Chehab 			return 1;
16689a0bf528SMauro Carvalho Chehab 		}
16699a0bf528SMauro Carvalho Chehab 
16709a0bf528SMauro Carvalho Chehab 	msg[0].addr = msg[1].addr = 0x40;
16719a0bf528SMauro Carvalho Chehab 
16729a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(i2c_adap, msg, 2) == 2)
16739a0bf528SMauro Carvalho Chehab 		if (rx[0] == 0x01 && rx[1] == 0xb3) {
16749a0bf528SMauro Carvalho Chehab 			dprintk("-D-  DiB7000PC detected");
16759a0bf528SMauro Carvalho Chehab 			return 1;
16769a0bf528SMauro Carvalho Chehab 		}
16779a0bf528SMauro Carvalho Chehab 
16789a0bf528SMauro Carvalho Chehab 	dprintk("-D-  DiB7000PC not detected");
16799a0bf528SMauro Carvalho Chehab 
16809a0bf528SMauro Carvalho Chehab 	kfree(rx);
16819a0bf528SMauro Carvalho Chehab rx_memory_error:
16829a0bf528SMauro Carvalho Chehab 	kfree(tx);
16839a0bf528SMauro Carvalho Chehab 	return ret;
16849a0bf528SMauro Carvalho Chehab }
16859a0bf528SMauro Carvalho Chehab 
1686*8abe4a0aSMauro Carvalho Chehab static struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
16879a0bf528SMauro Carvalho Chehab {
16889a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *st = demod->demodulator_priv;
16899a0bf528SMauro Carvalho Chehab 	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
16909a0bf528SMauro Carvalho Chehab }
16919a0bf528SMauro Carvalho Chehab 
1692*8abe4a0aSMauro Carvalho Chehab static int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
16939a0bf528SMauro Carvalho Chehab {
16949a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
16959a0bf528SMauro Carvalho Chehab 	u16 val = dib7000p_read_word(state, 235) & 0xffef;
16969a0bf528SMauro Carvalho Chehab 	val |= (onoff & 0x1) << 4;
16979a0bf528SMauro Carvalho Chehab 	dprintk("PID filter enabled %d", onoff);
16989a0bf528SMauro Carvalho Chehab 	return dib7000p_write_word(state, 235, val);
16999a0bf528SMauro Carvalho Chehab }
17009a0bf528SMauro Carvalho Chehab 
1701*8abe4a0aSMauro Carvalho Chehab static int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
17029a0bf528SMauro Carvalho Chehab {
17039a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
17049a0bf528SMauro Carvalho Chehab 	dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
17059a0bf528SMauro Carvalho Chehab 	return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
17069a0bf528SMauro Carvalho Chehab }
17079a0bf528SMauro Carvalho Chehab 
1708*8abe4a0aSMauro Carvalho Chehab static int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
17099a0bf528SMauro Carvalho Chehab {
17109a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *dpst;
17119a0bf528SMauro Carvalho Chehab 	int k = 0;
17129a0bf528SMauro Carvalho Chehab 	u8 new_addr = 0;
17139a0bf528SMauro Carvalho Chehab 
17149a0bf528SMauro Carvalho Chehab 	dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
17159a0bf528SMauro Carvalho Chehab 	if (!dpst)
17169a0bf528SMauro Carvalho Chehab 		return -ENOMEM;
17179a0bf528SMauro Carvalho Chehab 
17189a0bf528SMauro Carvalho Chehab 	dpst->i2c_adap = i2c;
17199a0bf528SMauro Carvalho Chehab 	mutex_init(&dpst->i2c_buffer_lock);
17209a0bf528SMauro Carvalho Chehab 
17219a0bf528SMauro Carvalho Chehab 	for (k = no_of_demods - 1; k >= 0; k--) {
17229a0bf528SMauro Carvalho Chehab 		dpst->cfg = cfg[k];
17239a0bf528SMauro Carvalho Chehab 
17249a0bf528SMauro Carvalho Chehab 		/* designated i2c address */
17259a0bf528SMauro Carvalho Chehab 		if (cfg[k].default_i2c_addr != 0)
17269a0bf528SMauro Carvalho Chehab 			new_addr = cfg[k].default_i2c_addr + (k << 1);
17279a0bf528SMauro Carvalho Chehab 		else
17289a0bf528SMauro Carvalho Chehab 			new_addr = (0x40 + k) << 1;
17299a0bf528SMauro Carvalho Chehab 		dpst->i2c_addr = new_addr;
17309a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(dpst, 1287, 0x0003);	/* sram lead in, rdy */
17319a0bf528SMauro Carvalho Chehab 		if (dib7000p_identify(dpst) != 0) {
17329a0bf528SMauro Carvalho Chehab 			dpst->i2c_addr = default_addr;
17339a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(dpst, 1287, 0x0003);	/* sram lead in, rdy */
17349a0bf528SMauro Carvalho Chehab 			if (dib7000p_identify(dpst) != 0) {
17359a0bf528SMauro Carvalho Chehab 				dprintk("DiB7000P #%d: not identified\n", k);
17369a0bf528SMauro Carvalho Chehab 				kfree(dpst);
17379a0bf528SMauro Carvalho Chehab 				return -EIO;
17389a0bf528SMauro Carvalho Chehab 			}
17399a0bf528SMauro Carvalho Chehab 		}
17409a0bf528SMauro Carvalho Chehab 
17419a0bf528SMauro Carvalho Chehab 		/* start diversity to pull_down div_str - just for i2c-enumeration */
17429a0bf528SMauro Carvalho Chehab 		dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
17439a0bf528SMauro Carvalho Chehab 
17449a0bf528SMauro Carvalho Chehab 		/* set new i2c address and force divstart */
17459a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
17469a0bf528SMauro Carvalho Chehab 
17479a0bf528SMauro Carvalho Chehab 		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
17489a0bf528SMauro Carvalho Chehab 	}
17499a0bf528SMauro Carvalho Chehab 
17509a0bf528SMauro Carvalho Chehab 	for (k = 0; k < no_of_demods; k++) {
17519a0bf528SMauro Carvalho Chehab 		dpst->cfg = cfg[k];
17529a0bf528SMauro Carvalho Chehab 		if (cfg[k].default_i2c_addr != 0)
17539a0bf528SMauro Carvalho Chehab 			dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
17549a0bf528SMauro Carvalho Chehab 		else
17559a0bf528SMauro Carvalho Chehab 			dpst->i2c_addr = (0x40 + k) << 1;
17569a0bf528SMauro Carvalho Chehab 
17579a0bf528SMauro Carvalho Chehab 		// unforce divstr
17589a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
17599a0bf528SMauro Carvalho Chehab 
17609a0bf528SMauro Carvalho Chehab 		/* deactivate div - it was just for i2c-enumeration */
17619a0bf528SMauro Carvalho Chehab 		dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
17629a0bf528SMauro Carvalho Chehab 	}
17639a0bf528SMauro Carvalho Chehab 
17649a0bf528SMauro Carvalho Chehab 	kfree(dpst);
17659a0bf528SMauro Carvalho Chehab 	return 0;
17669a0bf528SMauro Carvalho Chehab }
17679a0bf528SMauro Carvalho Chehab 
17689a0bf528SMauro Carvalho Chehab static const s32 lut_1000ln_mant[] = {
17699a0bf528SMauro Carvalho Chehab 	6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
17709a0bf528SMauro Carvalho Chehab };
17719a0bf528SMauro Carvalho Chehab 
17729a0bf528SMauro Carvalho Chehab static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
17739a0bf528SMauro Carvalho Chehab {
17749a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
17759a0bf528SMauro Carvalho Chehab 	u32 tmp_val = 0, exp = 0, mant = 0;
17769a0bf528SMauro Carvalho Chehab 	s32 pow_i;
17779a0bf528SMauro Carvalho Chehab 	u16 buf[2];
17789a0bf528SMauro Carvalho Chehab 	u8 ix = 0;
17799a0bf528SMauro Carvalho Chehab 
17809a0bf528SMauro Carvalho Chehab 	buf[0] = dib7000p_read_word(state, 0x184);
17819a0bf528SMauro Carvalho Chehab 	buf[1] = dib7000p_read_word(state, 0x185);
17829a0bf528SMauro Carvalho Chehab 	pow_i = (buf[0] << 16) | buf[1];
17839a0bf528SMauro Carvalho Chehab 	dprintk("raw pow_i = %d", pow_i);
17849a0bf528SMauro Carvalho Chehab 
17859a0bf528SMauro Carvalho Chehab 	tmp_val = pow_i;
17869a0bf528SMauro Carvalho Chehab 	while (tmp_val >>= 1)
17879a0bf528SMauro Carvalho Chehab 		exp++;
17889a0bf528SMauro Carvalho Chehab 
17899a0bf528SMauro Carvalho Chehab 	mant = (pow_i * 1000 / (1 << exp));
17909a0bf528SMauro Carvalho Chehab 	dprintk(" mant = %d exp = %d", mant / 1000, exp);
17919a0bf528SMauro Carvalho Chehab 
17929a0bf528SMauro Carvalho Chehab 	ix = (u8) ((mant - 1000) / 100);	/* index of the LUT */
17939a0bf528SMauro Carvalho Chehab 	dprintk(" ix = %d", ix);
17949a0bf528SMauro Carvalho Chehab 
17959a0bf528SMauro Carvalho Chehab 	pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
17969a0bf528SMauro Carvalho Chehab 	pow_i = (pow_i << 8) / 1000;
17979a0bf528SMauro Carvalho Chehab 	dprintk(" pow_i = %d", pow_i);
17989a0bf528SMauro Carvalho Chehab 
17999a0bf528SMauro Carvalho Chehab 	return pow_i;
18009a0bf528SMauro Carvalho Chehab }
18019a0bf528SMauro Carvalho Chehab 
18029a0bf528SMauro Carvalho Chehab static int map_addr_to_serpar_number(struct i2c_msg *msg)
18039a0bf528SMauro Carvalho Chehab {
18049a0bf528SMauro Carvalho Chehab 	if ((msg->buf[0] <= 15))
18059a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 1;
18069a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 17)
18079a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 15;
18089a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 16)
18099a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 17;
18109a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 19)
18119a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 16;
18129a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
18139a0bf528SMauro Carvalho Chehab 		msg->buf[0] -= 3;
18149a0bf528SMauro Carvalho Chehab 	else if (msg->buf[0] == 28)
18159a0bf528SMauro Carvalho Chehab 		msg->buf[0] = 23;
18169a0bf528SMauro Carvalho Chehab 	else
18179a0bf528SMauro Carvalho Chehab 		return -EINVAL;
18189a0bf528SMauro Carvalho Chehab 	return 0;
18199a0bf528SMauro Carvalho Chehab }
18209a0bf528SMauro Carvalho Chehab 
18219a0bf528SMauro Carvalho Chehab static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
18229a0bf528SMauro Carvalho Chehab {
18239a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
18249a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1;
18259a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
18269a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
18279a0bf528SMauro Carvalho Chehab 
18289a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
18299a0bf528SMauro Carvalho Chehab 		n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
18309a0bf528SMauro Carvalho Chehab 		i--;
18319a0bf528SMauro Carvalho Chehab 		if (i == 0)
18329a0bf528SMauro Carvalho Chehab 			dprintk("Tuner ITF: write busy (overflow)");
18339a0bf528SMauro Carvalho Chehab 	}
18349a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
18359a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
18369a0bf528SMauro Carvalho Chehab 
18379a0bf528SMauro Carvalho Chehab 	return num;
18389a0bf528SMauro Carvalho Chehab }
18399a0bf528SMauro Carvalho Chehab 
18409a0bf528SMauro Carvalho Chehab static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
18419a0bf528SMauro Carvalho Chehab {
18429a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
18439a0bf528SMauro Carvalho Chehab 	u8 n_overflow = 1, n_empty = 1;
18449a0bf528SMauro Carvalho Chehab 	u16 i = 1000;
18459a0bf528SMauro Carvalho Chehab 	u16 serpar_num = msg[0].buf[0];
18469a0bf528SMauro Carvalho Chehab 	u16 read_word;
18479a0bf528SMauro Carvalho Chehab 
18489a0bf528SMauro Carvalho Chehab 	while (n_overflow == 1 && i) {
18499a0bf528SMauro Carvalho Chehab 		n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
18509a0bf528SMauro Carvalho Chehab 		i--;
18519a0bf528SMauro Carvalho Chehab 		if (i == 0)
18529a0bf528SMauro Carvalho Chehab 			dprintk("TunerITF: read busy (overflow)");
18539a0bf528SMauro Carvalho Chehab 	}
18549a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
18559a0bf528SMauro Carvalho Chehab 
18569a0bf528SMauro Carvalho Chehab 	i = 1000;
18579a0bf528SMauro Carvalho Chehab 	while (n_empty == 1 && i) {
18589a0bf528SMauro Carvalho Chehab 		n_empty = dib7000p_read_word(state, 1984) & 0x1;
18599a0bf528SMauro Carvalho Chehab 		i--;
18609a0bf528SMauro Carvalho Chehab 		if (i == 0)
18619a0bf528SMauro Carvalho Chehab 			dprintk("TunerITF: read busy (empty)");
18629a0bf528SMauro Carvalho Chehab 	}
18639a0bf528SMauro Carvalho Chehab 	read_word = dib7000p_read_word(state, 1987);
18649a0bf528SMauro Carvalho Chehab 	msg[1].buf[0] = (read_word >> 8) & 0xff;
18659a0bf528SMauro Carvalho Chehab 	msg[1].buf[1] = (read_word) & 0xff;
18669a0bf528SMauro Carvalho Chehab 
18679a0bf528SMauro Carvalho Chehab 	return num;
18689a0bf528SMauro Carvalho Chehab }
18699a0bf528SMauro Carvalho Chehab 
18709a0bf528SMauro Carvalho Chehab static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
18719a0bf528SMauro Carvalho Chehab {
18729a0bf528SMauro 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... */
18739a0bf528SMauro Carvalho Chehab 		if (num == 1) {	/* write */
18749a0bf528SMauro Carvalho Chehab 			return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
18759a0bf528SMauro Carvalho Chehab 		} else {	/* read */
18769a0bf528SMauro Carvalho Chehab 			return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
18779a0bf528SMauro Carvalho Chehab 		}
18789a0bf528SMauro Carvalho Chehab 	}
18799a0bf528SMauro Carvalho Chehab 	return num;
18809a0bf528SMauro Carvalho Chehab }
18819a0bf528SMauro Carvalho Chehab 
18829a0bf528SMauro Carvalho Chehab static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
18839a0bf528SMauro Carvalho Chehab 		struct i2c_msg msg[], int num, u16 apb_address)
18849a0bf528SMauro Carvalho Chehab {
18859a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
18869a0bf528SMauro Carvalho Chehab 	u16 word;
18879a0bf528SMauro Carvalho Chehab 
18889a0bf528SMauro Carvalho Chehab 	if (num == 1) {		/* write */
18899a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
18909a0bf528SMauro Carvalho Chehab 	} else {
18919a0bf528SMauro Carvalho Chehab 		word = dib7000p_read_word(state, apb_address);
18929a0bf528SMauro Carvalho Chehab 		msg[1].buf[0] = (word >> 8) & 0xff;
18939a0bf528SMauro Carvalho Chehab 		msg[1].buf[1] = (word) & 0xff;
18949a0bf528SMauro Carvalho Chehab 	}
18959a0bf528SMauro Carvalho Chehab 
18969a0bf528SMauro Carvalho Chehab 	return num;
18979a0bf528SMauro Carvalho Chehab }
18989a0bf528SMauro Carvalho Chehab 
18999a0bf528SMauro Carvalho Chehab static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
19009a0bf528SMauro Carvalho Chehab {
19019a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
19029a0bf528SMauro Carvalho Chehab 
19039a0bf528SMauro Carvalho Chehab 	u16 apb_address = 0, word;
19049a0bf528SMauro Carvalho Chehab 	int i = 0;
19059a0bf528SMauro Carvalho Chehab 	switch (msg[0].buf[0]) {
19069a0bf528SMauro Carvalho Chehab 	case 0x12:
19079a0bf528SMauro Carvalho Chehab 		apb_address = 1920;
19089a0bf528SMauro Carvalho Chehab 		break;
19099a0bf528SMauro Carvalho Chehab 	case 0x14:
19109a0bf528SMauro Carvalho Chehab 		apb_address = 1921;
19119a0bf528SMauro Carvalho Chehab 		break;
19129a0bf528SMauro Carvalho Chehab 	case 0x24:
19139a0bf528SMauro Carvalho Chehab 		apb_address = 1922;
19149a0bf528SMauro Carvalho Chehab 		break;
19159a0bf528SMauro Carvalho Chehab 	case 0x1a:
19169a0bf528SMauro Carvalho Chehab 		apb_address = 1923;
19179a0bf528SMauro Carvalho Chehab 		break;
19189a0bf528SMauro Carvalho Chehab 	case 0x22:
19199a0bf528SMauro Carvalho Chehab 		apb_address = 1924;
19209a0bf528SMauro Carvalho Chehab 		break;
19219a0bf528SMauro Carvalho Chehab 	case 0x33:
19229a0bf528SMauro Carvalho Chehab 		apb_address = 1926;
19239a0bf528SMauro Carvalho Chehab 		break;
19249a0bf528SMauro Carvalho Chehab 	case 0x34:
19259a0bf528SMauro Carvalho Chehab 		apb_address = 1927;
19269a0bf528SMauro Carvalho Chehab 		break;
19279a0bf528SMauro Carvalho Chehab 	case 0x35:
19289a0bf528SMauro Carvalho Chehab 		apb_address = 1928;
19299a0bf528SMauro Carvalho Chehab 		break;
19309a0bf528SMauro Carvalho Chehab 	case 0x36:
19319a0bf528SMauro Carvalho Chehab 		apb_address = 1929;
19329a0bf528SMauro Carvalho Chehab 		break;
19339a0bf528SMauro Carvalho Chehab 	case 0x37:
19349a0bf528SMauro Carvalho Chehab 		apb_address = 1930;
19359a0bf528SMauro Carvalho Chehab 		break;
19369a0bf528SMauro Carvalho Chehab 	case 0x38:
19379a0bf528SMauro Carvalho Chehab 		apb_address = 1931;
19389a0bf528SMauro Carvalho Chehab 		break;
19399a0bf528SMauro Carvalho Chehab 	case 0x39:
19409a0bf528SMauro Carvalho Chehab 		apb_address = 1932;
19419a0bf528SMauro Carvalho Chehab 		break;
19429a0bf528SMauro Carvalho Chehab 	case 0x2a:
19439a0bf528SMauro Carvalho Chehab 		apb_address = 1935;
19449a0bf528SMauro Carvalho Chehab 		break;
19459a0bf528SMauro Carvalho Chehab 	case 0x2b:
19469a0bf528SMauro Carvalho Chehab 		apb_address = 1936;
19479a0bf528SMauro Carvalho Chehab 		break;
19489a0bf528SMauro Carvalho Chehab 	case 0x2c:
19499a0bf528SMauro Carvalho Chehab 		apb_address = 1937;
19509a0bf528SMauro Carvalho Chehab 		break;
19519a0bf528SMauro Carvalho Chehab 	case 0x2d:
19529a0bf528SMauro Carvalho Chehab 		apb_address = 1938;
19539a0bf528SMauro Carvalho Chehab 		break;
19549a0bf528SMauro Carvalho Chehab 	case 0x2e:
19559a0bf528SMauro Carvalho Chehab 		apb_address = 1939;
19569a0bf528SMauro Carvalho Chehab 		break;
19579a0bf528SMauro Carvalho Chehab 	case 0x2f:
19589a0bf528SMauro Carvalho Chehab 		apb_address = 1940;
19599a0bf528SMauro Carvalho Chehab 		break;
19609a0bf528SMauro Carvalho Chehab 	case 0x30:
19619a0bf528SMauro Carvalho Chehab 		apb_address = 1941;
19629a0bf528SMauro Carvalho Chehab 		break;
19639a0bf528SMauro Carvalho Chehab 	case 0x31:
19649a0bf528SMauro Carvalho Chehab 		apb_address = 1942;
19659a0bf528SMauro Carvalho Chehab 		break;
19669a0bf528SMauro Carvalho Chehab 	case 0x32:
19679a0bf528SMauro Carvalho Chehab 		apb_address = 1943;
19689a0bf528SMauro Carvalho Chehab 		break;
19699a0bf528SMauro Carvalho Chehab 	case 0x3e:
19709a0bf528SMauro Carvalho Chehab 		apb_address = 1944;
19719a0bf528SMauro Carvalho Chehab 		break;
19729a0bf528SMauro Carvalho Chehab 	case 0x3f:
19739a0bf528SMauro Carvalho Chehab 		apb_address = 1945;
19749a0bf528SMauro Carvalho Chehab 		break;
19759a0bf528SMauro Carvalho Chehab 	case 0x40:
19769a0bf528SMauro Carvalho Chehab 		apb_address = 1948;
19779a0bf528SMauro Carvalho Chehab 		break;
19789a0bf528SMauro Carvalho Chehab 	case 0x25:
19799a0bf528SMauro Carvalho Chehab 		apb_address = 914;
19809a0bf528SMauro Carvalho Chehab 		break;
19819a0bf528SMauro Carvalho Chehab 	case 0x26:
19829a0bf528SMauro Carvalho Chehab 		apb_address = 915;
19839a0bf528SMauro Carvalho Chehab 		break;
19849a0bf528SMauro Carvalho Chehab 	case 0x27:
19859a0bf528SMauro Carvalho Chehab 		apb_address = 917;
19869a0bf528SMauro Carvalho Chehab 		break;
19879a0bf528SMauro Carvalho Chehab 	case 0x28:
19889a0bf528SMauro Carvalho Chehab 		apb_address = 916;
19899a0bf528SMauro Carvalho Chehab 		break;
19909a0bf528SMauro Carvalho Chehab 	case 0x1d:
19919a0bf528SMauro Carvalho Chehab 		i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
19929a0bf528SMauro Carvalho Chehab 		word = dib7000p_read_word(state, 384 + i);
19939a0bf528SMauro Carvalho Chehab 		msg[1].buf[0] = (word >> 8) & 0xff;
19949a0bf528SMauro Carvalho Chehab 		msg[1].buf[1] = (word) & 0xff;
19959a0bf528SMauro Carvalho Chehab 		return num;
19969a0bf528SMauro Carvalho Chehab 	case 0x1f:
19979a0bf528SMauro Carvalho Chehab 		if (num == 1) {	/* write */
19989a0bf528SMauro Carvalho Chehab 			word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
19999a0bf528SMauro Carvalho Chehab 			word &= 0x3;
20009a0bf528SMauro Carvalho Chehab 			word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
20019a0bf528SMauro Carvalho Chehab 			dib7000p_write_word(state, 72, word);	/* Set the proper input */
20029a0bf528SMauro Carvalho Chehab 			return num;
20039a0bf528SMauro Carvalho Chehab 		}
20049a0bf528SMauro Carvalho Chehab 	}
20059a0bf528SMauro Carvalho Chehab 
20069a0bf528SMauro Carvalho Chehab 	if (apb_address != 0)	/* R/W acces via APB */
20079a0bf528SMauro Carvalho Chehab 		return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
20089a0bf528SMauro Carvalho Chehab 	else			/* R/W access via SERPAR  */
20099a0bf528SMauro Carvalho Chehab 		return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
20109a0bf528SMauro Carvalho Chehab 
20119a0bf528SMauro Carvalho Chehab 	return 0;
20129a0bf528SMauro Carvalho Chehab }
20139a0bf528SMauro Carvalho Chehab 
20149a0bf528SMauro Carvalho Chehab static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
20159a0bf528SMauro Carvalho Chehab {
20169a0bf528SMauro Carvalho Chehab 	return I2C_FUNC_I2C;
20179a0bf528SMauro Carvalho Chehab }
20189a0bf528SMauro Carvalho Chehab 
20199a0bf528SMauro Carvalho Chehab static struct i2c_algorithm dib7090_tuner_xfer_algo = {
20209a0bf528SMauro Carvalho Chehab 	.master_xfer = dib7090_tuner_xfer,
20219a0bf528SMauro Carvalho Chehab 	.functionality = dib7000p_i2c_func,
20229a0bf528SMauro Carvalho Chehab };
20239a0bf528SMauro Carvalho Chehab 
2024*8abe4a0aSMauro Carvalho Chehab static struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
20259a0bf528SMauro Carvalho Chehab {
20269a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *st = fe->demodulator_priv;
20279a0bf528SMauro Carvalho Chehab 	return &st->dib7090_tuner_adap;
20289a0bf528SMauro Carvalho Chehab }
20299a0bf528SMauro Carvalho Chehab 
20309a0bf528SMauro Carvalho Chehab static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
20319a0bf528SMauro Carvalho Chehab {
20329a0bf528SMauro Carvalho Chehab 	u16 reg;
20339a0bf528SMauro Carvalho Chehab 
20349a0bf528SMauro Carvalho Chehab 	/* drive host bus 2, 3, 4 */
20359a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
20369a0bf528SMauro Carvalho Chehab 	reg |= (drive << 12) | (drive << 6) | drive;
20379a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1798, reg);
20389a0bf528SMauro Carvalho Chehab 
20399a0bf528SMauro Carvalho Chehab 	/* drive host bus 5,6 */
20409a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
20419a0bf528SMauro Carvalho Chehab 	reg |= (drive << 8) | (drive << 2);
20429a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1799, reg);
20439a0bf528SMauro Carvalho Chehab 
20449a0bf528SMauro Carvalho Chehab 	/* drive host bus 7, 8, 9 */
20459a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
20469a0bf528SMauro Carvalho Chehab 	reg |= (drive << 12) | (drive << 6) | drive;
20479a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1800, reg);
20489a0bf528SMauro Carvalho Chehab 
20499a0bf528SMauro Carvalho Chehab 	/* drive host bus 10, 11 */
20509a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
20519a0bf528SMauro Carvalho Chehab 	reg |= (drive << 8) | (drive << 2);
20529a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1801, reg);
20539a0bf528SMauro Carvalho Chehab 
20549a0bf528SMauro Carvalho Chehab 	/* drive host bus 12, 13, 14 */
20559a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
20569a0bf528SMauro Carvalho Chehab 	reg |= (drive << 12) | (drive << 6) | drive;
20579a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1802, reg);
20589a0bf528SMauro Carvalho Chehab 
20599a0bf528SMauro Carvalho Chehab 	return 0;
20609a0bf528SMauro Carvalho Chehab }
20619a0bf528SMauro Carvalho Chehab 
20629a0bf528SMauro Carvalho Chehab static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
20639a0bf528SMauro Carvalho Chehab {
20649a0bf528SMauro Carvalho Chehab 	u32 quantif = 3;
20659a0bf528SMauro Carvalho Chehab 	u32 nom = (insertExtSynchro * P_Kin + syncSize);
20669a0bf528SMauro Carvalho Chehab 	u32 denom = P_Kout;
20679a0bf528SMauro Carvalho Chehab 	u32 syncFreq = ((nom << quantif) / denom);
20689a0bf528SMauro Carvalho Chehab 
20699a0bf528SMauro Carvalho Chehab 	if ((syncFreq & ((1 << quantif) - 1)) != 0)
20709a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif) + 1;
20719a0bf528SMauro Carvalho Chehab 	else
20729a0bf528SMauro Carvalho Chehab 		syncFreq = (syncFreq >> quantif);
20739a0bf528SMauro Carvalho Chehab 
20749a0bf528SMauro Carvalho Chehab 	if (syncFreq != 0)
20759a0bf528SMauro Carvalho Chehab 		syncFreq = syncFreq - 1;
20769a0bf528SMauro Carvalho Chehab 
20779a0bf528SMauro Carvalho Chehab 	return syncFreq;
20789a0bf528SMauro Carvalho Chehab }
20799a0bf528SMauro Carvalho Chehab 
20809a0bf528SMauro 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)
20819a0bf528SMauro Carvalho Chehab {
20829a0bf528SMauro Carvalho Chehab 	dprintk("Configure DibStream Tx");
20839a0bf528SMauro Carvalho Chehab 
20849a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1615, 1);
20859a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1603, P_Kin);
20869a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1605, P_Kout);
20879a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1606, insertExtSynchro);
20889a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1608, synchroMode);
20899a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
20909a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1610, syncWord & 0xffff);
20919a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1612, syncSize);
20929a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1615, 0);
20939a0bf528SMauro Carvalho Chehab 
20949a0bf528SMauro Carvalho Chehab 	return 0;
20959a0bf528SMauro Carvalho Chehab }
20969a0bf528SMauro Carvalho Chehab 
20979a0bf528SMauro 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,
20989a0bf528SMauro Carvalho Chehab 		u32 dataOutRate)
20999a0bf528SMauro Carvalho Chehab {
21009a0bf528SMauro Carvalho Chehab 	u32 syncFreq;
21019a0bf528SMauro Carvalho Chehab 
21029a0bf528SMauro Carvalho Chehab 	dprintk("Configure DibStream Rx");
21039a0bf528SMauro Carvalho Chehab 	if ((P_Kin != 0) && (P_Kout != 0)) {
21049a0bf528SMauro Carvalho Chehab 		syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
21059a0bf528SMauro Carvalho Chehab 		dib7000p_write_word(state, 1542, syncFreq);
21069a0bf528SMauro Carvalho Chehab 	}
21079a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1554, 1);
21089a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1536, P_Kin);
21099a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1537, P_Kout);
21109a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1539, synchroMode);
21119a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
21129a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1541, syncWord & 0xffff);
21139a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1543, syncSize);
21149a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1544, dataOutRate);
21159a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1554, 0);
21169a0bf528SMauro Carvalho Chehab 
21179a0bf528SMauro Carvalho Chehab 	return 0;
21189a0bf528SMauro Carvalho Chehab }
21199a0bf528SMauro Carvalho Chehab 
21209a0bf528SMauro Carvalho Chehab static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
21219a0bf528SMauro Carvalho Chehab {
21229a0bf528SMauro Carvalho Chehab 	u16 reg_1287 = dib7000p_read_word(state, 1287);
21239a0bf528SMauro Carvalho Chehab 
21249a0bf528SMauro Carvalho Chehab 	switch (onoff) {
21259a0bf528SMauro Carvalho Chehab 	case 1:
21269a0bf528SMauro Carvalho Chehab 			reg_1287 &= ~(1<<7);
21279a0bf528SMauro Carvalho Chehab 			break;
21289a0bf528SMauro Carvalho Chehab 	case 0:
21299a0bf528SMauro Carvalho Chehab 			reg_1287 |= (1<<7);
21309a0bf528SMauro Carvalho Chehab 			break;
21319a0bf528SMauro Carvalho Chehab 	}
21329a0bf528SMauro Carvalho Chehab 
21339a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1287, reg_1287);
21349a0bf528SMauro Carvalho Chehab }
21359a0bf528SMauro Carvalho Chehab 
21369a0bf528SMauro Carvalho Chehab static void dib7090_configMpegMux(struct dib7000p_state *state,
21379a0bf528SMauro Carvalho Chehab 		u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
21389a0bf528SMauro Carvalho Chehab {
21399a0bf528SMauro Carvalho Chehab 	dprintk("Enable Mpeg mux");
21409a0bf528SMauro Carvalho Chehab 
21419a0bf528SMauro Carvalho Chehab 	dib7090_enMpegMux(state, 0);
21429a0bf528SMauro Carvalho Chehab 
21439a0bf528SMauro Carvalho Chehab 	/* If the input mode is MPEG do not divide the serial clock */
21449a0bf528SMauro Carvalho Chehab 	if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
21459a0bf528SMauro Carvalho Chehab 		enSerialClkDiv2 = 0;
21469a0bf528SMauro Carvalho Chehab 
21479a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
21489a0bf528SMauro Carvalho Chehab 			| ((enSerialMode & 0x1) << 1)
21499a0bf528SMauro Carvalho Chehab 			| (enSerialClkDiv2 & 0x1));
21509a0bf528SMauro Carvalho Chehab 
21519a0bf528SMauro Carvalho Chehab 	dib7090_enMpegMux(state, 1);
21529a0bf528SMauro Carvalho Chehab }
21539a0bf528SMauro Carvalho Chehab 
21549a0bf528SMauro Carvalho Chehab static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
21559a0bf528SMauro Carvalho Chehab {
21569a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
21579a0bf528SMauro Carvalho Chehab 
21589a0bf528SMauro Carvalho Chehab 	switch (mode) {
21599a0bf528SMauro Carvalho Chehab 	case MPEG_ON_DIBTX:
21609a0bf528SMauro Carvalho Chehab 			dprintk("SET MPEG ON DIBSTREAM TX");
21619a0bf528SMauro Carvalho Chehab 			dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
21629a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<9);
21639a0bf528SMauro Carvalho Chehab 			break;
21649a0bf528SMauro Carvalho Chehab 	case DIV_ON_DIBTX:
21659a0bf528SMauro Carvalho Chehab 			dprintk("SET DIV_OUT ON DIBSTREAM TX");
21669a0bf528SMauro Carvalho Chehab 			dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
21679a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<8);
21689a0bf528SMauro Carvalho Chehab 			break;
21699a0bf528SMauro Carvalho Chehab 	case ADC_ON_DIBTX:
21709a0bf528SMauro Carvalho Chehab 			dprintk("SET ADC_OUT ON DIBSTREAM TX");
21719a0bf528SMauro Carvalho Chehab 			dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
21729a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<7);
21739a0bf528SMauro Carvalho Chehab 			break;
21749a0bf528SMauro Carvalho Chehab 	default:
21759a0bf528SMauro Carvalho Chehab 			break;
21769a0bf528SMauro Carvalho Chehab 	}
21779a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1288, reg_1288);
21789a0bf528SMauro Carvalho Chehab }
21799a0bf528SMauro Carvalho Chehab 
21809a0bf528SMauro Carvalho Chehab static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
21819a0bf528SMauro Carvalho Chehab {
21829a0bf528SMauro Carvalho Chehab 	u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
21839a0bf528SMauro Carvalho Chehab 
21849a0bf528SMauro Carvalho Chehab 	switch (mode) {
21859a0bf528SMauro Carvalho Chehab 	case DEMOUT_ON_HOSTBUS:
21869a0bf528SMauro Carvalho Chehab 			dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
21879a0bf528SMauro Carvalho Chehab 			dib7090_enMpegMux(state, 0);
21889a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<6);
21899a0bf528SMauro Carvalho Chehab 			break;
21909a0bf528SMauro Carvalho Chehab 	case DIBTX_ON_HOSTBUS:
21919a0bf528SMauro Carvalho Chehab 			dprintk("SET DIBSTREAM TX ON HOST BUS");
21929a0bf528SMauro Carvalho Chehab 			dib7090_enMpegMux(state, 0);
21939a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<5);
21949a0bf528SMauro Carvalho Chehab 			break;
21959a0bf528SMauro Carvalho Chehab 	case MPEG_ON_HOSTBUS:
21969a0bf528SMauro Carvalho Chehab 			dprintk("SET MPEG MUX ON HOST BUS");
21979a0bf528SMauro Carvalho Chehab 			reg_1288 |= (1<<4);
21989a0bf528SMauro Carvalho Chehab 			break;
21999a0bf528SMauro Carvalho Chehab 	default:
22009a0bf528SMauro Carvalho Chehab 			break;
22019a0bf528SMauro Carvalho Chehab 	}
22029a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1288, reg_1288);
22039a0bf528SMauro Carvalho Chehab }
22049a0bf528SMauro Carvalho Chehab 
22059a0bf528SMauro Carvalho Chehab int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
22069a0bf528SMauro Carvalho Chehab {
22079a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
22089a0bf528SMauro Carvalho Chehab 	u16 reg_1287;
22099a0bf528SMauro Carvalho Chehab 
22109a0bf528SMauro Carvalho Chehab 	switch (onoff) {
22119a0bf528SMauro Carvalho Chehab 	case 0: /* only use the internal way - not the diversity input */
22129a0bf528SMauro Carvalho Chehab 			dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__);
22139a0bf528SMauro Carvalho Chehab 			dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
22149a0bf528SMauro Carvalho Chehab 
22159a0bf528SMauro Carvalho Chehab 			/* Do not divide the serial clock of MPEG MUX */
22169a0bf528SMauro Carvalho Chehab 			/* in SERIAL MODE in case input mode MPEG is used */
22179a0bf528SMauro Carvalho Chehab 			reg_1287 = dib7000p_read_word(state, 1287);
22189a0bf528SMauro Carvalho Chehab 			/* enSerialClkDiv2 == 1 ? */
22199a0bf528SMauro Carvalho Chehab 			if ((reg_1287 & 0x1) == 1) {
22209a0bf528SMauro Carvalho Chehab 				/* force enSerialClkDiv2 = 0 */
22219a0bf528SMauro Carvalho Chehab 				reg_1287 &= ~0x1;
22229a0bf528SMauro Carvalho Chehab 				dib7000p_write_word(state, 1287, reg_1287);
22239a0bf528SMauro Carvalho Chehab 			}
22249a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 1;
22259a0bf528SMauro Carvalho Chehab 			break;
22269a0bf528SMauro Carvalho Chehab 	case 1: /* both ways */
22279a0bf528SMauro Carvalho Chehab 	case 2: /* only the diversity input */
22289a0bf528SMauro Carvalho Chehab 			dprintk("%s ON : Enable diversity INPUT", __func__);
22299a0bf528SMauro Carvalho Chehab 			dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
22309a0bf528SMauro Carvalho Chehab 			state->input_mode_mpeg = 0;
22319a0bf528SMauro Carvalho Chehab 			break;
22329a0bf528SMauro Carvalho Chehab 	}
22339a0bf528SMauro Carvalho Chehab 
22349a0bf528SMauro Carvalho Chehab 	dib7000p_set_diversity_in(&state->demod, onoff);
22359a0bf528SMauro Carvalho Chehab 	return 0;
22369a0bf528SMauro Carvalho Chehab }
22379a0bf528SMauro Carvalho Chehab 
22389a0bf528SMauro Carvalho Chehab static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
22399a0bf528SMauro Carvalho Chehab {
22409a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
22419a0bf528SMauro Carvalho Chehab 
22429a0bf528SMauro Carvalho Chehab 	u16 outreg, smo_mode, fifo_threshold;
22439a0bf528SMauro Carvalho Chehab 	u8 prefer_mpeg_mux_use = 1;
22449a0bf528SMauro Carvalho Chehab 	int ret = 0;
22459a0bf528SMauro Carvalho Chehab 
22469a0bf528SMauro Carvalho Chehab 	dib7090_host_bus_drive(state, 1);
22479a0bf528SMauro Carvalho Chehab 
22489a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
22499a0bf528SMauro Carvalho Chehab 	smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
22509a0bf528SMauro Carvalho Chehab 	outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
22519a0bf528SMauro Carvalho Chehab 
22529a0bf528SMauro Carvalho Chehab 	switch (mode) {
22539a0bf528SMauro Carvalho Chehab 	case OUTMODE_HIGH_Z:
22549a0bf528SMauro Carvalho Chehab 		outreg = 0;
22559a0bf528SMauro Carvalho Chehab 		break;
22569a0bf528SMauro Carvalho Chehab 
22579a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_SERIAL:
22589a0bf528SMauro Carvalho Chehab 		if (prefer_mpeg_mux_use) {
22599a0bf528SMauro Carvalho Chehab 			dprintk("setting output mode TS_SERIAL using Mpeg Mux");
22609a0bf528SMauro Carvalho Chehab 			dib7090_configMpegMux(state, 3, 1, 1);
22619a0bf528SMauro Carvalho Chehab 			dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
22629a0bf528SMauro Carvalho Chehab 		} else {/* Use Smooth block */
22639a0bf528SMauro Carvalho Chehab 			dprintk("setting output mode TS_SERIAL using Smooth bloc");
22649a0bf528SMauro Carvalho Chehab 			dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
22659a0bf528SMauro Carvalho Chehab 			outreg |= (2<<6) | (0 << 1);
22669a0bf528SMauro Carvalho Chehab 		}
22679a0bf528SMauro Carvalho Chehab 		break;
22689a0bf528SMauro Carvalho Chehab 
22699a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_GATED_CLK:
22709a0bf528SMauro Carvalho Chehab 		if (prefer_mpeg_mux_use) {
22719a0bf528SMauro Carvalho Chehab 			dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux");
22729a0bf528SMauro Carvalho Chehab 			dib7090_configMpegMux(state, 2, 0, 0);
22739a0bf528SMauro Carvalho Chehab 			dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
22749a0bf528SMauro Carvalho Chehab 		} else { /* Use Smooth block */
22759a0bf528SMauro Carvalho Chehab 			dprintk("setting output mode TS_PARALLEL_GATED using Smooth block");
22769a0bf528SMauro Carvalho Chehab 			dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
22779a0bf528SMauro Carvalho Chehab 			outreg |= (0<<6);
22789a0bf528SMauro Carvalho Chehab 		}
22799a0bf528SMauro Carvalho Chehab 		break;
22809a0bf528SMauro Carvalho Chehab 
22819a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_PAR_CONT_CLK:	/* Using Smooth block only */
22829a0bf528SMauro Carvalho Chehab 		dprintk("setting output mode TS_PARALLEL_CONT using Smooth block");
22839a0bf528SMauro Carvalho Chehab 		dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
22849a0bf528SMauro Carvalho Chehab 		outreg |= (1<<6);
22859a0bf528SMauro Carvalho Chehab 		break;
22869a0bf528SMauro Carvalho Chehab 
22879a0bf528SMauro Carvalho Chehab 	case OUTMODE_MPEG2_FIFO:	/* Using Smooth block because not supported by new Mpeg Mux bloc */
22889a0bf528SMauro Carvalho Chehab 		dprintk("setting output mode TS_FIFO using Smooth block");
22899a0bf528SMauro Carvalho Chehab 		dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
22909a0bf528SMauro Carvalho Chehab 		outreg |= (5<<6);
22919a0bf528SMauro Carvalho Chehab 		smo_mode |= (3 << 1);
22929a0bf528SMauro Carvalho Chehab 		fifo_threshold = 512;
22939a0bf528SMauro Carvalho Chehab 		break;
22949a0bf528SMauro Carvalho Chehab 
22959a0bf528SMauro Carvalho Chehab 	case OUTMODE_DIVERSITY:
22969a0bf528SMauro Carvalho Chehab 		dprintk("setting output mode MODE_DIVERSITY");
22979a0bf528SMauro Carvalho Chehab 		dib7090_setDibTxMux(state, DIV_ON_DIBTX);
22989a0bf528SMauro Carvalho Chehab 		dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
22999a0bf528SMauro Carvalho Chehab 		break;
23009a0bf528SMauro Carvalho Chehab 
23019a0bf528SMauro Carvalho Chehab 	case OUTMODE_ANALOG_ADC:
23029a0bf528SMauro Carvalho Chehab 		dprintk("setting output mode MODE_ANALOG_ADC");
23039a0bf528SMauro Carvalho Chehab 		dib7090_setDibTxMux(state, ADC_ON_DIBTX);
23049a0bf528SMauro Carvalho Chehab 		dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
23059a0bf528SMauro Carvalho Chehab 		break;
23069a0bf528SMauro Carvalho Chehab 	}
23079a0bf528SMauro Carvalho Chehab 	if (mode != OUTMODE_HIGH_Z)
23089a0bf528SMauro Carvalho Chehab 		outreg |= (1 << 10);
23099a0bf528SMauro Carvalho Chehab 
23109a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
23119a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5);
23129a0bf528SMauro Carvalho Chehab 
23139a0bf528SMauro Carvalho Chehab 	ret |= dib7000p_write_word(state, 235, smo_mode);
23149a0bf528SMauro Carvalho Chehab 	ret |= dib7000p_write_word(state, 236, fifo_threshold);	/* synchronous fread */
23159a0bf528SMauro Carvalho Chehab 	ret |= dib7000p_write_word(state, 1286, outreg);
23169a0bf528SMauro Carvalho Chehab 
23179a0bf528SMauro Carvalho Chehab 	return ret;
23189a0bf528SMauro Carvalho Chehab }
23199a0bf528SMauro Carvalho Chehab 
2320*8abe4a0aSMauro Carvalho Chehab static int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
23219a0bf528SMauro Carvalho Chehab {
23229a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
23239a0bf528SMauro Carvalho Chehab 	u16 en_cur_state;
23249a0bf528SMauro Carvalho Chehab 
23259a0bf528SMauro Carvalho Chehab 	dprintk("sleep dib7090: %d", onoff);
23269a0bf528SMauro Carvalho Chehab 
23279a0bf528SMauro Carvalho Chehab 	en_cur_state = dib7000p_read_word(state, 1922);
23289a0bf528SMauro Carvalho Chehab 
23299a0bf528SMauro Carvalho Chehab 	if (en_cur_state > 0xff)
23309a0bf528SMauro Carvalho Chehab 		state->tuner_enable = en_cur_state;
23319a0bf528SMauro Carvalho Chehab 
23329a0bf528SMauro Carvalho Chehab 	if (onoff)
23339a0bf528SMauro Carvalho Chehab 		en_cur_state &= 0x00ff;
23349a0bf528SMauro Carvalho Chehab 	else {
23359a0bf528SMauro Carvalho Chehab 		if (state->tuner_enable != 0)
23369a0bf528SMauro Carvalho Chehab 			en_cur_state = state->tuner_enable;
23379a0bf528SMauro Carvalho Chehab 	}
23389a0bf528SMauro Carvalho Chehab 
23399a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1922, en_cur_state);
23409a0bf528SMauro Carvalho Chehab 
23419a0bf528SMauro Carvalho Chehab 	return 0;
23429a0bf528SMauro Carvalho Chehab }
23439a0bf528SMauro Carvalho Chehab 
2344*8abe4a0aSMauro Carvalho Chehab static int dib7090_get_adc_power(struct dvb_frontend *fe)
23459a0bf528SMauro Carvalho Chehab {
23469a0bf528SMauro Carvalho Chehab 	return dib7000p_get_adc_power(fe);
23479a0bf528SMauro Carvalho Chehab }
23489a0bf528SMauro Carvalho Chehab 
2349*8abe4a0aSMauro Carvalho Chehab static int dib7090_slave_reset(struct dvb_frontend *fe)
23509a0bf528SMauro Carvalho Chehab {
23519a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *state = fe->demodulator_priv;
23529a0bf528SMauro Carvalho Chehab 	u16 reg;
23539a0bf528SMauro Carvalho Chehab 
23549a0bf528SMauro Carvalho Chehab 	reg = dib7000p_read_word(state, 1794);
23559a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1794, reg | (4 << 12));
23569a0bf528SMauro Carvalho Chehab 
23579a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(state, 1032, 0xffff);
23589a0bf528SMauro Carvalho Chehab 	return 0;
23599a0bf528SMauro Carvalho Chehab }
23609a0bf528SMauro Carvalho Chehab 
23619a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops dib7000p_ops;
2362*8abe4a0aSMauro Carvalho Chehab static struct dvb_frontend *dib7000p_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
23639a0bf528SMauro Carvalho Chehab {
23649a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *demod;
23659a0bf528SMauro Carvalho Chehab 	struct dib7000p_state *st;
23669a0bf528SMauro Carvalho Chehab 	st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
23679a0bf528SMauro Carvalho Chehab 	if (st == NULL)
23689a0bf528SMauro Carvalho Chehab 		return NULL;
23699a0bf528SMauro Carvalho Chehab 
23709a0bf528SMauro Carvalho Chehab 	memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
23719a0bf528SMauro Carvalho Chehab 	st->i2c_adap = i2c_adap;
23729a0bf528SMauro Carvalho Chehab 	st->i2c_addr = i2c_addr;
23739a0bf528SMauro Carvalho Chehab 	st->gpio_val = cfg->gpio_val;
23749a0bf528SMauro Carvalho Chehab 	st->gpio_dir = cfg->gpio_dir;
23759a0bf528SMauro Carvalho Chehab 
23769a0bf528SMauro Carvalho Chehab 	/* Ensure the output mode remains at the previous default if it's
23779a0bf528SMauro Carvalho Chehab 	 * not specifically set by the caller.
23789a0bf528SMauro Carvalho Chehab 	 */
23799a0bf528SMauro Carvalho Chehab 	if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
23809a0bf528SMauro Carvalho Chehab 		st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
23819a0bf528SMauro Carvalho Chehab 
23829a0bf528SMauro Carvalho Chehab 	demod = &st->demod;
23839a0bf528SMauro Carvalho Chehab 	demod->demodulator_priv = st;
23849a0bf528SMauro Carvalho Chehab 	memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
23859a0bf528SMauro Carvalho Chehab 	mutex_init(&st->i2c_buffer_lock);
23869a0bf528SMauro Carvalho Chehab 
23879a0bf528SMauro Carvalho Chehab 	dib7000p_write_word(st, 1287, 0x0003);	/* sram lead in, rdy */
23889a0bf528SMauro Carvalho Chehab 
23899a0bf528SMauro Carvalho Chehab 	if (dib7000p_identify(st) != 0)
23909a0bf528SMauro Carvalho Chehab 		goto error;
23919a0bf528SMauro Carvalho Chehab 
23929a0bf528SMauro Carvalho Chehab 	st->version = dib7000p_read_word(st, 897);
23939a0bf528SMauro Carvalho Chehab 
23949a0bf528SMauro Carvalho Chehab 	/* FIXME: make sure the dev.parent field is initialized, or else
23959a0bf528SMauro Carvalho Chehab 	   request_firmware() will hit an OOPS (this should be moved somewhere
23969a0bf528SMauro Carvalho Chehab 	   more common) */
23979a0bf528SMauro Carvalho Chehab 	st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
23989a0bf528SMauro Carvalho Chehab 
23999a0bf528SMauro Carvalho Chehab 	dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
24009a0bf528SMauro Carvalho Chehab 
24019a0bf528SMauro Carvalho Chehab 	/* init 7090 tuner adapter */
24029a0bf528SMauro Carvalho Chehab 	strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
24039a0bf528SMauro Carvalho Chehab 	st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
24049a0bf528SMauro Carvalho Chehab 	st->dib7090_tuner_adap.algo_data = NULL;
24059a0bf528SMauro Carvalho Chehab 	st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
24069a0bf528SMauro Carvalho Chehab 	i2c_set_adapdata(&st->dib7090_tuner_adap, st);
24079a0bf528SMauro Carvalho Chehab 	i2c_add_adapter(&st->dib7090_tuner_adap);
24089a0bf528SMauro Carvalho Chehab 
24099a0bf528SMauro Carvalho Chehab 	dib7000p_demod_reset(st);
24109a0bf528SMauro Carvalho Chehab 
24119a0bf528SMauro Carvalho Chehab 	if (st->version == SOC7090) {
24129a0bf528SMauro Carvalho Chehab 		dib7090_set_output_mode(demod, st->cfg.output_mode);
24139a0bf528SMauro Carvalho Chehab 		dib7090_set_diversity_in(demod, 0);
24149a0bf528SMauro Carvalho Chehab 	}
24159a0bf528SMauro Carvalho Chehab 
24169a0bf528SMauro Carvalho Chehab 	return demod;
24179a0bf528SMauro Carvalho Chehab 
24189a0bf528SMauro Carvalho Chehab error:
24199a0bf528SMauro Carvalho Chehab 	kfree(st);
24209a0bf528SMauro Carvalho Chehab 	return NULL;
24219a0bf528SMauro Carvalho Chehab }
2422*8abe4a0aSMauro Carvalho Chehab 
2423*8abe4a0aSMauro Carvalho Chehab void *dib7000p_attach(struct dib7000p_ops *ops)
2424*8abe4a0aSMauro Carvalho Chehab {
2425*8abe4a0aSMauro Carvalho Chehab 	if (!ops)
2426*8abe4a0aSMauro Carvalho Chehab 		return NULL;
2427*8abe4a0aSMauro Carvalho Chehab 
2428*8abe4a0aSMauro Carvalho Chehab 	ops->slave_reset = dib7090_slave_reset;
2429*8abe4a0aSMauro Carvalho Chehab 	ops->get_adc_power = dib7090_get_adc_power;
2430*8abe4a0aSMauro Carvalho Chehab 	ops->dib7000pc_detection = dib7000pc_detection;
2431*8abe4a0aSMauro Carvalho Chehab 	ops->get_i2c_tuner = dib7090_get_i2c_tuner;
2432*8abe4a0aSMauro Carvalho Chehab 	ops->tuner_sleep = dib7090_tuner_sleep;
2433*8abe4a0aSMauro Carvalho Chehab 	ops->init = dib7000p_init;
2434*8abe4a0aSMauro Carvalho Chehab 	ops->set_agc1_min = dib7000p_set_agc1_min;
2435*8abe4a0aSMauro Carvalho Chehab 	ops->set_gpio = dib7000p_set_gpio;
2436*8abe4a0aSMauro Carvalho Chehab 	ops->i2c_enumeration = dib7000p_i2c_enumeration;
2437*8abe4a0aSMauro Carvalho Chehab 	ops->pid_filter = dib7000p_pid_filter;
2438*8abe4a0aSMauro Carvalho Chehab 	ops->pid_filter_ctrl = dib7000p_pid_filter_ctrl;
2439*8abe4a0aSMauro Carvalho Chehab 	ops->get_i2c_master = dib7000p_get_i2c_master;
2440*8abe4a0aSMauro Carvalho Chehab 	ops->update_pll = dib7000p_update_pll;
2441*8abe4a0aSMauro Carvalho Chehab 	ops->ctrl_timf = dib7000p_ctrl_timf;
2442*8abe4a0aSMauro Carvalho Chehab 	ops->get_agc_values = dib7000p_get_agc_values;
2443*8abe4a0aSMauro Carvalho Chehab 	ops->set_wbd_ref = dib7000p_set_wbd_ref;
2444*8abe4a0aSMauro Carvalho Chehab 
2445*8abe4a0aSMauro Carvalho Chehab 	return ops;
2446*8abe4a0aSMauro Carvalho Chehab }
2447*8abe4a0aSMauro Carvalho Chehab EXPORT_SYMBOL(dib7000p_attach);
24489a0bf528SMauro Carvalho Chehab 
24499a0bf528SMauro Carvalho Chehab static struct dvb_frontend_ops dib7000p_ops = {
24509a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_DVBT },
24519a0bf528SMauro Carvalho Chehab 	.info = {
24529a0bf528SMauro Carvalho Chehab 		 .name = "DiBcom 7000PC",
24539a0bf528SMauro Carvalho Chehab 		 .frequency_min = 44250000,
24549a0bf528SMauro Carvalho Chehab 		 .frequency_max = 867250000,
24559a0bf528SMauro Carvalho Chehab 		 .frequency_stepsize = 62500,
24569a0bf528SMauro Carvalho Chehab 		 .caps = FE_CAN_INVERSION_AUTO |
24579a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
24589a0bf528SMauro Carvalho Chehab 		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
24599a0bf528SMauro Carvalho Chehab 		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
24609a0bf528SMauro Carvalho Chehab 		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
24619a0bf528SMauro Carvalho Chehab 		 },
24629a0bf528SMauro Carvalho Chehab 
24639a0bf528SMauro Carvalho Chehab 	.release = dib7000p_release,
24649a0bf528SMauro Carvalho Chehab 
24659a0bf528SMauro Carvalho Chehab 	.init = dib7000p_wakeup,
24669a0bf528SMauro Carvalho Chehab 	.sleep = dib7000p_sleep,
24679a0bf528SMauro Carvalho Chehab 
24689a0bf528SMauro Carvalho Chehab 	.set_frontend = dib7000p_set_frontend,
24699a0bf528SMauro Carvalho Chehab 	.get_tune_settings = dib7000p_fe_get_tune_settings,
24709a0bf528SMauro Carvalho Chehab 	.get_frontend = dib7000p_get_frontend,
24719a0bf528SMauro Carvalho Chehab 
24729a0bf528SMauro Carvalho Chehab 	.read_status = dib7000p_read_status,
24739a0bf528SMauro Carvalho Chehab 	.read_ber = dib7000p_read_ber,
24749a0bf528SMauro Carvalho Chehab 	.read_signal_strength = dib7000p_read_signal_strength,
24759a0bf528SMauro Carvalho Chehab 	.read_snr = dib7000p_read_snr,
24769a0bf528SMauro Carvalho Chehab 	.read_ucblocks = dib7000p_read_unc_blocks,
24779a0bf528SMauro Carvalho Chehab };
24789a0bf528SMauro Carvalho Chehab 
24799a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
24809a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
24819a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
24829a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
2483