19a0bf528SMauro Carvalho Chehab /*
29a0bf528SMauro Carvalho Chehab  * Linux-DVB Driver for DiBcom's DiB7000M and
39a0bf528SMauro Carvalho Chehab  *              first generation DiB7000P-demodulator-family.
49a0bf528SMauro Carvalho Chehab  *
59a0bf528SMauro Carvalho Chehab  * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
69a0bf528SMauro Carvalho Chehab  *
79a0bf528SMauro Carvalho Chehab  * This program is free software; you can redistribute it and/or
89a0bf528SMauro Carvalho Chehab  *	modify it under the terms of the GNU General Public License as
99a0bf528SMauro Carvalho Chehab  *	published by the Free Software Foundation, version 2.
109a0bf528SMauro Carvalho Chehab  */
1175702277SMauro Carvalho Chehab 
1275702277SMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1375702277SMauro Carvalho Chehab 
149a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
159a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
169a0bf528SMauro Carvalho Chehab #include <linux/i2c.h>
179a0bf528SMauro Carvalho Chehab #include <linux/mutex.h>
189a0bf528SMauro Carvalho Chehab 
19fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
209a0bf528SMauro Carvalho Chehab 
219a0bf528SMauro Carvalho Chehab #include "dib7000m.h"
229a0bf528SMauro Carvalho Chehab 
239a0bf528SMauro Carvalho Chehab static int debug;
249a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
259a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
269a0bf528SMauro Carvalho Chehab 
2775702277SMauro Carvalho Chehab #define dprintk(fmt, arg...) do {					\
2875702277SMauro Carvalho Chehab 	if (debug)							\
2975702277SMauro Carvalho Chehab 		printk(KERN_DEBUG pr_fmt("%s: " fmt),			\
3075702277SMauro Carvalho Chehab 		       __func__, ##arg);				\
3175702277SMauro Carvalho Chehab } while (0)
329a0bf528SMauro Carvalho Chehab 
339a0bf528SMauro Carvalho Chehab struct dib7000m_state {
349a0bf528SMauro Carvalho Chehab 	struct dvb_frontend demod;
359a0bf528SMauro Carvalho Chehab     struct dib7000m_config cfg;
369a0bf528SMauro Carvalho Chehab 
379a0bf528SMauro Carvalho Chehab 	u8 i2c_addr;
389a0bf528SMauro Carvalho Chehab 	struct i2c_adapter   *i2c_adap;
399a0bf528SMauro Carvalho Chehab 
409a0bf528SMauro Carvalho Chehab 	struct dibx000_i2c_master i2c_master;
419a0bf528SMauro Carvalho Chehab 
429a0bf528SMauro Carvalho Chehab /* offset is 1 in case of the 7000MC */
439a0bf528SMauro Carvalho Chehab 	u8 reg_offs;
449a0bf528SMauro Carvalho Chehab 
459a0bf528SMauro Carvalho Chehab 	u16 wbd_ref;
469a0bf528SMauro Carvalho Chehab 
479a0bf528SMauro Carvalho Chehab 	u8 current_band;
489a0bf528SMauro Carvalho Chehab 	u32 current_bandwidth;
499a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *current_agc;
509a0bf528SMauro Carvalho Chehab 	u32 timf;
519a0bf528SMauro Carvalho Chehab 	u32 timf_default;
529a0bf528SMauro Carvalho Chehab 	u32 internal_clk;
539a0bf528SMauro Carvalho Chehab 
549a0bf528SMauro Carvalho Chehab 	u8 div_force_off : 1;
559a0bf528SMauro Carvalho Chehab 	u8 div_state : 1;
569a0bf528SMauro Carvalho Chehab 	u16 div_sync_wait;
579a0bf528SMauro Carvalho Chehab 
589a0bf528SMauro Carvalho Chehab 	u16 revision;
599a0bf528SMauro Carvalho Chehab 
609a0bf528SMauro Carvalho Chehab 	u8 agc_state;
619a0bf528SMauro Carvalho Chehab 
629a0bf528SMauro Carvalho Chehab 	/* for the I2C transfer */
639a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2];
649a0bf528SMauro Carvalho Chehab 	u8 i2c_write_buffer[4];
659a0bf528SMauro Carvalho Chehab 	u8 i2c_read_buffer[2];
669a0bf528SMauro Carvalho Chehab 	struct mutex i2c_buffer_lock;
679a0bf528SMauro Carvalho Chehab };
689a0bf528SMauro Carvalho Chehab 
699a0bf528SMauro Carvalho Chehab enum dib7000m_power_mode {
709a0bf528SMauro Carvalho Chehab 	DIB7000M_POWER_ALL = 0,
719a0bf528SMauro Carvalho Chehab 
729a0bf528SMauro Carvalho Chehab 	DIB7000M_POWER_NO,
739a0bf528SMauro Carvalho Chehab 	DIB7000M_POWER_INTERF_ANALOG_AGC,
749a0bf528SMauro Carvalho Chehab 	DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD,
759a0bf528SMauro Carvalho Chehab 	DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD,
769a0bf528SMauro Carvalho Chehab 	DIB7000M_POWER_INTERFACE_ONLY,
779a0bf528SMauro Carvalho Chehab };
789a0bf528SMauro Carvalho Chehab 
799a0bf528SMauro Carvalho Chehab static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
809a0bf528SMauro Carvalho Chehab {
819a0bf528SMauro Carvalho Chehab 	u16 ret;
829a0bf528SMauro Carvalho Chehab 
839a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
8475702277SMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
859a0bf528SMauro Carvalho Chehab 		return 0;
869a0bf528SMauro Carvalho Chehab 	}
879a0bf528SMauro Carvalho Chehab 
889a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = (reg >> 8) | 0x80;
899a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
909a0bf528SMauro Carvalho Chehab 
919a0bf528SMauro Carvalho Chehab 	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
929a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c_addr >> 1;
939a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
949a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
959a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 2;
969a0bf528SMauro Carvalho Chehab 	state->msg[1].addr = state->i2c_addr >> 1;
979a0bf528SMauro Carvalho Chehab 	state->msg[1].flags = I2C_M_RD;
989a0bf528SMauro Carvalho Chehab 	state->msg[1].buf = state->i2c_read_buffer;
999a0bf528SMauro Carvalho Chehab 	state->msg[1].len = 2;
1009a0bf528SMauro Carvalho Chehab 
1019a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
10275702277SMauro Carvalho Chehab 		dprintk("i2c read error on %d\n", reg);
1039a0bf528SMauro Carvalho Chehab 
1049a0bf528SMauro Carvalho Chehab 	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
1059a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
1069a0bf528SMauro Carvalho Chehab 
1079a0bf528SMauro Carvalho Chehab 	return ret;
1089a0bf528SMauro Carvalho Chehab }
1099a0bf528SMauro Carvalho Chehab 
1109a0bf528SMauro Carvalho Chehab static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
1119a0bf528SMauro Carvalho Chehab {
1129a0bf528SMauro Carvalho Chehab 	int ret;
1139a0bf528SMauro Carvalho Chehab 
1149a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
11575702277SMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
1169a0bf528SMauro Carvalho Chehab 		return -EINVAL;
1179a0bf528SMauro Carvalho Chehab 	}
1189a0bf528SMauro Carvalho Chehab 
1199a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
1209a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = reg & 0xff;
1219a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
1229a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[3] = val & 0xff;
1239a0bf528SMauro Carvalho Chehab 
1249a0bf528SMauro Carvalho Chehab 	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
1259a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->i2c_addr >> 1;
1269a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
1279a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
1289a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 4;
1299a0bf528SMauro Carvalho Chehab 
1309a0bf528SMauro Carvalho Chehab 	ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
1319a0bf528SMauro Carvalho Chehab 			-EREMOTEIO : 0);
1329a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
1339a0bf528SMauro Carvalho Chehab 	return ret;
1349a0bf528SMauro Carvalho Chehab }
1359a0bf528SMauro Carvalho Chehab static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
1369a0bf528SMauro Carvalho Chehab {
1379a0bf528SMauro Carvalho Chehab 	u16 l = 0, r, *n;
1389a0bf528SMauro Carvalho Chehab 	n = buf;
1399a0bf528SMauro Carvalho Chehab 	l = *n++;
1409a0bf528SMauro Carvalho Chehab 	while (l) {
1419a0bf528SMauro Carvalho Chehab 		r = *n++;
1429a0bf528SMauro Carvalho Chehab 
1439a0bf528SMauro Carvalho Chehab 		if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC
1449a0bf528SMauro Carvalho Chehab 			r++;
1459a0bf528SMauro Carvalho Chehab 
1469a0bf528SMauro Carvalho Chehab 		do {
1479a0bf528SMauro Carvalho Chehab 			dib7000m_write_word(state, r, *n++);
1489a0bf528SMauro Carvalho Chehab 			r++;
1499a0bf528SMauro Carvalho Chehab 		} while (--l);
1509a0bf528SMauro Carvalho Chehab 		l = *n++;
1519a0bf528SMauro Carvalho Chehab 	}
1529a0bf528SMauro Carvalho Chehab }
1539a0bf528SMauro Carvalho Chehab 
1549a0bf528SMauro Carvalho Chehab static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
1559a0bf528SMauro Carvalho Chehab {
1569a0bf528SMauro Carvalho Chehab 	int    ret = 0;
1579a0bf528SMauro Carvalho Chehab 	u16 outreg, fifo_threshold, smo_mode,
1589a0bf528SMauro Carvalho Chehab 		sram = 0x0005; /* by default SRAM output is disabled */
1599a0bf528SMauro Carvalho Chehab 
1609a0bf528SMauro Carvalho Chehab 	outreg = 0;
1619a0bf528SMauro Carvalho Chehab 	fifo_threshold = 1792;
1629a0bf528SMauro Carvalho Chehab 	smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1);
1639a0bf528SMauro Carvalho Chehab 
16475702277SMauro Carvalho Chehab 	dprintk("setting output mode for demod %p to %d\n", &state->demod, mode);
1659a0bf528SMauro Carvalho Chehab 
1669a0bf528SMauro Carvalho Chehab 	switch (mode) {
1679a0bf528SMauro Carvalho Chehab 		case OUTMODE_MPEG2_PAR_GATED_CLK:   // STBs with parallel gated clock
1689a0bf528SMauro Carvalho Chehab 			outreg = (1 << 10);  /* 0x0400 */
1699a0bf528SMauro Carvalho Chehab 			break;
1709a0bf528SMauro Carvalho Chehab 		case OUTMODE_MPEG2_PAR_CONT_CLK:    // STBs with parallel continues clock
1719a0bf528SMauro Carvalho Chehab 			outreg = (1 << 10) | (1 << 6); /* 0x0440 */
1729a0bf528SMauro Carvalho Chehab 			break;
1739a0bf528SMauro Carvalho Chehab 		case OUTMODE_MPEG2_SERIAL:          // STBs with serial input
1749a0bf528SMauro Carvalho Chehab 			outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
1759a0bf528SMauro Carvalho Chehab 			break;
1769a0bf528SMauro Carvalho Chehab 		case OUTMODE_DIVERSITY:
1779a0bf528SMauro Carvalho Chehab 			if (state->cfg.hostbus_diversity)
1789a0bf528SMauro Carvalho Chehab 				outreg = (1 << 10) | (4 << 6); /* 0x0500 */
1799a0bf528SMauro Carvalho Chehab 			else
1809a0bf528SMauro Carvalho Chehab 				sram   |= 0x0c00;
1819a0bf528SMauro Carvalho Chehab 			break;
1829a0bf528SMauro Carvalho Chehab 		case OUTMODE_MPEG2_FIFO:            // e.g. USB feeding
1839a0bf528SMauro Carvalho Chehab 			smo_mode |= (3 << 1);
1849a0bf528SMauro Carvalho Chehab 			fifo_threshold = 512;
1859a0bf528SMauro Carvalho Chehab 			outreg = (1 << 10) | (5 << 6);
1869a0bf528SMauro Carvalho Chehab 			break;
1879a0bf528SMauro Carvalho Chehab 		case OUTMODE_HIGH_Z:  // disable
1889a0bf528SMauro Carvalho Chehab 			outreg = 0;
1899a0bf528SMauro Carvalho Chehab 			break;
1909a0bf528SMauro Carvalho Chehab 		default:
19175702277SMauro Carvalho Chehab 			dprintk("Unhandled output_mode passed to be set for demod %p\n", &state->demod);
1929a0bf528SMauro Carvalho Chehab 			break;
1939a0bf528SMauro Carvalho Chehab 	}
1949a0bf528SMauro Carvalho Chehab 
1959a0bf528SMauro Carvalho Chehab 	if (state->cfg.output_mpeg2_in_188_bytes)
1969a0bf528SMauro Carvalho Chehab 		smo_mode |= (1 << 5) ;
1979a0bf528SMauro Carvalho Chehab 
1989a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state,  294 + state->reg_offs, smo_mode);
1999a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state,  295 + state->reg_offs, fifo_threshold); /* synchronous fread */
2009a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 1795, outreg);
2019a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 1805, sram);
2029a0bf528SMauro Carvalho Chehab 
2039a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x4003) {
2049a0bf528SMauro Carvalho Chehab 		u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd;
2059a0bf528SMauro Carvalho Chehab 		if (mode == OUTMODE_DIVERSITY)
2069a0bf528SMauro Carvalho Chehab 			clk_cfg1 |= (1 << 1); // P_O_CLK_en
2079a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 909, clk_cfg1);
2089a0bf528SMauro Carvalho Chehab 	}
2099a0bf528SMauro Carvalho Chehab 	return ret;
2109a0bf528SMauro Carvalho Chehab }
2119a0bf528SMauro Carvalho Chehab 
2129a0bf528SMauro Carvalho Chehab static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode)
2139a0bf528SMauro Carvalho Chehab {
2149a0bf528SMauro Carvalho Chehab 	/* by default everything is going to be powered off */
2159a0bf528SMauro Carvalho Chehab 	u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906  = 0x3fff;
2169a0bf528SMauro Carvalho Chehab 	u8  offset = 0;
2179a0bf528SMauro Carvalho Chehab 
2189a0bf528SMauro Carvalho Chehab 	/* now, depending on the requested mode, we power on */
2199a0bf528SMauro Carvalho Chehab 	switch (mode) {
2209a0bf528SMauro Carvalho Chehab 		/* power up everything in the demod */
2219a0bf528SMauro Carvalho Chehab 		case DIB7000M_POWER_ALL:
2229a0bf528SMauro Carvalho Chehab 			reg_903 = 0x0000; reg_904 = 0x0000; reg_905 = 0x0000; reg_906 = 0x0000;
2239a0bf528SMauro Carvalho Chehab 			break;
2249a0bf528SMauro Carvalho Chehab 
2259a0bf528SMauro Carvalho Chehab 		/* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */
2269a0bf528SMauro Carvalho Chehab 		case DIB7000M_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */
2279a0bf528SMauro Carvalho Chehab 			reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2));
2289a0bf528SMauro Carvalho Chehab 			break;
2299a0bf528SMauro Carvalho Chehab 
2309a0bf528SMauro Carvalho Chehab 		case DIB7000M_POWER_INTERF_ANALOG_AGC:
2319a0bf528SMauro Carvalho Chehab 			reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10));
2329a0bf528SMauro Carvalho Chehab 			reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2));
2339a0bf528SMauro Carvalho Chehab 			reg_906 &= ~((1 << 0));
2349a0bf528SMauro Carvalho Chehab 			break;
2359a0bf528SMauro Carvalho Chehab 
2369a0bf528SMauro Carvalho Chehab 		case DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD:
2379a0bf528SMauro Carvalho Chehab 			reg_903 = 0x0000; reg_904 = 0x801f; reg_905 = 0x0000; reg_906 = 0x0000;
2389a0bf528SMauro Carvalho Chehab 			break;
2399a0bf528SMauro Carvalho Chehab 
2409a0bf528SMauro Carvalho Chehab 		case DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD:
2419a0bf528SMauro Carvalho Chehab 			reg_903 = 0x0000; reg_904 = 0x8000; reg_905 = 0x010b; reg_906 = 0x0000;
2429a0bf528SMauro Carvalho Chehab 			break;
2439a0bf528SMauro Carvalho Chehab 		case DIB7000M_POWER_NO:
2449a0bf528SMauro Carvalho Chehab 			break;
2459a0bf528SMauro Carvalho Chehab 	}
2469a0bf528SMauro Carvalho Chehab 
2479a0bf528SMauro Carvalho Chehab 	/* always power down unused parts */
2489a0bf528SMauro Carvalho Chehab 	if (!state->cfg.mobile_mode)
2499a0bf528SMauro Carvalho Chehab 		reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
2509a0bf528SMauro Carvalho Chehab 
2519a0bf528SMauro Carvalho Chehab 	/* P_sdio_select_clk = 0 on MC and after*/
2529a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x4000)
2539a0bf528SMauro Carvalho Chehab 		reg_906 <<= 1;
2549a0bf528SMauro Carvalho Chehab 
2559a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x4003)
2569a0bf528SMauro Carvalho Chehab 		offset = 1;
2579a0bf528SMauro Carvalho Chehab 
2589a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 903 + offset, reg_903);
2599a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 904 + offset, reg_904);
2609a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 905 + offset, reg_905);
2619a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 906 + offset, reg_906);
2629a0bf528SMauro Carvalho Chehab }
2639a0bf528SMauro Carvalho Chehab 
2649a0bf528SMauro Carvalho Chehab static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no)
2659a0bf528SMauro Carvalho Chehab {
2669a0bf528SMauro Carvalho Chehab 	int ret = 0;
2679a0bf528SMauro Carvalho Chehab 	u16 reg_913 = dib7000m_read_word(state, 913),
2689a0bf528SMauro Carvalho Chehab 	       reg_914 = dib7000m_read_word(state, 914);
2699a0bf528SMauro Carvalho Chehab 
2709a0bf528SMauro Carvalho Chehab 	switch (no) {
2719a0bf528SMauro Carvalho Chehab 		case DIBX000_SLOW_ADC_ON:
2729a0bf528SMauro Carvalho Chehab 			reg_914 |= (1 << 1) | (1 << 0);
2739a0bf528SMauro Carvalho Chehab 			ret |= dib7000m_write_word(state, 914, reg_914);
2749a0bf528SMauro Carvalho Chehab 			reg_914 &= ~(1 << 1);
2759a0bf528SMauro Carvalho Chehab 			break;
2769a0bf528SMauro Carvalho Chehab 
2779a0bf528SMauro Carvalho Chehab 		case DIBX000_SLOW_ADC_OFF:
2789a0bf528SMauro Carvalho Chehab 			reg_914 |=  (1 << 1) | (1 << 0);
2799a0bf528SMauro Carvalho Chehab 			break;
2809a0bf528SMauro Carvalho Chehab 
2819a0bf528SMauro Carvalho Chehab 		case DIBX000_ADC_ON:
2829a0bf528SMauro Carvalho Chehab 			if (state->revision == 0x4000) { // workaround for PA/MA
2839a0bf528SMauro Carvalho Chehab 				// power-up ADC
2849a0bf528SMauro Carvalho Chehab 				dib7000m_write_word(state, 913, 0);
2859a0bf528SMauro Carvalho Chehab 				dib7000m_write_word(state, 914, reg_914 & 0x3);
2869a0bf528SMauro Carvalho Chehab 				// power-down bandgag
2879a0bf528SMauro Carvalho Chehab 				dib7000m_write_word(state, 913, (1 << 15));
2889a0bf528SMauro Carvalho Chehab 				dib7000m_write_word(state, 914, reg_914 & 0x3);
2899a0bf528SMauro Carvalho Chehab 			}
2909a0bf528SMauro Carvalho Chehab 
2919a0bf528SMauro Carvalho Chehab 			reg_913 &= 0x0fff;
2929a0bf528SMauro Carvalho Chehab 			reg_914 &= 0x0003;
2939a0bf528SMauro Carvalho Chehab 			break;
2949a0bf528SMauro Carvalho Chehab 
2959a0bf528SMauro Carvalho Chehab 		case DIBX000_ADC_OFF: // leave the VBG voltage on
2969a0bf528SMauro Carvalho Chehab 			reg_913 |= (1 << 14) | (1 << 13) | (1 << 12);
2979a0bf528SMauro Carvalho Chehab 			reg_914 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
2989a0bf528SMauro Carvalho Chehab 			break;
2999a0bf528SMauro Carvalho Chehab 
3009a0bf528SMauro Carvalho Chehab 		case DIBX000_VBG_ENABLE:
3019a0bf528SMauro Carvalho Chehab 			reg_913 &= ~(1 << 15);
3029a0bf528SMauro Carvalho Chehab 			break;
3039a0bf528SMauro Carvalho Chehab 
3049a0bf528SMauro Carvalho Chehab 		case DIBX000_VBG_DISABLE:
3059a0bf528SMauro Carvalho Chehab 			reg_913 |= (1 << 15);
3069a0bf528SMauro Carvalho Chehab 			break;
3079a0bf528SMauro Carvalho Chehab 
3089a0bf528SMauro Carvalho Chehab 		default:
3099a0bf528SMauro Carvalho Chehab 			break;
3109a0bf528SMauro Carvalho Chehab 	}
3119a0bf528SMauro Carvalho Chehab 
31275702277SMauro Carvalho Chehab //	dprintk("913: %x, 914: %x\n", reg_913, reg_914);
3139a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 913, reg_913);
3149a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 914, reg_914);
3159a0bf528SMauro Carvalho Chehab 
3169a0bf528SMauro Carvalho Chehab 	return ret;
3179a0bf528SMauro Carvalho Chehab }
3189a0bf528SMauro Carvalho Chehab 
3199a0bf528SMauro Carvalho Chehab static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw)
3209a0bf528SMauro Carvalho Chehab {
3219a0bf528SMauro Carvalho Chehab 	u32 timf;
3229a0bf528SMauro Carvalho Chehab 
3239a0bf528SMauro Carvalho Chehab 	if (!bw)
3249a0bf528SMauro Carvalho Chehab 		bw = 8000;
3259a0bf528SMauro Carvalho Chehab 
3269a0bf528SMauro Carvalho Chehab 	// store the current bandwidth for later use
3279a0bf528SMauro Carvalho Chehab 	state->current_bandwidth = bw;
3289a0bf528SMauro Carvalho Chehab 
3299a0bf528SMauro Carvalho Chehab 	if (state->timf == 0) {
33075702277SMauro Carvalho Chehab 		dprintk("using default timf\n");
3319a0bf528SMauro Carvalho Chehab 		timf = state->timf_default;
3329a0bf528SMauro Carvalho Chehab 	} else {
33375702277SMauro Carvalho Chehab 		dprintk("using updated timf\n");
3349a0bf528SMauro Carvalho Chehab 		timf = state->timf;
3359a0bf528SMauro Carvalho Chehab 	}
3369a0bf528SMauro Carvalho Chehab 
3379a0bf528SMauro Carvalho Chehab 	timf = timf * (bw / 50) / 160;
3389a0bf528SMauro Carvalho Chehab 
3399a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
3409a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 24, (u16) ((timf      ) & 0xffff));
3419a0bf528SMauro Carvalho Chehab 
3429a0bf528SMauro Carvalho Chehab 	return 0;
3439a0bf528SMauro Carvalho Chehab }
3449a0bf528SMauro Carvalho Chehab 
3459a0bf528SMauro Carvalho Chehab static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff)
3469a0bf528SMauro Carvalho Chehab {
3479a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *state = demod->demodulator_priv;
3489a0bf528SMauro Carvalho Chehab 
3499a0bf528SMauro Carvalho Chehab 	if (state->div_force_off) {
35075702277SMauro Carvalho Chehab 		dprintk("diversity combination deactivated - forced by COFDM parameters\n");
3519a0bf528SMauro Carvalho Chehab 		onoff = 0;
3529a0bf528SMauro Carvalho Chehab 	}
3539a0bf528SMauro Carvalho Chehab 	state->div_state = (u8)onoff;
3549a0bf528SMauro Carvalho Chehab 
3559a0bf528SMauro Carvalho Chehab 	if (onoff) {
3569a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 263 + state->reg_offs, 6);
3579a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 264 + state->reg_offs, 6);
3589a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
3599a0bf528SMauro Carvalho Chehab 	} else {
3609a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 263 + state->reg_offs, 1);
3619a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 264 + state->reg_offs, 0);
3629a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 266 + state->reg_offs, 0);
3639a0bf528SMauro Carvalho Chehab 	}
3649a0bf528SMauro Carvalho Chehab 
3659a0bf528SMauro Carvalho Chehab 	return 0;
3669a0bf528SMauro Carvalho Chehab }
3679a0bf528SMauro Carvalho Chehab 
3689a0bf528SMauro Carvalho Chehab static int dib7000m_sad_calib(struct dib7000m_state *state)
3699a0bf528SMauro Carvalho Chehab {
3709a0bf528SMauro Carvalho Chehab 
3719a0bf528SMauro Carvalho Chehab /* internal */
372868c9a17SMauro Carvalho Chehab //	dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writing in set_bandwidth
3739a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 929, (0 << 1) | (0 << 0));
3749a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096
3759a0bf528SMauro Carvalho Chehab 
3769a0bf528SMauro Carvalho Chehab 	/* do the calibration */
3779a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 929, (1 << 0));
3789a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 929, (0 << 0));
3799a0bf528SMauro Carvalho Chehab 
3809a0bf528SMauro Carvalho Chehab 	msleep(1);
3819a0bf528SMauro Carvalho Chehab 
3829a0bf528SMauro Carvalho Chehab 	return 0;
3839a0bf528SMauro Carvalho Chehab }
3849a0bf528SMauro Carvalho Chehab 
3859a0bf528SMauro Carvalho Chehab static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw)
3869a0bf528SMauro Carvalho Chehab {
3879a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
3889a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000)        & 0xffff));
3899a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 21, (u16) ( (bw->ifreq          >> 16) & 0xffff));
3909a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 22, (u16) (  bw->ifreq                 & 0xffff));
3919a0bf528SMauro Carvalho Chehab 
3929a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 928, bw->sad_cfg);
3939a0bf528SMauro Carvalho Chehab }
3949a0bf528SMauro Carvalho Chehab 
3959a0bf528SMauro Carvalho Chehab static void dib7000m_reset_pll(struct dib7000m_state *state)
3969a0bf528SMauro Carvalho Chehab {
3979a0bf528SMauro Carvalho Chehab 	const struct dibx000_bandwidth_config *bw = state->cfg.bw;
3989a0bf528SMauro Carvalho Chehab 	u16 reg_907,reg_910;
3999a0bf528SMauro Carvalho Chehab 
4009a0bf528SMauro Carvalho Chehab 	/* default */
4019a0bf528SMauro Carvalho Chehab 	reg_907 = (bw->pll_bypass << 15) | (bw->modulo << 7) |
4029a0bf528SMauro Carvalho Chehab 		(bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) |
4039a0bf528SMauro Carvalho Chehab 		(bw->enable_refdiv << 1) | (0 << 0);
4049a0bf528SMauro Carvalho Chehab 	reg_910 = (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset;
4059a0bf528SMauro Carvalho Chehab 
4069a0bf528SMauro Carvalho Chehab 	// for this oscillator frequency should be 30 MHz for the Master (default values in the board_parameters give that value)
4079a0bf528SMauro Carvalho Chehab 	// this is only working only for 30 MHz crystals
4089a0bf528SMauro Carvalho Chehab 	if (!state->cfg.quartz_direct) {
4099a0bf528SMauro Carvalho Chehab 		reg_910 |= (1 << 5);  // forcing the predivider to 1
4109a0bf528SMauro Carvalho Chehab 
4119a0bf528SMauro Carvalho Chehab 		// if the previous front-end is baseband, its output frequency is 15 MHz (prev freq divided by 2)
4129a0bf528SMauro Carvalho Chehab 		if(state->cfg.input_clk_is_div_2)
4139a0bf528SMauro Carvalho Chehab 			reg_907 |= (16 << 9);
4149a0bf528SMauro Carvalho Chehab 		else // otherwise the previous front-end puts out its input (default 30MHz) - no extra division necessary
4159a0bf528SMauro Carvalho Chehab 			reg_907 |= (8 << 9);
4169a0bf528SMauro Carvalho Chehab 	} else {
4179a0bf528SMauro Carvalho Chehab 		reg_907 |= (bw->pll_ratio & 0x3f) << 9;
4189a0bf528SMauro Carvalho Chehab 		reg_910 |= (bw->pll_prediv << 5);
4199a0bf528SMauro Carvalho Chehab 	}
4209a0bf528SMauro Carvalho Chehab 
4219a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 910, reg_910); // pll cfg
4229a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 907, reg_907); // clk cfg0
4239a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 908, 0x0006);  // clk_cfg1
4249a0bf528SMauro Carvalho Chehab 
4259a0bf528SMauro Carvalho Chehab 	dib7000m_reset_pll_common(state, bw);
4269a0bf528SMauro Carvalho Chehab }
4279a0bf528SMauro Carvalho Chehab 
4289a0bf528SMauro Carvalho Chehab static void dib7000mc_reset_pll(struct dib7000m_state *state)
4299a0bf528SMauro Carvalho Chehab {
4309a0bf528SMauro Carvalho Chehab 	const struct dibx000_bandwidth_config *bw = state->cfg.bw;
4319a0bf528SMauro Carvalho Chehab 	u16 clk_cfg1;
4329a0bf528SMauro Carvalho Chehab 
4339a0bf528SMauro Carvalho Chehab 	// clk_cfg0
4349a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0));
4359a0bf528SMauro Carvalho Chehab 
4369a0bf528SMauro Carvalho Chehab 	// clk_cfg1
4379a0bf528SMauro Carvalho Chehab 	//dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) |
4389a0bf528SMauro Carvalho Chehab 	clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) |
4399a0bf528SMauro Carvalho Chehab 			(bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) |
4409a0bf528SMauro Carvalho Chehab 			(1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0);
4419a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 908, clk_cfg1);
4429a0bf528SMauro Carvalho Chehab 	clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3);
4439a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 908, clk_cfg1);
4449a0bf528SMauro Carvalho Chehab 
4459a0bf528SMauro Carvalho Chehab 	// smpl_cfg
4469a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7));
4479a0bf528SMauro Carvalho Chehab 
4489a0bf528SMauro Carvalho Chehab 	dib7000m_reset_pll_common(state, bw);
4499a0bf528SMauro Carvalho Chehab }
4509a0bf528SMauro Carvalho Chehab 
4519a0bf528SMauro Carvalho Chehab static int dib7000m_reset_gpio(struct dib7000m_state *st)
4529a0bf528SMauro Carvalho Chehab {
4539a0bf528SMauro Carvalho Chehab 	/* reset the GPIOs */
4549a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(st, 773, st->cfg.gpio_dir);
4559a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(st, 774, st->cfg.gpio_val);
4569a0bf528SMauro Carvalho Chehab 
4579a0bf528SMauro Carvalho Chehab 	/* TODO 782 is P_gpio_od */
4589a0bf528SMauro Carvalho Chehab 
4599a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(st, 775, st->cfg.gpio_pwm_pos);
4609a0bf528SMauro Carvalho Chehab 
4619a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(st, 780, st->cfg.pwm_freq_div);
4629a0bf528SMauro Carvalho Chehab 	return 0;
4639a0bf528SMauro Carvalho Chehab }
4649a0bf528SMauro Carvalho Chehab 
4659a0bf528SMauro Carvalho Chehab static u16 dib7000m_defaults_common[] =
4669a0bf528SMauro Carvalho Chehab 
4679a0bf528SMauro Carvalho Chehab {
4689a0bf528SMauro Carvalho Chehab 	// auto search configuration
4699a0bf528SMauro Carvalho Chehab 	3, 2,
4709a0bf528SMauro Carvalho Chehab 		0x0004,
4719a0bf528SMauro Carvalho Chehab 		0x1000,
4729a0bf528SMauro Carvalho Chehab 		0x0814,
4739a0bf528SMauro Carvalho Chehab 
4749a0bf528SMauro Carvalho Chehab 	12, 6,
4759a0bf528SMauro Carvalho Chehab 		0x001b,
4769a0bf528SMauro Carvalho Chehab 		0x7740,
4779a0bf528SMauro Carvalho Chehab 		0x005b,
4789a0bf528SMauro Carvalho Chehab 		0x8d80,
4799a0bf528SMauro Carvalho Chehab 		0x01c9,
4809a0bf528SMauro Carvalho Chehab 		0xc380,
4819a0bf528SMauro Carvalho Chehab 		0x0000,
4829a0bf528SMauro Carvalho Chehab 		0x0080,
4839a0bf528SMauro Carvalho Chehab 		0x0000,
4849a0bf528SMauro Carvalho Chehab 		0x0090,
4859a0bf528SMauro Carvalho Chehab 		0x0001,
4869a0bf528SMauro Carvalho Chehab 		0xd4c0,
4879a0bf528SMauro Carvalho Chehab 
4889a0bf528SMauro Carvalho Chehab 	1, 26,
4899a0bf528SMauro Carvalho Chehab 		0x6680, // P_corm_thres Lock algorithms configuration
4909a0bf528SMauro Carvalho Chehab 
4919a0bf528SMauro Carvalho Chehab 	1, 170,
4929a0bf528SMauro Carvalho Chehab 		0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on
4939a0bf528SMauro Carvalho Chehab 
4949a0bf528SMauro Carvalho Chehab 	8, 173,
4959a0bf528SMauro Carvalho Chehab 		0,
4969a0bf528SMauro Carvalho Chehab 		0,
4979a0bf528SMauro Carvalho Chehab 		0,
4989a0bf528SMauro Carvalho Chehab 		0,
4999a0bf528SMauro Carvalho Chehab 		0,
5009a0bf528SMauro Carvalho Chehab 		0,
5019a0bf528SMauro Carvalho Chehab 		0,
5029a0bf528SMauro Carvalho Chehab 		0,
5039a0bf528SMauro Carvalho Chehab 
5049a0bf528SMauro Carvalho Chehab 	1, 182,
5059a0bf528SMauro Carvalho Chehab 		8192, // P_fft_nb_to_cut
5069a0bf528SMauro Carvalho Chehab 
5079a0bf528SMauro Carvalho Chehab 	2, 195,
5089a0bf528SMauro Carvalho Chehab 		0x0ccd, // P_pha3_thres
5099a0bf528SMauro Carvalho Chehab 		0,      // P_cti_use_cpe, P_cti_use_prog
5109a0bf528SMauro Carvalho Chehab 
5119a0bf528SMauro Carvalho Chehab 	1, 205,
5129a0bf528SMauro Carvalho Chehab 		0x200f, // P_cspu_regul, P_cspu_win_cut
5139a0bf528SMauro Carvalho Chehab 
5149a0bf528SMauro Carvalho Chehab 	5, 214,
5159a0bf528SMauro Carvalho Chehab 		0x023d, // P_adp_regul_cnt
5169a0bf528SMauro Carvalho Chehab 		0x00a4, // P_adp_noise_cnt
5179a0bf528SMauro Carvalho Chehab 		0x00a4, // P_adp_regul_ext
5189a0bf528SMauro Carvalho Chehab 		0x7ff0, // P_adp_noise_ext
5199a0bf528SMauro Carvalho Chehab 		0x3ccc, // P_adp_fil
5209a0bf528SMauro Carvalho Chehab 
5219a0bf528SMauro Carvalho Chehab 	1, 226,
5229a0bf528SMauro Carvalho Chehab 		0, // P_2d_byp_ti_num
5239a0bf528SMauro Carvalho Chehab 
5249a0bf528SMauro Carvalho Chehab 	1, 255,
5259a0bf528SMauro Carvalho Chehab 		0x800, // P_equal_thres_wgn
5269a0bf528SMauro Carvalho Chehab 
5279a0bf528SMauro Carvalho Chehab 	1, 263,
5289a0bf528SMauro Carvalho Chehab 		0x0001,
5299a0bf528SMauro Carvalho Chehab 
5309a0bf528SMauro Carvalho Chehab 	1, 281,
5319a0bf528SMauro Carvalho Chehab 		0x0010, // P_fec_*
5329a0bf528SMauro Carvalho Chehab 
5339a0bf528SMauro Carvalho Chehab 	1, 294,
5349a0bf528SMauro Carvalho Chehab 		0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
5359a0bf528SMauro Carvalho Chehab 
5369a0bf528SMauro Carvalho Chehab 	0
5379a0bf528SMauro Carvalho Chehab };
5389a0bf528SMauro Carvalho Chehab 
5399a0bf528SMauro Carvalho Chehab static u16 dib7000m_defaults[] =
5409a0bf528SMauro Carvalho Chehab 
5419a0bf528SMauro Carvalho Chehab {
5429a0bf528SMauro Carvalho Chehab 	/* set ADC level to -16 */
5439a0bf528SMauro Carvalho Chehab 	11, 76,
5449a0bf528SMauro Carvalho Chehab 		(1 << 13) - 825 - 117,
5459a0bf528SMauro Carvalho Chehab 		(1 << 13) - 837 - 117,
5469a0bf528SMauro Carvalho Chehab 		(1 << 13) - 811 - 117,
5479a0bf528SMauro Carvalho Chehab 		(1 << 13) - 766 - 117,
5489a0bf528SMauro Carvalho Chehab 		(1 << 13) - 737 - 117,
5499a0bf528SMauro Carvalho Chehab 		(1 << 13) - 693 - 117,
5509a0bf528SMauro Carvalho Chehab 		(1 << 13) - 648 - 117,
5519a0bf528SMauro Carvalho Chehab 		(1 << 13) - 619 - 117,
5529a0bf528SMauro Carvalho Chehab 		(1 << 13) - 575 - 117,
5539a0bf528SMauro Carvalho Chehab 		(1 << 13) - 531 - 117,
5549a0bf528SMauro Carvalho Chehab 		(1 << 13) - 501 - 117,
5559a0bf528SMauro Carvalho Chehab 
5569a0bf528SMauro Carvalho Chehab 	// Tuner IO bank: max drive (14mA)
5579a0bf528SMauro Carvalho Chehab 	1, 912,
5589a0bf528SMauro Carvalho Chehab 		0x2c8a,
5599a0bf528SMauro Carvalho Chehab 
5609a0bf528SMauro Carvalho Chehab 	1, 1817,
5619a0bf528SMauro Carvalho Chehab 		1,
5629a0bf528SMauro Carvalho Chehab 
5639a0bf528SMauro Carvalho Chehab 	0,
5649a0bf528SMauro Carvalho Chehab };
5659a0bf528SMauro Carvalho Chehab 
5669a0bf528SMauro Carvalho Chehab static int dib7000m_demod_reset(struct dib7000m_state *state)
5679a0bf528SMauro Carvalho Chehab {
5689a0bf528SMauro Carvalho Chehab 	dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
5699a0bf528SMauro Carvalho Chehab 
5709a0bf528SMauro Carvalho Chehab 	/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
5719a0bf528SMauro Carvalho Chehab 	dib7000m_set_adc_state(state, DIBX000_VBG_ENABLE);
5729a0bf528SMauro Carvalho Chehab 
5739a0bf528SMauro Carvalho Chehab 	/* restart all parts */
5749a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state,  898, 0xffff);
5759a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state,  899, 0xffff);
5769a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state,  900, 0xff0f);
5779a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state,  901, 0xfffc);
5789a0bf528SMauro Carvalho Chehab 
5799a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state,  898, 0);
5809a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state,  899, 0);
5819a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state,  900, 0);
5829a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state,  901, 0);
5839a0bf528SMauro Carvalho Chehab 
5849a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x4000)
5859a0bf528SMauro Carvalho Chehab 		dib7000m_reset_pll(state);
5869a0bf528SMauro Carvalho Chehab 	else
5879a0bf528SMauro Carvalho Chehab 		dib7000mc_reset_pll(state);
5889a0bf528SMauro Carvalho Chehab 
5899a0bf528SMauro Carvalho Chehab 	if (dib7000m_reset_gpio(state) != 0)
59075702277SMauro Carvalho Chehab 		dprintk("GPIO reset was not successful.\n");
5919a0bf528SMauro Carvalho Chehab 
5929a0bf528SMauro Carvalho Chehab 	if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
59375702277SMauro Carvalho Chehab 		dprintk("OUTPUT_MODE could not be reset.\n");
5949a0bf528SMauro Carvalho Chehab 
5959a0bf528SMauro Carvalho Chehab 	/* unforce divstr regardless whether i2c enumeration was done or not */
5969a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) );
5979a0bf528SMauro Carvalho Chehab 
5989a0bf528SMauro Carvalho Chehab 	dib7000m_set_bandwidth(state, 8000);
5999a0bf528SMauro Carvalho Chehab 
6009a0bf528SMauro Carvalho Chehab 	dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON);
6019a0bf528SMauro Carvalho Chehab 	dib7000m_sad_calib(state);
6029a0bf528SMauro Carvalho Chehab 	dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
6039a0bf528SMauro Carvalho Chehab 
6049a0bf528SMauro Carvalho Chehab 	if (state->cfg.dvbt_mode)
6059a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 1796, 0x0); // select DVB-T output
6069a0bf528SMauro Carvalho Chehab 
6079a0bf528SMauro Carvalho Chehab 	if (state->cfg.mobile_mode)
6089a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 261 + state->reg_offs, 2);
6099a0bf528SMauro Carvalho Chehab 	else
6109a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 224 + state->reg_offs, 1);
6119a0bf528SMauro Carvalho Chehab 
6129a0bf528SMauro Carvalho Chehab 	// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
6139a0bf528SMauro Carvalho Chehab 	if(state->cfg.tuner_is_baseband)
6149a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 36, 0x0755);
6159a0bf528SMauro Carvalho Chehab 	else
6169a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 36, 0x1f55);
6179a0bf528SMauro Carvalho Chehab 
6189a0bf528SMauro Carvalho Chehab 	// P_divclksel=3 P_divbitsel=1
6199a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x4000)
6209a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));
6219a0bf528SMauro Carvalho Chehab 	else
6229a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 909, (3 << 4) | 1);
6239a0bf528SMauro Carvalho Chehab 
6249a0bf528SMauro Carvalho Chehab 	dib7000m_write_tab(state, dib7000m_defaults_common);
6259a0bf528SMauro Carvalho Chehab 	dib7000m_write_tab(state, dib7000m_defaults);
6269a0bf528SMauro Carvalho Chehab 
6279a0bf528SMauro Carvalho Chehab 	dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY);
6289a0bf528SMauro Carvalho Chehab 
6299a0bf528SMauro Carvalho Chehab 	state->internal_clk = state->cfg.bw->internal;
6309a0bf528SMauro Carvalho Chehab 
6319a0bf528SMauro Carvalho Chehab 	return 0;
6329a0bf528SMauro Carvalho Chehab }
6339a0bf528SMauro Carvalho Chehab 
6349a0bf528SMauro Carvalho Chehab static void dib7000m_restart_agc(struct dib7000m_state *state)
6359a0bf528SMauro Carvalho Chehab {
6369a0bf528SMauro Carvalho Chehab 	// P_restart_iqc & P_restart_agc
6379a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 898, 0x0c00);
6389a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 898, 0x0000);
6399a0bf528SMauro Carvalho Chehab }
6409a0bf528SMauro Carvalho Chehab 
6419a0bf528SMauro Carvalho Chehab static int dib7000m_agc_soft_split(struct dib7000m_state *state)
6429a0bf528SMauro Carvalho Chehab {
6439a0bf528SMauro Carvalho Chehab 	u16 agc,split_offset;
6449a0bf528SMauro Carvalho Chehab 
6459a0bf528SMauro Carvalho Chehab 	if(!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
6469a0bf528SMauro Carvalho Chehab 		return 0;
6479a0bf528SMauro Carvalho Chehab 
6489a0bf528SMauro Carvalho Chehab 	// n_agc_global
6499a0bf528SMauro Carvalho Chehab 	agc = dib7000m_read_word(state, 390);
6509a0bf528SMauro Carvalho Chehab 
6519a0bf528SMauro Carvalho Chehab 	if (agc > state->current_agc->split.min_thres)
6529a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.min;
6539a0bf528SMauro Carvalho Chehab 	else if (agc < state->current_agc->split.max_thres)
6549a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.max;
6559a0bf528SMauro Carvalho Chehab 	else
6569a0bf528SMauro Carvalho Chehab 		split_offset = state->current_agc->split.max *
6579a0bf528SMauro Carvalho Chehab 			(agc - state->current_agc->split.min_thres) /
6589a0bf528SMauro Carvalho Chehab 			(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
6599a0bf528SMauro Carvalho Chehab 
66075702277SMauro Carvalho Chehab 	dprintk("AGC split_offset: %d\n", split_offset);
6619a0bf528SMauro Carvalho Chehab 
6629a0bf528SMauro Carvalho Chehab 	// P_agc_force_split and P_agc_split_offset
6639a0bf528SMauro Carvalho Chehab 	return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset);
6649a0bf528SMauro Carvalho Chehab }
6659a0bf528SMauro Carvalho Chehab 
6669a0bf528SMauro Carvalho Chehab static int dib7000m_update_lna(struct dib7000m_state *state)
6679a0bf528SMauro Carvalho Chehab {
6689a0bf528SMauro Carvalho Chehab 	u16 dyn_gain;
6699a0bf528SMauro Carvalho Chehab 
6709a0bf528SMauro Carvalho Chehab 	if (state->cfg.update_lna) {
6719a0bf528SMauro Carvalho Chehab 		// read dyn_gain here (because it is demod-dependent and not fe)
6729a0bf528SMauro Carvalho Chehab 		dyn_gain = dib7000m_read_word(state, 390);
6739a0bf528SMauro Carvalho Chehab 
6749a0bf528SMauro Carvalho Chehab 		if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
6759a0bf528SMauro Carvalho Chehab 			dib7000m_restart_agc(state);
6769a0bf528SMauro Carvalho Chehab 			return 1;
6779a0bf528SMauro Carvalho Chehab 		}
6789a0bf528SMauro Carvalho Chehab 	}
6799a0bf528SMauro Carvalho Chehab 	return 0;
6809a0bf528SMauro Carvalho Chehab }
6819a0bf528SMauro Carvalho Chehab 
6829a0bf528SMauro Carvalho Chehab static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
6839a0bf528SMauro Carvalho Chehab {
6849a0bf528SMauro Carvalho Chehab 	struct dibx000_agc_config *agc = NULL;
6859a0bf528SMauro Carvalho Chehab 	int i;
6869a0bf528SMauro Carvalho Chehab 	if (state->current_band == band && state->current_agc != NULL)
6879a0bf528SMauro Carvalho Chehab 		return 0;
6889a0bf528SMauro Carvalho Chehab 	state->current_band = band;
6899a0bf528SMauro Carvalho Chehab 
6909a0bf528SMauro Carvalho Chehab 	for (i = 0; i < state->cfg.agc_config_count; i++)
6919a0bf528SMauro Carvalho Chehab 		if (state->cfg.agc[i].band_caps & band) {
6929a0bf528SMauro Carvalho Chehab 			agc = &state->cfg.agc[i];
6939a0bf528SMauro Carvalho Chehab 			break;
6949a0bf528SMauro Carvalho Chehab 		}
6959a0bf528SMauro Carvalho Chehab 
6969a0bf528SMauro Carvalho Chehab 	if (agc == NULL) {
69775702277SMauro Carvalho Chehab 		dprintk("no valid AGC configuration found for band 0x%02x\n", band);
6989a0bf528SMauro Carvalho Chehab 		return -EINVAL;
6999a0bf528SMauro Carvalho Chehab 	}
7009a0bf528SMauro Carvalho Chehab 
7019a0bf528SMauro Carvalho Chehab 	state->current_agc = agc;
7029a0bf528SMauro Carvalho Chehab 
7039a0bf528SMauro Carvalho Chehab 	/* AGC */
7049a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 72 ,  agc->setup);
7059a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 73 ,  agc->inv_gain);
7069a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 74 ,  agc->time_stabiliz);
7079a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 97 , (agc->alpha_level << 12) | agc->thlock);
7089a0bf528SMauro Carvalho Chehab 
7099a0bf528SMauro Carvalho Chehab 	// Demod AGC loop configuration
7109a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp);
7119a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 99, (agc->beta_mant  << 6) | agc->beta_exp);
7129a0bf528SMauro Carvalho Chehab 
71375702277SMauro Carvalho Chehab 	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
7149a0bf528SMauro Carvalho Chehab 		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
7159a0bf528SMauro Carvalho Chehab 
7169a0bf528SMauro Carvalho Chehab 	/* AGC continued */
7179a0bf528SMauro Carvalho Chehab 	if (state->wbd_ref != 0)
7189a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 102, state->wbd_ref);
7199a0bf528SMauro Carvalho Chehab 	else // use default
7209a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 102, agc->wbd_ref);
7219a0bf528SMauro Carvalho Chehab 
7229a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 103, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) );
7239a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 104,  agc->agc1_max);
7249a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 105,  agc->agc1_min);
7259a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 106,  agc->agc2_max);
7269a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 107,  agc->agc2_min);
7279a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 108, (agc->agc1_pt1 << 8) | agc->agc1_pt2 );
7289a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 109, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
7299a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 110, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
7309a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 111, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
7319a0bf528SMauro Carvalho Chehab 
7329a0bf528SMauro Carvalho Chehab 	if (state->revision > 0x4000) { // settings for the MC
7339a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 71,   agc->agc1_pt3);
73475702277SMauro Carvalho Chehab //		dprintk("929: %x %d %d\n",
7359a0bf528SMauro Carvalho Chehab //			(dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel);
7369a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
7379a0bf528SMauro Carvalho Chehab 	} else {
7389a0bf528SMauro Carvalho Chehab 		// wrong default values
7399a0bf528SMauro Carvalho Chehab 		u16 b[9] = { 676, 696, 717, 737, 758, 778, 799, 819, 840 };
7409a0bf528SMauro Carvalho Chehab 		for (i = 0; i < 9; i++)
7419a0bf528SMauro Carvalho Chehab 			dib7000m_write_word(state, 88 + i, b[i]);
7429a0bf528SMauro Carvalho Chehab 	}
7439a0bf528SMauro Carvalho Chehab 	return 0;
7449a0bf528SMauro Carvalho Chehab }
7459a0bf528SMauro Carvalho Chehab 
7469a0bf528SMauro Carvalho Chehab static void dib7000m_update_timf(struct dib7000m_state *state)
7479a0bf528SMauro Carvalho Chehab {
7489a0bf528SMauro Carvalho Chehab 	u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437);
7499a0bf528SMauro Carvalho Chehab 	state->timf = timf * 160 / (state->current_bandwidth / 50);
7509a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 23, (u16) (timf >> 16));
7519a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 24, (u16) (timf & 0xffff));
75275702277SMauro Carvalho Chehab 	dprintk("updated timf_frequency: %d (default: %d)\n", state->timf, state->timf_default);
7539a0bf528SMauro Carvalho Chehab }
7549a0bf528SMauro Carvalho Chehab 
7559a0bf528SMauro Carvalho Chehab static int dib7000m_agc_startup(struct dvb_frontend *demod)
7569a0bf528SMauro Carvalho Chehab {
7579a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
7589a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *state = demod->demodulator_priv;
7599a0bf528SMauro Carvalho Chehab 	u16 cfg_72 = dib7000m_read_word(state, 72);
7609a0bf528SMauro Carvalho Chehab 	int ret = -1;
7619a0bf528SMauro Carvalho Chehab 	u8 *agc_state = &state->agc_state;
7629a0bf528SMauro Carvalho Chehab 	u8 agc_split;
7639a0bf528SMauro Carvalho Chehab 
7649a0bf528SMauro Carvalho Chehab 	switch (state->agc_state) {
7659a0bf528SMauro Carvalho Chehab 		case 0:
7669a0bf528SMauro Carvalho Chehab 			// set power-up level: interf+analog+AGC
7679a0bf528SMauro Carvalho Chehab 			dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);
7689a0bf528SMauro Carvalho Chehab 			dib7000m_set_adc_state(state, DIBX000_ADC_ON);
7699a0bf528SMauro Carvalho Chehab 
7709a0bf528SMauro Carvalho Chehab 			if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
7719a0bf528SMauro Carvalho Chehab 				return -1;
7729a0bf528SMauro Carvalho Chehab 
7739a0bf528SMauro Carvalho Chehab 			ret = 7; /* ADC power up */
7749a0bf528SMauro Carvalho Chehab 			(*agc_state)++;
7759a0bf528SMauro Carvalho Chehab 			break;
7769a0bf528SMauro Carvalho Chehab 
7779a0bf528SMauro Carvalho Chehab 		case 1:
7789a0bf528SMauro Carvalho Chehab 			/* AGC initialization */
7799a0bf528SMauro Carvalho Chehab 			if (state->cfg.agc_control)
7809a0bf528SMauro Carvalho Chehab 				state->cfg.agc_control(&state->demod, 1);
7819a0bf528SMauro Carvalho Chehab 
7829a0bf528SMauro Carvalho Chehab 			dib7000m_write_word(state, 75, 32768);
7839a0bf528SMauro Carvalho Chehab 			if (!state->current_agc->perform_agc_softsplit) {
7849a0bf528SMauro Carvalho Chehab 				/* we are using the wbd - so slow AGC startup */
7859a0bf528SMauro Carvalho Chehab 				dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */
7869a0bf528SMauro Carvalho Chehab 				(*agc_state)++;
7879a0bf528SMauro Carvalho Chehab 				ret = 5;
7889a0bf528SMauro Carvalho Chehab 			} else {
7899a0bf528SMauro Carvalho Chehab 				/* default AGC startup */
7909a0bf528SMauro Carvalho Chehab 				(*agc_state) = 4;
7919a0bf528SMauro Carvalho Chehab 				/* wait AGC rough lock time */
7929a0bf528SMauro Carvalho Chehab 				ret = 7;
7939a0bf528SMauro Carvalho Chehab 			}
7949a0bf528SMauro Carvalho Chehab 
7959a0bf528SMauro Carvalho Chehab 			dib7000m_restart_agc(state);
7969a0bf528SMauro Carvalho Chehab 			break;
7979a0bf528SMauro Carvalho Chehab 
7989a0bf528SMauro Carvalho Chehab 		case 2: /* fast split search path after 5sec */
7999a0bf528SMauro Carvalho Chehab 			dib7000m_write_word(state,  72, cfg_72 | (1 << 4)); /* freeze AGC loop */
8009a0bf528SMauro Carvalho Chehab 			dib7000m_write_word(state, 103, 2 << 9);            /* fast split search 0.25kHz */
8019a0bf528SMauro Carvalho Chehab 			(*agc_state)++;
8029a0bf528SMauro Carvalho Chehab 			ret = 14;
8039a0bf528SMauro Carvalho Chehab 			break;
8049a0bf528SMauro Carvalho Chehab 
8059a0bf528SMauro Carvalho Chehab 	case 3: /* split search ended */
8069a0bf528SMauro Carvalho Chehab 			agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */
8079a0bf528SMauro Carvalho Chehab 			dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */
8089a0bf528SMauro Carvalho Chehab 
8099a0bf528SMauro Carvalho Chehab 			dib7000m_write_word(state, 72,  cfg_72 & ~(1 << 4));   /* std AGC loop */
8109a0bf528SMauro Carvalho Chehab 			dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
8119a0bf528SMauro Carvalho Chehab 
8129a0bf528SMauro Carvalho Chehab 			dib7000m_restart_agc(state);
8139a0bf528SMauro Carvalho Chehab 
81475702277SMauro Carvalho Chehab 			dprintk("SPLIT %p: %hd\n", demod, agc_split);
8159a0bf528SMauro Carvalho Chehab 
8169a0bf528SMauro Carvalho Chehab 			(*agc_state)++;
8179a0bf528SMauro Carvalho Chehab 			ret = 5;
8189a0bf528SMauro Carvalho Chehab 			break;
8199a0bf528SMauro Carvalho Chehab 
8209a0bf528SMauro Carvalho Chehab 		case 4: /* LNA startup */
8219a0bf528SMauro Carvalho Chehab 			/* wait AGC accurate lock time */
8229a0bf528SMauro Carvalho Chehab 			ret = 7;
8239a0bf528SMauro Carvalho Chehab 
8249a0bf528SMauro Carvalho Chehab 			if (dib7000m_update_lna(state))
8259a0bf528SMauro Carvalho Chehab 				// wait only AGC rough lock time
8269a0bf528SMauro Carvalho Chehab 				ret = 5;
8279a0bf528SMauro Carvalho Chehab 			else
8289a0bf528SMauro Carvalho Chehab 				(*agc_state)++;
8299a0bf528SMauro Carvalho Chehab 			break;
8309a0bf528SMauro Carvalho Chehab 
8319a0bf528SMauro Carvalho Chehab 		case 5:
8329a0bf528SMauro Carvalho Chehab 			dib7000m_agc_soft_split(state);
8339a0bf528SMauro Carvalho Chehab 
8349a0bf528SMauro Carvalho Chehab 			if (state->cfg.agc_control)
8359a0bf528SMauro Carvalho Chehab 				state->cfg.agc_control(&state->demod, 0);
8369a0bf528SMauro Carvalho Chehab 
8379a0bf528SMauro Carvalho Chehab 			(*agc_state)++;
8389a0bf528SMauro Carvalho Chehab 			break;
8399a0bf528SMauro Carvalho Chehab 
8409a0bf528SMauro Carvalho Chehab 		default:
8419a0bf528SMauro Carvalho Chehab 			break;
8429a0bf528SMauro Carvalho Chehab 	}
8439a0bf528SMauro Carvalho Chehab 	return ret;
8449a0bf528SMauro Carvalho Chehab }
8459a0bf528SMauro Carvalho Chehab 
8469a0bf528SMauro Carvalho Chehab static void dib7000m_set_channel(struct dib7000m_state *state, struct dtv_frontend_properties *ch,
8479a0bf528SMauro Carvalho Chehab 				 u8 seq)
8489a0bf528SMauro Carvalho Chehab {
8499a0bf528SMauro Carvalho Chehab 	u16 value, est[4];
8509a0bf528SMauro Carvalho Chehab 
8519a0bf528SMauro Carvalho Chehab 	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
8529a0bf528SMauro Carvalho Chehab 
8539a0bf528SMauro Carvalho Chehab 	/* nfft, guard, qam, alpha */
8549a0bf528SMauro Carvalho Chehab 	value = 0;
8559a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
8569a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
8579a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_4K: value |= (2 << 7); break;
8589a0bf528SMauro Carvalho Chehab 		default:
8599a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
8609a0bf528SMauro Carvalho Chehab 	}
8619a0bf528SMauro Carvalho Chehab 	switch (ch->guard_interval) {
8629a0bf528SMauro Carvalho Chehab 		case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
8639a0bf528SMauro Carvalho Chehab 		case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
8649a0bf528SMauro Carvalho Chehab 		case GUARD_INTERVAL_1_4:  value |= (3 << 5); break;
8659a0bf528SMauro Carvalho Chehab 		default:
8669a0bf528SMauro Carvalho Chehab 		case GUARD_INTERVAL_1_8:  value |= (2 << 5); break;
8679a0bf528SMauro Carvalho Chehab 	}
8689a0bf528SMauro Carvalho Chehab 	switch (ch->modulation) {
8699a0bf528SMauro Carvalho Chehab 		case QPSK:  value |= (0 << 3); break;
8709a0bf528SMauro Carvalho Chehab 		case QAM_16: value |= (1 << 3); break;
8719a0bf528SMauro Carvalho Chehab 		default:
8729a0bf528SMauro Carvalho Chehab 		case QAM_64: value |= (2 << 3); break;
8739a0bf528SMauro Carvalho Chehab 	}
8749a0bf528SMauro Carvalho Chehab 	switch (HIERARCHY_1) {
8759a0bf528SMauro Carvalho Chehab 		case HIERARCHY_2: value |= 2; break;
8769a0bf528SMauro Carvalho Chehab 		case HIERARCHY_4: value |= 4; break;
8779a0bf528SMauro Carvalho Chehab 		default:
8789a0bf528SMauro Carvalho Chehab 		case HIERARCHY_1: value |= 1; break;
8799a0bf528SMauro Carvalho Chehab 	}
8809a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 0, value);
8819a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 5, (seq << 4));
8829a0bf528SMauro Carvalho Chehab 
8839a0bf528SMauro Carvalho Chehab 	/* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
8849a0bf528SMauro Carvalho Chehab 	value = 0;
8859a0bf528SMauro Carvalho Chehab 	if (1 != 0)
8869a0bf528SMauro Carvalho Chehab 		value |= (1 << 6);
8879a0bf528SMauro Carvalho Chehab 	if (ch->hierarchy == 1)
8889a0bf528SMauro Carvalho Chehab 		value |= (1 << 4);
8899a0bf528SMauro Carvalho Chehab 	if (1 == 1)
8909a0bf528SMauro Carvalho Chehab 		value |= 1;
8919a0bf528SMauro Carvalho Chehab 	switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
8929a0bf528SMauro Carvalho Chehab 		case FEC_2_3: value |= (2 << 1); break;
8939a0bf528SMauro Carvalho Chehab 		case FEC_3_4: value |= (3 << 1); break;
8949a0bf528SMauro Carvalho Chehab 		case FEC_5_6: value |= (5 << 1); break;
8959a0bf528SMauro Carvalho Chehab 		case FEC_7_8: value |= (7 << 1); break;
8969a0bf528SMauro Carvalho Chehab 		default:
8979a0bf528SMauro Carvalho Chehab 		case FEC_1_2: value |= (1 << 1); break;
8989a0bf528SMauro Carvalho Chehab 	}
8999a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 267 + state->reg_offs, value);
9009a0bf528SMauro Carvalho Chehab 
9019a0bf528SMauro Carvalho Chehab 	/* offset loop parameters */
9029a0bf528SMauro Carvalho Chehab 
9039a0bf528SMauro Carvalho Chehab 	/* P_timf_alpha = 6, P_corm_alpha=6, P_corm_thres=0x80 */
9049a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 26, (6 << 12) | (6 << 8) | 0x80);
9059a0bf528SMauro Carvalho Chehab 
9069a0bf528SMauro Carvalho Chehab 	/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=1, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
9079a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (1 << 9) | (3 << 5) | (1 << 4) | (0x3));
9089a0bf528SMauro Carvalho Chehab 
9099a0bf528SMauro Carvalho Chehab 	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max=3 */
9109a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 32, (0 << 4) | 0x3);
9119a0bf528SMauro Carvalho Chehab 
9129a0bf528SMauro Carvalho Chehab 	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step=5 */
9139a0bf528SMauro Carvalho Chehab 	dib7000m_write_word(state, 33, (0 << 4) | 0x5);
9149a0bf528SMauro Carvalho Chehab 
9159a0bf528SMauro Carvalho Chehab 	/* P_dvsy_sync_wait */
9169a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
9179a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_8K: value = 256; break;
9189a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_4K: value = 128; break;
9199a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_2K:
9209a0bf528SMauro Carvalho Chehab 		default: value = 64; break;
9219a0bf528SMauro Carvalho Chehab 	}
9229a0bf528SMauro Carvalho Chehab 	switch (ch->guard_interval) {
9239a0bf528SMauro Carvalho Chehab 		case GUARD_INTERVAL_1_16: value *= 2; break;
9249a0bf528SMauro Carvalho Chehab 		case GUARD_INTERVAL_1_8:  value *= 4; break;
9259a0bf528SMauro Carvalho Chehab 		case GUARD_INTERVAL_1_4:  value *= 8; break;
9269a0bf528SMauro Carvalho Chehab 		default:
9279a0bf528SMauro Carvalho Chehab 		case GUARD_INTERVAL_1_32: value *= 1; break;
9289a0bf528SMauro Carvalho Chehab 	}
9299a0bf528SMauro Carvalho Chehab 	state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO
9309a0bf528SMauro Carvalho Chehab 
931868c9a17SMauro Carvalho Chehab 	/* deactivate the possibility of diversity reception if extended interleave - not for 7000MC */
9329a0bf528SMauro Carvalho Chehab 	/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
9339a0bf528SMauro Carvalho Chehab 	if (1 == 1 || state->revision > 0x4000)
9349a0bf528SMauro Carvalho Chehab 		state->div_force_off = 0;
9359a0bf528SMauro Carvalho Chehab 	else
9369a0bf528SMauro Carvalho Chehab 		state->div_force_off = 1;
9379a0bf528SMauro Carvalho Chehab 	dib7000m_set_diversity_in(&state->demod, state->div_state);
9389a0bf528SMauro Carvalho Chehab 
9399a0bf528SMauro Carvalho Chehab 	/* channel estimation fine configuration */
9409a0bf528SMauro Carvalho Chehab 	switch (ch->modulation) {
9419a0bf528SMauro Carvalho Chehab 		case QAM_64:
9429a0bf528SMauro Carvalho Chehab 			est[0] = 0x0148;       /* P_adp_regul_cnt 0.04 */
9439a0bf528SMauro Carvalho Chehab 			est[1] = 0xfff0;       /* P_adp_noise_cnt -0.002 */
9449a0bf528SMauro Carvalho Chehab 			est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
9459a0bf528SMauro Carvalho Chehab 			est[3] = 0xfff8;       /* P_adp_noise_ext -0.001 */
9469a0bf528SMauro Carvalho Chehab 			break;
9479a0bf528SMauro Carvalho Chehab 		case QAM_16:
9489a0bf528SMauro Carvalho Chehab 			est[0] = 0x023d;       /* P_adp_regul_cnt 0.07 */
9499a0bf528SMauro Carvalho Chehab 			est[1] = 0xffdf;       /* P_adp_noise_cnt -0.004 */
9509a0bf528SMauro Carvalho Chehab 			est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
9519a0bf528SMauro Carvalho Chehab 			est[3] = 0xfff0;       /* P_adp_noise_ext -0.002 */
9529a0bf528SMauro Carvalho Chehab 			break;
9539a0bf528SMauro Carvalho Chehab 		default:
9549a0bf528SMauro Carvalho Chehab 			est[0] = 0x099a;       /* P_adp_regul_cnt 0.3 */
9559a0bf528SMauro Carvalho Chehab 			est[1] = 0xffae;       /* P_adp_noise_cnt -0.01 */
9569a0bf528SMauro Carvalho Chehab 			est[2] = 0x0333;       /* P_adp_regul_ext 0.1 */
9579a0bf528SMauro Carvalho Chehab 			est[3] = 0xfff8;       /* P_adp_noise_ext -0.002 */
9589a0bf528SMauro Carvalho Chehab 			break;
9599a0bf528SMauro Carvalho Chehab 	}
9609a0bf528SMauro Carvalho Chehab 	for (value = 0; value < 4; value++)
9619a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]);
9629a0bf528SMauro Carvalho Chehab 
9639a0bf528SMauro Carvalho Chehab 	// set power-up level: autosearch
9649a0bf528SMauro Carvalho Chehab 	dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD);
9659a0bf528SMauro Carvalho Chehab }
9669a0bf528SMauro Carvalho Chehab 
9679a0bf528SMauro Carvalho Chehab static int dib7000m_autosearch_start(struct dvb_frontend *demod)
9689a0bf528SMauro Carvalho Chehab {
9699a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
9709a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *state = demod->demodulator_priv;
9719a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties schan;
9729a0bf528SMauro Carvalho Chehab 	int ret = 0;
9739a0bf528SMauro Carvalho Chehab 	u32 value, factor;
9749a0bf528SMauro Carvalho Chehab 
9759a0bf528SMauro Carvalho Chehab 	schan = *ch;
9769a0bf528SMauro Carvalho Chehab 
9779a0bf528SMauro Carvalho Chehab 	schan.modulation = QAM_64;
9789a0bf528SMauro Carvalho Chehab 	schan.guard_interval        = GUARD_INTERVAL_1_32;
9799a0bf528SMauro Carvalho Chehab 	schan.transmission_mode         = TRANSMISSION_MODE_8K;
9809a0bf528SMauro Carvalho Chehab 	schan.code_rate_HP = FEC_2_3;
9819a0bf528SMauro Carvalho Chehab 	schan.code_rate_LP = FEC_3_4;
9829a0bf528SMauro Carvalho Chehab 	schan.hierarchy    = 0;
9839a0bf528SMauro Carvalho Chehab 
9849a0bf528SMauro Carvalho Chehab 	dib7000m_set_channel(state, &schan, 7);
9859a0bf528SMauro Carvalho Chehab 
9869a0bf528SMauro Carvalho Chehab 	factor = BANDWIDTH_TO_KHZ(schan.bandwidth_hz);
9879a0bf528SMauro Carvalho Chehab 	if (factor >= 5000)
9889a0bf528SMauro Carvalho Chehab 		factor = 1;
9899a0bf528SMauro Carvalho Chehab 	else
9909a0bf528SMauro Carvalho Chehab 		factor = 6;
9919a0bf528SMauro Carvalho Chehab 
9929a0bf528SMauro Carvalho Chehab 	// always use the setting for 8MHz here lock_time for 7,6 MHz are longer
9939a0bf528SMauro Carvalho Chehab 	value = 30 * state->internal_clk * factor;
9949a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 6,  (u16) ((value >> 16) & 0xffff)); // lock0 wait time
9959a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 7,  (u16)  (value        & 0xffff)); // lock0 wait time
9969a0bf528SMauro Carvalho Chehab 	value = 100 * state->internal_clk * factor;
9979a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 8,  (u16) ((value >> 16) & 0xffff)); // lock1 wait time
9989a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 9,  (u16)  (value        & 0xffff)); // lock1 wait time
9999a0bf528SMauro Carvalho Chehab 	value = 500 * state->internal_clk * factor;
10009a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
10019a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 11, (u16)  (value        & 0xffff)); // lock2 wait time
10029a0bf528SMauro Carvalho Chehab 
10039a0bf528SMauro Carvalho Chehab 	// start search
10049a0bf528SMauro Carvalho Chehab 	value = dib7000m_read_word(state, 0);
10059a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9)));
10069a0bf528SMauro Carvalho Chehab 
10079a0bf528SMauro Carvalho Chehab 	/* clear n_irq_pending */
10089a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x4000)
10099a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(state, 1793, 0);
10109a0bf528SMauro Carvalho Chehab 	else
10119a0bf528SMauro Carvalho Chehab 		dib7000m_read_word(state, 537);
10129a0bf528SMauro Carvalho Chehab 
10139a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 0, (u16) value);
10149a0bf528SMauro Carvalho Chehab 
10159a0bf528SMauro Carvalho Chehab 	return ret;
10169a0bf528SMauro Carvalho Chehab }
10179a0bf528SMauro Carvalho Chehab 
10189a0bf528SMauro Carvalho Chehab static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg)
10199a0bf528SMauro Carvalho Chehab {
10209a0bf528SMauro Carvalho Chehab 	u16 irq_pending = dib7000m_read_word(state, reg);
10219a0bf528SMauro Carvalho Chehab 
10229a0bf528SMauro Carvalho Chehab 	if (irq_pending & 0x1) { // failed
102375702277SMauro Carvalho Chehab 		dprintk("autosearch failed\n");
10249a0bf528SMauro Carvalho Chehab 		return 1;
10259a0bf528SMauro Carvalho Chehab 	}
10269a0bf528SMauro Carvalho Chehab 
10279a0bf528SMauro Carvalho Chehab 	if (irq_pending & 0x2) { // succeeded
102875702277SMauro Carvalho Chehab 		dprintk("autosearch succeeded\n");
10299a0bf528SMauro Carvalho Chehab 		return 2;
10309a0bf528SMauro Carvalho Chehab 	}
10319a0bf528SMauro Carvalho Chehab 	return 0; // still pending
10329a0bf528SMauro Carvalho Chehab }
10339a0bf528SMauro Carvalho Chehab 
10349a0bf528SMauro Carvalho Chehab static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod)
10359a0bf528SMauro Carvalho Chehab {
10369a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *state = demod->demodulator_priv;
10379a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x4000)
10389a0bf528SMauro Carvalho Chehab 		return dib7000m_autosearch_irq(state, 1793);
10399a0bf528SMauro Carvalho Chehab 	else
10409a0bf528SMauro Carvalho Chehab 		return dib7000m_autosearch_irq(state, 537);
10419a0bf528SMauro Carvalho Chehab }
10429a0bf528SMauro Carvalho Chehab 
10439a0bf528SMauro Carvalho Chehab static int dib7000m_tune(struct dvb_frontend *demod)
10449a0bf528SMauro Carvalho Chehab {
10459a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
10469a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *state = demod->demodulator_priv;
10479a0bf528SMauro Carvalho Chehab 	int ret = 0;
10489a0bf528SMauro Carvalho Chehab 	u16 value;
10499a0bf528SMauro Carvalho Chehab 
10509a0bf528SMauro Carvalho Chehab 	// we are already tuned - just resuming from suspend
10519a0bf528SMauro Carvalho Chehab 	dib7000m_set_channel(state, ch, 0);
10529a0bf528SMauro Carvalho Chehab 
10539a0bf528SMauro Carvalho Chehab 	// restart demod
10549a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 898, 0x4000);
10559a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 898, 0x0000);
10569a0bf528SMauro Carvalho Chehab 	msleep(45);
10579a0bf528SMauro Carvalho Chehab 
10589a0bf528SMauro Carvalho Chehab 	dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD);
10599a0bf528SMauro 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 */
10609a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
10619a0bf528SMauro Carvalho Chehab 
10629a0bf528SMauro Carvalho Chehab 	// never achieved a lock before - wait for timfreq to update
10639a0bf528SMauro Carvalho Chehab 	if (state->timf == 0)
10649a0bf528SMauro Carvalho Chehab 		msleep(200);
10659a0bf528SMauro Carvalho Chehab 
10669a0bf528SMauro Carvalho Chehab 	//dump_reg(state);
10679a0bf528SMauro Carvalho Chehab 	/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
10689a0bf528SMauro Carvalho Chehab 	value = (6 << 8) | 0x80;
10699a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
10709a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_2K: value |= (7 << 12); break;
10719a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_4K: value |= (8 << 12); break;
10729a0bf528SMauro Carvalho Chehab 		default:
10739a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_8K: value |= (9 << 12); break;
10749a0bf528SMauro Carvalho Chehab 	}
10759a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 26, value);
10769a0bf528SMauro Carvalho Chehab 
10779a0bf528SMauro Carvalho Chehab 	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
10789a0bf528SMauro Carvalho Chehab 	value = (0 << 4);
10799a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
10809a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_2K: value |= 0x6; break;
10819a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_4K: value |= 0x7; break;
10829a0bf528SMauro Carvalho Chehab 		default:
10839a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_8K: value |= 0x8; break;
10849a0bf528SMauro Carvalho Chehab 	}
10859a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 32, value);
10869a0bf528SMauro Carvalho Chehab 
10879a0bf528SMauro Carvalho Chehab 	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
10889a0bf528SMauro Carvalho Chehab 	value = (0 << 4);
10899a0bf528SMauro Carvalho Chehab 	switch (ch->transmission_mode) {
10909a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_2K: value |= 0x6; break;
10919a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_4K: value |= 0x7; break;
10929a0bf528SMauro Carvalho Chehab 		default:
10939a0bf528SMauro Carvalho Chehab 		case TRANSMISSION_MODE_8K: value |= 0x8; break;
10949a0bf528SMauro Carvalho Chehab 	}
10959a0bf528SMauro Carvalho Chehab 	ret |= dib7000m_write_word(state, 33,  value);
10969a0bf528SMauro Carvalho Chehab 
10979a0bf528SMauro Carvalho Chehab 	// we achieved a lock - it's time to update the timf freq
10989a0bf528SMauro Carvalho Chehab 	if ((dib7000m_read_word(state, 535) >> 6)  & 0x1)
10999a0bf528SMauro Carvalho Chehab 		dib7000m_update_timf(state);
11009a0bf528SMauro Carvalho Chehab 
11019a0bf528SMauro Carvalho Chehab 	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
11029a0bf528SMauro Carvalho Chehab 	return ret;
11039a0bf528SMauro Carvalho Chehab }
11049a0bf528SMauro Carvalho Chehab 
11059a0bf528SMauro Carvalho Chehab static int dib7000m_wakeup(struct dvb_frontend *demod)
11069a0bf528SMauro Carvalho Chehab {
11079a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *state = demod->demodulator_priv;
11089a0bf528SMauro Carvalho Chehab 
11099a0bf528SMauro Carvalho Chehab 	dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
11109a0bf528SMauro Carvalho Chehab 
11119a0bf528SMauro Carvalho Chehab 	if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
111275702277SMauro Carvalho Chehab 		dprintk("could not start Slow ADC\n");
11139a0bf528SMauro Carvalho Chehab 
11149a0bf528SMauro Carvalho Chehab 	return 0;
11159a0bf528SMauro Carvalho Chehab }
11169a0bf528SMauro Carvalho Chehab 
11179a0bf528SMauro Carvalho Chehab static int dib7000m_sleep(struct dvb_frontend *demod)
11189a0bf528SMauro Carvalho Chehab {
11199a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *st = demod->demodulator_priv;
11209a0bf528SMauro Carvalho Chehab 	dib7000m_set_output_mode(st, OUTMODE_HIGH_Z);
11219a0bf528SMauro Carvalho Chehab 	dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY);
11229a0bf528SMauro Carvalho Chehab 	return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) |
11239a0bf528SMauro Carvalho Chehab 		dib7000m_set_adc_state(st, DIBX000_ADC_OFF);
11249a0bf528SMauro Carvalho Chehab }
11259a0bf528SMauro Carvalho Chehab 
11269a0bf528SMauro Carvalho Chehab static int dib7000m_identify(struct dib7000m_state *state)
11279a0bf528SMauro Carvalho Chehab {
11289a0bf528SMauro Carvalho Chehab 	u16 value;
11299a0bf528SMauro Carvalho Chehab 
11309a0bf528SMauro Carvalho Chehab 	if ((value = dib7000m_read_word(state, 896)) != 0x01b3) {
113175702277SMauro Carvalho Chehab 		dprintk("wrong Vendor ID (0x%x)\n", value);
11329a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO;
11339a0bf528SMauro Carvalho Chehab 	}
11349a0bf528SMauro Carvalho Chehab 
11359a0bf528SMauro Carvalho Chehab 	state->revision = dib7000m_read_word(state, 897);
11369a0bf528SMauro Carvalho Chehab 	if (state->revision != 0x4000 &&
11379a0bf528SMauro Carvalho Chehab 		state->revision != 0x4001 &&
11389a0bf528SMauro Carvalho Chehab 		state->revision != 0x4002 &&
11399a0bf528SMauro Carvalho Chehab 		state->revision != 0x4003) {
114075702277SMauro Carvalho Chehab 		dprintk("wrong Device ID (0x%x)\n", value);
11419a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO;
11429a0bf528SMauro Carvalho Chehab 	}
11439a0bf528SMauro Carvalho Chehab 
11449a0bf528SMauro Carvalho Chehab 	/* protect this driver to be used with 7000PC */
11459a0bf528SMauro Carvalho Chehab 	if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) {
114675702277SMauro Carvalho Chehab 		dprintk("this driver does not work with DiB7000PC\n");
11479a0bf528SMauro Carvalho Chehab 		return -EREMOTEIO;
11489a0bf528SMauro Carvalho Chehab 	}
11499a0bf528SMauro Carvalho Chehab 
11509a0bf528SMauro Carvalho Chehab 	switch (state->revision) {
115175702277SMauro Carvalho Chehab 	case 0x4000: dprintk("found DiB7000MA/PA/MB/PB\n"); break;
115275702277SMauro Carvalho Chehab 	case 0x4001: state->reg_offs = 1; dprintk("found DiB7000HC\n"); break;
115375702277SMauro Carvalho Chehab 	case 0x4002: state->reg_offs = 1; dprintk("found DiB7000MC\n"); break;
115475702277SMauro Carvalho Chehab 	case 0x4003: state->reg_offs = 1; dprintk("found DiB9000\n"); break;
11559a0bf528SMauro Carvalho Chehab 	}
11569a0bf528SMauro Carvalho Chehab 
11579a0bf528SMauro Carvalho Chehab 	return 0;
11589a0bf528SMauro Carvalho Chehab }
11599a0bf528SMauro Carvalho Chehab 
11609a0bf528SMauro Carvalho Chehab 
11617e3e68bcSMauro Carvalho Chehab static int dib7000m_get_frontend(struct dvb_frontend* fe,
11627e3e68bcSMauro Carvalho Chehab 				 struct dtv_frontend_properties *fep)
11639a0bf528SMauro Carvalho Chehab {
11649a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *state = fe->demodulator_priv;
11659a0bf528SMauro Carvalho Chehab 	u16 tps = dib7000m_read_word(state,480);
11669a0bf528SMauro Carvalho Chehab 
11679a0bf528SMauro Carvalho Chehab 	fep->inversion = INVERSION_AUTO;
11689a0bf528SMauro Carvalho Chehab 
11699a0bf528SMauro Carvalho Chehab 	fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
11709a0bf528SMauro Carvalho Chehab 
11719a0bf528SMauro Carvalho Chehab 	switch ((tps >> 8) & 0x3) {
11729a0bf528SMauro Carvalho Chehab 		case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break;
11739a0bf528SMauro Carvalho Chehab 		case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break;
11749a0bf528SMauro Carvalho Chehab 		/* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
11759a0bf528SMauro Carvalho Chehab 	}
11769a0bf528SMauro Carvalho Chehab 
11779a0bf528SMauro Carvalho Chehab 	switch (tps & 0x3) {
11789a0bf528SMauro Carvalho Chehab 		case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break;
11799a0bf528SMauro Carvalho Chehab 		case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break;
11809a0bf528SMauro Carvalho Chehab 		case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break;
11819a0bf528SMauro Carvalho Chehab 		case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break;
11829a0bf528SMauro Carvalho Chehab 	}
11839a0bf528SMauro Carvalho Chehab 
11849a0bf528SMauro Carvalho Chehab 	switch ((tps >> 14) & 0x3) {
11859a0bf528SMauro Carvalho Chehab 		case 0: fep->modulation = QPSK; break;
11869a0bf528SMauro Carvalho Chehab 		case 1: fep->modulation = QAM_16; break;
11879a0bf528SMauro Carvalho Chehab 		case 2:
11889a0bf528SMauro Carvalho Chehab 		default: fep->modulation = QAM_64; break;
11899a0bf528SMauro Carvalho Chehab 	}
11909a0bf528SMauro Carvalho Chehab 
11919a0bf528SMauro Carvalho Chehab 	/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
11929a0bf528SMauro Carvalho Chehab 	/* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
11939a0bf528SMauro Carvalho Chehab 
11949a0bf528SMauro Carvalho Chehab 	fep->hierarchy = HIERARCHY_NONE;
11959a0bf528SMauro Carvalho Chehab 	switch ((tps >> 5) & 0x7) {
11969a0bf528SMauro Carvalho Chehab 		case 1: fep->code_rate_HP = FEC_1_2; break;
11979a0bf528SMauro Carvalho Chehab 		case 2: fep->code_rate_HP = FEC_2_3; break;
11989a0bf528SMauro Carvalho Chehab 		case 3: fep->code_rate_HP = FEC_3_4; break;
11999a0bf528SMauro Carvalho Chehab 		case 5: fep->code_rate_HP = FEC_5_6; break;
12009a0bf528SMauro Carvalho Chehab 		case 7:
12019a0bf528SMauro Carvalho Chehab 		default: fep->code_rate_HP = FEC_7_8; break;
12029a0bf528SMauro Carvalho Chehab 
12039a0bf528SMauro Carvalho Chehab 	}
12049a0bf528SMauro Carvalho Chehab 
12059a0bf528SMauro Carvalho Chehab 	switch ((tps >> 2) & 0x7) {
12069a0bf528SMauro Carvalho Chehab 		case 1: fep->code_rate_LP = FEC_1_2; break;
12079a0bf528SMauro Carvalho Chehab 		case 2: fep->code_rate_LP = FEC_2_3; break;
12089a0bf528SMauro Carvalho Chehab 		case 3: fep->code_rate_LP = FEC_3_4; break;
12099a0bf528SMauro Carvalho Chehab 		case 5: fep->code_rate_LP = FEC_5_6; break;
12109a0bf528SMauro Carvalho Chehab 		case 7:
12119a0bf528SMauro Carvalho Chehab 		default: fep->code_rate_LP = FEC_7_8; break;
12129a0bf528SMauro Carvalho Chehab 	}
12139a0bf528SMauro Carvalho Chehab 
12149a0bf528SMauro Carvalho Chehab 	/* native interleaver: (dib7000m_read_word(state, 481) >>  5) & 0x1 */
12159a0bf528SMauro Carvalho Chehab 
12169a0bf528SMauro Carvalho Chehab 	return 0;
12179a0bf528SMauro Carvalho Chehab }
12189a0bf528SMauro Carvalho Chehab 
12199a0bf528SMauro Carvalho Chehab static int dib7000m_set_frontend(struct dvb_frontend *fe)
12209a0bf528SMauro Carvalho Chehab {
12219a0bf528SMauro Carvalho Chehab 	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
12229a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *state = fe->demodulator_priv;
12239a0bf528SMauro Carvalho Chehab 	int time, ret;
12249a0bf528SMauro Carvalho Chehab 
12259a0bf528SMauro Carvalho Chehab 	dib7000m_set_output_mode(state, OUTMODE_HIGH_Z);
12269a0bf528SMauro Carvalho Chehab 
12279a0bf528SMauro Carvalho Chehab 	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz));
12289a0bf528SMauro Carvalho Chehab 
12299a0bf528SMauro Carvalho Chehab 	if (fe->ops.tuner_ops.set_params)
12309a0bf528SMauro Carvalho Chehab 		fe->ops.tuner_ops.set_params(fe);
12319a0bf528SMauro Carvalho Chehab 
12329a0bf528SMauro Carvalho Chehab 	/* start up the AGC */
12339a0bf528SMauro Carvalho Chehab 	state->agc_state = 0;
12349a0bf528SMauro Carvalho Chehab 	do {
12359a0bf528SMauro Carvalho Chehab 		time = dib7000m_agc_startup(fe);
12369a0bf528SMauro Carvalho Chehab 		if (time != -1)
12379a0bf528SMauro Carvalho Chehab 			msleep(time);
12389a0bf528SMauro Carvalho Chehab 	} while (time != -1);
12399a0bf528SMauro Carvalho Chehab 
12409a0bf528SMauro Carvalho Chehab 	if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
12419a0bf528SMauro Carvalho Chehab 		fep->guard_interval    == GUARD_INTERVAL_AUTO ||
12429a0bf528SMauro Carvalho Chehab 		fep->modulation        == QAM_AUTO ||
12439a0bf528SMauro Carvalho Chehab 		fep->code_rate_HP      == FEC_AUTO) {
12449a0bf528SMauro Carvalho Chehab 		int i = 800, found;
12459a0bf528SMauro Carvalho Chehab 
12469a0bf528SMauro Carvalho Chehab 		dib7000m_autosearch_start(fe);
12479a0bf528SMauro Carvalho Chehab 		do {
12489a0bf528SMauro Carvalho Chehab 			msleep(1);
12499a0bf528SMauro Carvalho Chehab 			found = dib7000m_autosearch_is_irq(fe);
12509a0bf528SMauro Carvalho Chehab 		} while (found == 0 && i--);
12519a0bf528SMauro Carvalho Chehab 
125275702277SMauro Carvalho Chehab 		dprintk("autosearch returns: %d\n", found);
12539a0bf528SMauro Carvalho Chehab 		if (found == 0 || found == 1)
12549a0bf528SMauro Carvalho Chehab 			return 0; // no channel found
12559a0bf528SMauro Carvalho Chehab 
12567e3e68bcSMauro Carvalho Chehab 		dib7000m_get_frontend(fe, fep);
12579a0bf528SMauro Carvalho Chehab 	}
12589a0bf528SMauro Carvalho Chehab 
12599a0bf528SMauro Carvalho Chehab 	ret = dib7000m_tune(fe);
12609a0bf528SMauro Carvalho Chehab 
12619a0bf528SMauro Carvalho Chehab 	/* make this a config parameter */
12629a0bf528SMauro Carvalho Chehab 	dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
12639a0bf528SMauro Carvalho Chehab 	return ret;
12649a0bf528SMauro Carvalho Chehab }
12659a0bf528SMauro Carvalho Chehab 
12660df289a2SMauro Carvalho Chehab static int dib7000m_read_status(struct dvb_frontend *fe, enum fe_status *stat)
12679a0bf528SMauro Carvalho Chehab {
12689a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *state = fe->demodulator_priv;
12699a0bf528SMauro Carvalho Chehab 	u16 lock = dib7000m_read_word(state, 535);
12709a0bf528SMauro Carvalho Chehab 
12719a0bf528SMauro Carvalho Chehab 	*stat = 0;
12729a0bf528SMauro Carvalho Chehab 
12739a0bf528SMauro Carvalho Chehab 	if (lock & 0x8000)
12749a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SIGNAL;
12759a0bf528SMauro Carvalho Chehab 	if (lock & 0x3000)
12769a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_CARRIER;
12779a0bf528SMauro Carvalho Chehab 	if (lock & 0x0100)
12789a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_VITERBI;
12799a0bf528SMauro Carvalho Chehab 	if (lock & 0x0010)
12809a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_SYNC;
12819a0bf528SMauro Carvalho Chehab 	if (lock & 0x0008)
12829a0bf528SMauro Carvalho Chehab 		*stat |= FE_HAS_LOCK;
12839a0bf528SMauro Carvalho Chehab 
12849a0bf528SMauro Carvalho Chehab 	return 0;
12859a0bf528SMauro Carvalho Chehab }
12869a0bf528SMauro Carvalho Chehab 
12879a0bf528SMauro Carvalho Chehab static int dib7000m_read_ber(struct dvb_frontend *fe, u32 *ber)
12889a0bf528SMauro Carvalho Chehab {
12899a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *state = fe->demodulator_priv;
12909a0bf528SMauro Carvalho Chehab 	*ber = (dib7000m_read_word(state, 526) << 16) | dib7000m_read_word(state, 527);
12919a0bf528SMauro Carvalho Chehab 	return 0;
12929a0bf528SMauro Carvalho Chehab }
12939a0bf528SMauro Carvalho Chehab 
12949a0bf528SMauro Carvalho Chehab static int dib7000m_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
12959a0bf528SMauro Carvalho Chehab {
12969a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *state = fe->demodulator_priv;
12979a0bf528SMauro Carvalho Chehab 	*unc = dib7000m_read_word(state, 534);
12989a0bf528SMauro Carvalho Chehab 	return 0;
12999a0bf528SMauro Carvalho Chehab }
13009a0bf528SMauro Carvalho Chehab 
13019a0bf528SMauro Carvalho Chehab static int dib7000m_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
13029a0bf528SMauro Carvalho Chehab {
13039a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *state = fe->demodulator_priv;
13049a0bf528SMauro Carvalho Chehab 	u16 val = dib7000m_read_word(state, 390);
13059a0bf528SMauro Carvalho Chehab 	*strength = 65535 - val;
13069a0bf528SMauro Carvalho Chehab 	return 0;
13079a0bf528SMauro Carvalho Chehab }
13089a0bf528SMauro Carvalho Chehab 
13099a0bf528SMauro Carvalho Chehab static int dib7000m_read_snr(struct dvb_frontend* fe, u16 *snr)
13109a0bf528SMauro Carvalho Chehab {
13119a0bf528SMauro Carvalho Chehab 	*snr = 0x0000;
13129a0bf528SMauro Carvalho Chehab 	return 0;
13139a0bf528SMauro Carvalho Chehab }
13149a0bf528SMauro Carvalho Chehab 
13159a0bf528SMauro Carvalho Chehab static int dib7000m_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
13169a0bf528SMauro Carvalho Chehab {
13179a0bf528SMauro Carvalho Chehab 	tune->min_delay_ms = 1000;
13189a0bf528SMauro Carvalho Chehab 	return 0;
13199a0bf528SMauro Carvalho Chehab }
13209a0bf528SMauro Carvalho Chehab 
13219a0bf528SMauro Carvalho Chehab static void dib7000m_release(struct dvb_frontend *demod)
13229a0bf528SMauro Carvalho Chehab {
13239a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *st = demod->demodulator_priv;
13249a0bf528SMauro Carvalho Chehab 	dibx000_exit_i2c_master(&st->i2c_master);
13259a0bf528SMauro Carvalho Chehab 	kfree(st);
13269a0bf528SMauro Carvalho Chehab }
13279a0bf528SMauro Carvalho Chehab 
13289a0bf528SMauro Carvalho Chehab struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
13299a0bf528SMauro Carvalho Chehab {
13309a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *st = demod->demodulator_priv;
13319a0bf528SMauro Carvalho Chehab 	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
13329a0bf528SMauro Carvalho Chehab }
13339a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib7000m_get_i2c_master);
13349a0bf528SMauro Carvalho Chehab 
13359a0bf528SMauro Carvalho Chehab int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
13369a0bf528SMauro Carvalho Chehab {
13379a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *state = fe->demodulator_priv;
13389a0bf528SMauro Carvalho Chehab 	u16 val = dib7000m_read_word(state, 294 + state->reg_offs) & 0xffef;
13399a0bf528SMauro Carvalho Chehab 	val |= (onoff & 0x1) << 4;
134075702277SMauro Carvalho Chehab 	dprintk("PID filter enabled %d\n", onoff);
13419a0bf528SMauro Carvalho Chehab 	return dib7000m_write_word(state, 294 + state->reg_offs, val);
13429a0bf528SMauro Carvalho Chehab }
13439a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib7000m_pid_filter_ctrl);
13449a0bf528SMauro Carvalho Chehab 
13459a0bf528SMauro Carvalho Chehab int dib7000m_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
13469a0bf528SMauro Carvalho Chehab {
13479a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *state = fe->demodulator_priv;
134875702277SMauro Carvalho Chehab 	dprintk("PID filter: index %x, PID %d, OnOff %d\n", id, pid, onoff);
13499a0bf528SMauro Carvalho Chehab 	return dib7000m_write_word(state, 300 + state->reg_offs + id,
13509a0bf528SMauro Carvalho Chehab 			onoff ? (1 << 13) | pid : 0);
13519a0bf528SMauro Carvalho Chehab }
13529a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib7000m_pid_filter);
13539a0bf528SMauro Carvalho Chehab 
13549a0bf528SMauro Carvalho Chehab #if 0
13559a0bf528SMauro Carvalho Chehab /* used with some prototype boards */
13569a0bf528SMauro Carvalho Chehab int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods,
13579a0bf528SMauro Carvalho Chehab 		u8 default_addr, struct dib7000m_config cfg[])
13589a0bf528SMauro Carvalho Chehab {
13599a0bf528SMauro Carvalho Chehab 	struct dib7000m_state st = { .i2c_adap = i2c };
13609a0bf528SMauro Carvalho Chehab 	int k = 0;
13619a0bf528SMauro Carvalho Chehab 	u8 new_addr = 0;
13629a0bf528SMauro Carvalho Chehab 
13639a0bf528SMauro Carvalho Chehab 	for (k = no_of_demods-1; k >= 0; k--) {
13649a0bf528SMauro Carvalho Chehab 		st.cfg = cfg[k];
13659a0bf528SMauro Carvalho Chehab 
13669a0bf528SMauro Carvalho Chehab 		/* designated i2c address */
13679a0bf528SMauro Carvalho Chehab 		new_addr          = (0x40 + k) << 1;
13689a0bf528SMauro Carvalho Chehab 		st.i2c_addr = new_addr;
13699a0bf528SMauro Carvalho Chehab 		if (dib7000m_identify(&st) != 0) {
13709a0bf528SMauro Carvalho Chehab 			st.i2c_addr = default_addr;
13719a0bf528SMauro Carvalho Chehab 			if (dib7000m_identify(&st) != 0) {
137275702277SMauro Carvalho Chehab 				dprintk("DiB7000M #%d: not identified\n", k);
13739a0bf528SMauro Carvalho Chehab 				return -EIO;
13749a0bf528SMauro Carvalho Chehab 			}
13759a0bf528SMauro Carvalho Chehab 		}
13769a0bf528SMauro Carvalho Chehab 
13779a0bf528SMauro Carvalho Chehab 		/* start diversity to pull_down div_str - just for i2c-enumeration */
13789a0bf528SMauro Carvalho Chehab 		dib7000m_set_output_mode(&st, OUTMODE_DIVERSITY);
13799a0bf528SMauro Carvalho Chehab 
13809a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(&st, 1796, 0x0); // select DVB-T output
13819a0bf528SMauro Carvalho Chehab 
13829a0bf528SMauro Carvalho Chehab 		/* set new i2c address and force divstart */
13839a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2);
13849a0bf528SMauro Carvalho Chehab 
138575702277SMauro Carvalho Chehab 		dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
13869a0bf528SMauro Carvalho Chehab 	}
13879a0bf528SMauro Carvalho Chehab 
13889a0bf528SMauro Carvalho Chehab 	for (k = 0; k < no_of_demods; k++) {
13899a0bf528SMauro Carvalho Chehab 		st.cfg = cfg[k];
13909a0bf528SMauro Carvalho Chehab 		st.i2c_addr = (0x40 + k) << 1;
13919a0bf528SMauro Carvalho Chehab 
13929a0bf528SMauro Carvalho Chehab 		// unforce divstr
13939a0bf528SMauro Carvalho Chehab 		dib7000m_write_word(&st,1794, st.i2c_addr << 2);
13949a0bf528SMauro Carvalho Chehab 
13959a0bf528SMauro Carvalho Chehab 		/* deactivate div - it was just for i2c-enumeration */
13969a0bf528SMauro Carvalho Chehab 		dib7000m_set_output_mode(&st, OUTMODE_HIGH_Z);
13979a0bf528SMauro Carvalho Chehab 	}
13989a0bf528SMauro Carvalho Chehab 
13999a0bf528SMauro Carvalho Chehab 	return 0;
14009a0bf528SMauro Carvalho Chehab }
14019a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib7000m_i2c_enumeration);
14029a0bf528SMauro Carvalho Chehab #endif
14039a0bf528SMauro Carvalho Chehab 
1404bd336e63SMax Kellermann static const struct dvb_frontend_ops dib7000m_ops;
14059a0bf528SMauro Carvalho Chehab struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg)
14069a0bf528SMauro Carvalho Chehab {
14079a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *demod;
14089a0bf528SMauro Carvalho Chehab 	struct dib7000m_state *st;
14099a0bf528SMauro Carvalho Chehab 	st = kzalloc(sizeof(struct dib7000m_state), GFP_KERNEL);
14109a0bf528SMauro Carvalho Chehab 	if (st == NULL)
14119a0bf528SMauro Carvalho Chehab 		return NULL;
14129a0bf528SMauro Carvalho Chehab 
14139a0bf528SMauro Carvalho Chehab 	memcpy(&st->cfg, cfg, sizeof(struct dib7000m_config));
14149a0bf528SMauro Carvalho Chehab 	st->i2c_adap = i2c_adap;
14159a0bf528SMauro Carvalho Chehab 	st->i2c_addr = i2c_addr;
14169a0bf528SMauro Carvalho Chehab 
14179a0bf528SMauro Carvalho Chehab 	demod                   = &st->demod;
14189a0bf528SMauro Carvalho Chehab 	demod->demodulator_priv = st;
14199a0bf528SMauro Carvalho Chehab 	memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
14209a0bf528SMauro Carvalho Chehab 	mutex_init(&st->i2c_buffer_lock);
14219a0bf528SMauro Carvalho Chehab 
14229a0bf528SMauro Carvalho Chehab 	st->timf_default = cfg->bw->timf;
14239a0bf528SMauro Carvalho Chehab 
14249a0bf528SMauro Carvalho Chehab 	if (dib7000m_identify(st) != 0)
14259a0bf528SMauro Carvalho Chehab 		goto error;
14269a0bf528SMauro Carvalho Chehab 
14279a0bf528SMauro Carvalho Chehab 	if (st->revision == 0x4000)
14289a0bf528SMauro Carvalho Chehab 		dibx000_init_i2c_master(&st->i2c_master, DIB7000, st->i2c_adap, st->i2c_addr);
14299a0bf528SMauro Carvalho Chehab 	else
14309a0bf528SMauro Carvalho Chehab 		dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c_adap, st->i2c_addr);
14319a0bf528SMauro Carvalho Chehab 
14329a0bf528SMauro Carvalho Chehab 	dib7000m_demod_reset(st);
14339a0bf528SMauro Carvalho Chehab 
14349a0bf528SMauro Carvalho Chehab 	return demod;
14359a0bf528SMauro Carvalho Chehab 
14369a0bf528SMauro Carvalho Chehab error:
14379a0bf528SMauro Carvalho Chehab 	kfree(st);
14389a0bf528SMauro Carvalho Chehab 	return NULL;
14399a0bf528SMauro Carvalho Chehab }
14409a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib7000m_attach);
14419a0bf528SMauro Carvalho Chehab 
1442bd336e63SMax Kellermann static const struct dvb_frontend_ops dib7000m_ops = {
14439a0bf528SMauro Carvalho Chehab 	.delsys = { SYS_DVBT },
14449a0bf528SMauro Carvalho Chehab 	.info = {
14459a0bf528SMauro Carvalho Chehab 		.name = "DiBcom 7000MA/MB/PA/PB/MC",
1446f1b1eabfSMauro Carvalho Chehab 		.frequency_min_hz      =  44250 * kHz,
1447f1b1eabfSMauro Carvalho Chehab 		.frequency_max_hz      = 867250 * kHz,
1448f1b1eabfSMauro Carvalho Chehab 		.frequency_stepsize_hz = 62500,
14499a0bf528SMauro Carvalho Chehab 		.caps = FE_CAN_INVERSION_AUTO |
14509a0bf528SMauro Carvalho Chehab 			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
14519a0bf528SMauro Carvalho Chehab 			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
14529a0bf528SMauro Carvalho Chehab 			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
14539a0bf528SMauro Carvalho Chehab 			FE_CAN_TRANSMISSION_MODE_AUTO |
14549a0bf528SMauro Carvalho Chehab 			FE_CAN_GUARD_INTERVAL_AUTO |
14559a0bf528SMauro Carvalho Chehab 			FE_CAN_RECOVER |
14569a0bf528SMauro Carvalho Chehab 			FE_CAN_HIERARCHY_AUTO,
14579a0bf528SMauro Carvalho Chehab 	},
14589a0bf528SMauro Carvalho Chehab 
14599a0bf528SMauro Carvalho Chehab 	.release              = dib7000m_release,
14609a0bf528SMauro Carvalho Chehab 
14619a0bf528SMauro Carvalho Chehab 	.init                 = dib7000m_wakeup,
14629a0bf528SMauro Carvalho Chehab 	.sleep                = dib7000m_sleep,
14639a0bf528SMauro Carvalho Chehab 
14649a0bf528SMauro Carvalho Chehab 	.set_frontend         = dib7000m_set_frontend,
14659a0bf528SMauro Carvalho Chehab 	.get_tune_settings    = dib7000m_fe_get_tune_settings,
14669a0bf528SMauro Carvalho Chehab 	.get_frontend         = dib7000m_get_frontend,
14679a0bf528SMauro Carvalho Chehab 
14689a0bf528SMauro Carvalho Chehab 	.read_status          = dib7000m_read_status,
14699a0bf528SMauro Carvalho Chehab 	.read_ber             = dib7000m_read_ber,
14709a0bf528SMauro Carvalho Chehab 	.read_signal_strength = dib7000m_read_signal_strength,
14719a0bf528SMauro Carvalho Chehab 	.read_snr             = dib7000m_read_snr,
14729a0bf528SMauro Carvalho Chehab 	.read_ucblocks        = dib7000m_read_unc_blocks,
14739a0bf528SMauro Carvalho Chehab };
14749a0bf528SMauro Carvalho Chehab 
147599e44da7SPatrick Boettcher MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
14769a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 7000MA/MB/PA/PB/MC COFDM demodulator");
14779a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
1478