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