1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29a0bf528SMauro Carvalho Chehab /*
39a0bf528SMauro Carvalho Chehab  * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner.
49a0bf528SMauro Carvalho Chehab  *
59a0bf528SMauro Carvalho Chehab  * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/)
69a0bf528SMauro Carvalho Chehab  *
79a0bf528SMauro Carvalho Chehab  * This code is more or less generated from another driver, please
89a0bf528SMauro Carvalho Chehab  * excuse some codingstyle oddities.
99a0bf528SMauro Carvalho Chehab  */
109a0bf528SMauro Carvalho Chehab 
114bd1a8ddSMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
124bd1a8ddSMauro Carvalho Chehab 
139a0bf528SMauro Carvalho Chehab #include <linux/kernel.h>
149a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
159a0bf528SMauro Carvalho Chehab #include <linux/i2c.h>
169a0bf528SMauro Carvalho Chehab #include <linux/mutex.h>
179a0bf528SMauro Carvalho Chehab 
18fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
199a0bf528SMauro Carvalho Chehab 
209a0bf528SMauro Carvalho Chehab #include "dib0090.h"
219a0bf528SMauro Carvalho Chehab #include "dibx000_common.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 
274bd1a8ddSMauro Carvalho Chehab #define dprintk(fmt, arg...) do {					\
284bd1a8ddSMauro Carvalho Chehab 	if (debug)							\
294bd1a8ddSMauro Carvalho Chehab 		printk(KERN_DEBUG pr_fmt("%s: " fmt),			\
304bd1a8ddSMauro Carvalho Chehab 		       __func__, ##arg);				\
319a0bf528SMauro Carvalho Chehab } while (0)
329a0bf528SMauro Carvalho Chehab 
339a0bf528SMauro Carvalho Chehab #define CONFIG_SYS_DVBT
349a0bf528SMauro Carvalho Chehab #define CONFIG_SYS_ISDBT
359a0bf528SMauro Carvalho Chehab #define CONFIG_BAND_CBAND
369a0bf528SMauro Carvalho Chehab #define CONFIG_BAND_VHF
379a0bf528SMauro Carvalho Chehab #define CONFIG_BAND_UHF
389a0bf528SMauro Carvalho Chehab #define CONFIG_DIB0090_USE_PWM_AGC
399a0bf528SMauro Carvalho Chehab 
409a0bf528SMauro Carvalho Chehab #define EN_LNA0      0x8000
419a0bf528SMauro Carvalho Chehab #define EN_LNA1      0x4000
429a0bf528SMauro Carvalho Chehab #define EN_LNA2      0x2000
439a0bf528SMauro Carvalho Chehab #define EN_LNA3      0x1000
449a0bf528SMauro Carvalho Chehab #define EN_MIX0      0x0800
459a0bf528SMauro Carvalho Chehab #define EN_MIX1      0x0400
469a0bf528SMauro Carvalho Chehab #define EN_MIX2      0x0200
479a0bf528SMauro Carvalho Chehab #define EN_MIX3      0x0100
489a0bf528SMauro Carvalho Chehab #define EN_IQADC     0x0040
499a0bf528SMauro Carvalho Chehab #define EN_PLL       0x0020
509a0bf528SMauro Carvalho Chehab #define EN_TX        0x0010
519a0bf528SMauro Carvalho Chehab #define EN_BB        0x0008
529a0bf528SMauro Carvalho Chehab #define EN_LO        0x0004
539a0bf528SMauro Carvalho Chehab #define EN_BIAS      0x0001
549a0bf528SMauro Carvalho Chehab 
559a0bf528SMauro Carvalho Chehab #define EN_IQANA     0x0002
569a0bf528SMauro Carvalho Chehab #define EN_DIGCLK    0x0080	/* not in the 0x24 reg, only in 0x1b */
579a0bf528SMauro Carvalho Chehab #define EN_CRYSTAL   0x0002
589a0bf528SMauro Carvalho Chehab 
599a0bf528SMauro Carvalho Chehab #define EN_UHF		 0x22E9
609a0bf528SMauro Carvalho Chehab #define EN_VHF		 0x44E9
619a0bf528SMauro Carvalho Chehab #define EN_LBD		 0x11E9
629a0bf528SMauro Carvalho Chehab #define EN_SBD		 0x44E9
639a0bf528SMauro Carvalho Chehab #define EN_CAB		 0x88E9
649a0bf528SMauro Carvalho Chehab 
659a0bf528SMauro Carvalho Chehab /* Calibration defines */
669a0bf528SMauro Carvalho Chehab #define      DC_CAL 0x1
679a0bf528SMauro Carvalho Chehab #define     WBD_CAL 0x2
689a0bf528SMauro Carvalho Chehab #define    TEMP_CAL 0x4
699a0bf528SMauro Carvalho Chehab #define CAPTRIM_CAL 0x8
709a0bf528SMauro Carvalho Chehab 
719a0bf528SMauro Carvalho Chehab #define KROSUS_PLL_LOCKED   0x800
729a0bf528SMauro Carvalho Chehab #define KROSUS              0x2
739a0bf528SMauro Carvalho Chehab 
749a0bf528SMauro Carvalho Chehab /* Use those defines to identify SOC version */
759a0bf528SMauro Carvalho Chehab #define SOC               0x02
769a0bf528SMauro Carvalho Chehab #define SOC_7090_P1G_11R1 0x82
779a0bf528SMauro Carvalho Chehab #define SOC_7090_P1G_21R1 0x8a
789a0bf528SMauro Carvalho Chehab #define SOC_8090_P1G_11R1 0x86
799a0bf528SMauro Carvalho Chehab #define SOC_8090_P1G_21R1 0x8e
809a0bf528SMauro Carvalho Chehab 
819a0bf528SMauro Carvalho Chehab /* else use thos ones to check */
829a0bf528SMauro Carvalho Chehab #define P1A_B      0x0
839a0bf528SMauro Carvalho Chehab #define P1C	   0x1
849a0bf528SMauro Carvalho Chehab #define P1D_E_F    0x3
859a0bf528SMauro Carvalho Chehab #define P1G	   0x7
869a0bf528SMauro Carvalho Chehab #define P1G_21R2   0xf
879a0bf528SMauro Carvalho Chehab 
889a0bf528SMauro Carvalho Chehab #define MP001 0x1		/* Single 9090/8096 */
899a0bf528SMauro Carvalho Chehab #define MP005 0x4		/* Single Sband */
909a0bf528SMauro Carvalho Chehab #define MP008 0x6		/* Dual diversity VHF-UHF-LBAND */
919a0bf528SMauro Carvalho Chehab #define MP009 0x7		/* Dual diversity 29098 CBAND-UHF-LBAND-SBAND */
929a0bf528SMauro Carvalho Chehab 
939a0bf528SMauro Carvalho Chehab #define pgm_read_word(w) (*w)
949a0bf528SMauro Carvalho Chehab 
959a0bf528SMauro Carvalho Chehab struct dc_calibration;
969a0bf528SMauro Carvalho Chehab 
979a0bf528SMauro Carvalho Chehab struct dib0090_tuning {
989a0bf528SMauro Carvalho Chehab 	u32 max_freq;		/* for every frequency less than or equal to that field: this information is correct */
999a0bf528SMauro Carvalho Chehab 	u8 switch_trim;
1009a0bf528SMauro Carvalho Chehab 	u8 lna_tune;
1019a0bf528SMauro Carvalho Chehab 	u16 lna_bias;
1029a0bf528SMauro Carvalho Chehab 	u16 v2i;
1039a0bf528SMauro Carvalho Chehab 	u16 mix;
1049a0bf528SMauro Carvalho Chehab 	u16 load;
1059a0bf528SMauro Carvalho Chehab 	u16 tuner_enable;
1069a0bf528SMauro Carvalho Chehab };
1079a0bf528SMauro Carvalho Chehab 
1089a0bf528SMauro Carvalho Chehab struct dib0090_pll {
1099a0bf528SMauro Carvalho Chehab 	u32 max_freq;		/* for every frequency less than or equal to that field: this information is correct */
1109a0bf528SMauro Carvalho Chehab 	u8 vco_band;
1119a0bf528SMauro Carvalho Chehab 	u8 hfdiv_code;
1129a0bf528SMauro Carvalho Chehab 	u8 hfdiv;
1139a0bf528SMauro Carvalho Chehab 	u8 topresc;
1149a0bf528SMauro Carvalho Chehab };
1159a0bf528SMauro Carvalho Chehab 
1169a0bf528SMauro Carvalho Chehab struct dib0090_identity {
1179a0bf528SMauro Carvalho Chehab 	u8 version;
1189a0bf528SMauro Carvalho Chehab 	u8 product;
1199a0bf528SMauro Carvalho Chehab 	u8 p1g;
1209a0bf528SMauro Carvalho Chehab 	u8 in_soc;
1219a0bf528SMauro Carvalho Chehab };
1229a0bf528SMauro Carvalho Chehab 
1239a0bf528SMauro Carvalho Chehab struct dib0090_state {
1249a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *i2c;
1259a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *fe;
1269a0bf528SMauro Carvalho Chehab 	const struct dib0090_config *config;
1279a0bf528SMauro Carvalho Chehab 
1289a0bf528SMauro Carvalho Chehab 	u8 current_band;
1299a0bf528SMauro Carvalho Chehab 	enum frontend_tune_state tune_state;
1309a0bf528SMauro Carvalho Chehab 	u32 current_rf;
1319a0bf528SMauro Carvalho Chehab 
1329a0bf528SMauro Carvalho Chehab 	u16 wbd_offset;
1339a0bf528SMauro Carvalho Chehab 	s16 wbd_target;		/* in dB */
1349a0bf528SMauro Carvalho Chehab 
1359a0bf528SMauro Carvalho Chehab 	s16 rf_gain_limit;	/* take-over-point: where to split between bb and rf gain */
1369a0bf528SMauro Carvalho Chehab 	s16 current_gain;	/* keeps the currently programmed gain */
1379a0bf528SMauro Carvalho Chehab 	u8 agc_step;		/* new binary search */
1389a0bf528SMauro Carvalho Chehab 
1399a0bf528SMauro Carvalho Chehab 	u16 gain[2];		/* for channel monitoring */
1409a0bf528SMauro Carvalho Chehab 
1419a0bf528SMauro Carvalho Chehab 	const u16 *rf_ramp;
1429a0bf528SMauro Carvalho Chehab 	const u16 *bb_ramp;
1439a0bf528SMauro Carvalho Chehab 
1449a0bf528SMauro Carvalho Chehab 	/* for the software AGC ramps */
1459a0bf528SMauro Carvalho Chehab 	u16 bb_1_def;
1469a0bf528SMauro Carvalho Chehab 	u16 rf_lt_def;
1479a0bf528SMauro Carvalho Chehab 	u16 gain_reg[4];
1489a0bf528SMauro Carvalho Chehab 
1499a0bf528SMauro Carvalho Chehab 	/* for the captrim/dc-offset search */
1509a0bf528SMauro Carvalho Chehab 	s8 step;
1519a0bf528SMauro Carvalho Chehab 	s16 adc_diff;
1529a0bf528SMauro Carvalho Chehab 	s16 min_adc_diff;
1539a0bf528SMauro Carvalho Chehab 
1549a0bf528SMauro Carvalho Chehab 	s8 captrim;
1559a0bf528SMauro Carvalho Chehab 	s8 fcaptrim;
1569a0bf528SMauro Carvalho Chehab 
1579a0bf528SMauro Carvalho Chehab 	const struct dc_calibration *dc;
1589a0bf528SMauro Carvalho Chehab 	u16 bb6, bb7;
1599a0bf528SMauro Carvalho Chehab 
1609a0bf528SMauro Carvalho Chehab 	const struct dib0090_tuning *current_tune_table_index;
1619a0bf528SMauro Carvalho Chehab 	const struct dib0090_pll *current_pll_table_index;
1629a0bf528SMauro Carvalho Chehab 
1639a0bf528SMauro Carvalho Chehab 	u8 tuner_is_tuned;
1649a0bf528SMauro Carvalho Chehab 	u8 agc_freeze;
1659a0bf528SMauro Carvalho Chehab 
1669a0bf528SMauro Carvalho Chehab 	struct dib0090_identity identity;
1679a0bf528SMauro Carvalho Chehab 
1689a0bf528SMauro Carvalho Chehab 	u32 rf_request;
1699a0bf528SMauro Carvalho Chehab 	u8 current_standard;
1709a0bf528SMauro Carvalho Chehab 
1719a0bf528SMauro Carvalho Chehab 	u8 calibrate;
1729a0bf528SMauro Carvalho Chehab 	u32 rest;
1739a0bf528SMauro Carvalho Chehab 	u16 bias;
1749a0bf528SMauro Carvalho Chehab 	s16 temperature;
1759a0bf528SMauro Carvalho Chehab 
1769a0bf528SMauro Carvalho Chehab 	u8 wbd_calibration_gain;
1779a0bf528SMauro Carvalho Chehab 	const struct dib0090_wbd_slope *current_wbd_table;
1789a0bf528SMauro Carvalho Chehab 	u16 wbdmux;
1799a0bf528SMauro Carvalho Chehab 
1809a0bf528SMauro Carvalho Chehab 	/* for the I2C transfer */
1819a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg[2];
1829a0bf528SMauro Carvalho Chehab 	u8 i2c_write_buffer[3];
1839a0bf528SMauro Carvalho Chehab 	u8 i2c_read_buffer[2];
1849a0bf528SMauro Carvalho Chehab 	struct mutex i2c_buffer_lock;
1859a0bf528SMauro Carvalho Chehab };
1869a0bf528SMauro Carvalho Chehab 
1879a0bf528SMauro Carvalho Chehab struct dib0090_fw_state {
1889a0bf528SMauro Carvalho Chehab 	struct i2c_adapter *i2c;
1899a0bf528SMauro Carvalho Chehab 	struct dvb_frontend *fe;
1909a0bf528SMauro Carvalho Chehab 	struct dib0090_identity identity;
1919a0bf528SMauro Carvalho Chehab 	const struct dib0090_config *config;
1929a0bf528SMauro Carvalho Chehab 
1939a0bf528SMauro Carvalho Chehab 	/* for the I2C transfer */
1949a0bf528SMauro Carvalho Chehab 	struct i2c_msg msg;
1959a0bf528SMauro Carvalho Chehab 	u8 i2c_write_buffer[2];
1969a0bf528SMauro Carvalho Chehab 	u8 i2c_read_buffer[2];
1979a0bf528SMauro Carvalho Chehab 	struct mutex i2c_buffer_lock;
1989a0bf528SMauro Carvalho Chehab };
1999a0bf528SMauro Carvalho Chehab 
dib0090_read_reg(struct dib0090_state * state,u8 reg)2009a0bf528SMauro Carvalho Chehab static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
2019a0bf528SMauro Carvalho Chehab {
2029a0bf528SMauro Carvalho Chehab 	u16 ret;
2039a0bf528SMauro Carvalho Chehab 
2049a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2054bd1a8ddSMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
2069a0bf528SMauro Carvalho Chehab 		return 0;
2079a0bf528SMauro Carvalho Chehab 	}
2089a0bf528SMauro Carvalho Chehab 
2099a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = reg;
2109a0bf528SMauro Carvalho Chehab 
2119a0bf528SMauro Carvalho Chehab 	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
2129a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->config->i2c_address;
2139a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
2149a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
2159a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 1;
2169a0bf528SMauro Carvalho Chehab 	state->msg[1].addr = state->config->i2c_address;
2179a0bf528SMauro Carvalho Chehab 	state->msg[1].flags = I2C_M_RD;
2189a0bf528SMauro Carvalho Chehab 	state->msg[1].buf = state->i2c_read_buffer;
2199a0bf528SMauro Carvalho Chehab 	state->msg[1].len = 2;
2209a0bf528SMauro Carvalho Chehab 
2219a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
2224bd1a8ddSMauro Carvalho Chehab 		pr_warn("DiB0090 I2C read failed\n");
2239a0bf528SMauro Carvalho Chehab 		ret = 0;
2249a0bf528SMauro Carvalho Chehab 	} else
2259a0bf528SMauro Carvalho Chehab 		ret = (state->i2c_read_buffer[0] << 8)
2269a0bf528SMauro Carvalho Chehab 			| state->i2c_read_buffer[1];
2279a0bf528SMauro Carvalho Chehab 
2289a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
2299a0bf528SMauro Carvalho Chehab 	return ret;
2309a0bf528SMauro Carvalho Chehab }
2319a0bf528SMauro Carvalho Chehab 
dib0090_write_reg(struct dib0090_state * state,u32 reg,u16 val)2329a0bf528SMauro Carvalho Chehab static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
2339a0bf528SMauro Carvalho Chehab {
2349a0bf528SMauro Carvalho Chehab 	int ret;
2359a0bf528SMauro Carvalho Chehab 
2369a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2374bd1a8ddSMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
2389a0bf528SMauro Carvalho Chehab 		return -EINVAL;
2399a0bf528SMauro Carvalho Chehab 	}
2409a0bf528SMauro Carvalho Chehab 
2419a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = reg & 0xff;
2429a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = val >> 8;
2439a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[2] = val & 0xff;
2449a0bf528SMauro Carvalho Chehab 
2459a0bf528SMauro Carvalho Chehab 	memset(state->msg, 0, sizeof(struct i2c_msg));
2469a0bf528SMauro Carvalho Chehab 	state->msg[0].addr = state->config->i2c_address;
2479a0bf528SMauro Carvalho Chehab 	state->msg[0].flags = 0;
2489a0bf528SMauro Carvalho Chehab 	state->msg[0].buf = state->i2c_write_buffer;
2499a0bf528SMauro Carvalho Chehab 	state->msg[0].len = 3;
2509a0bf528SMauro Carvalho Chehab 
2519a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
2524bd1a8ddSMauro Carvalho Chehab 		pr_warn("DiB0090 I2C write failed\n");
2539a0bf528SMauro Carvalho Chehab 		ret = -EREMOTEIO;
2549a0bf528SMauro Carvalho Chehab 	} else
2559a0bf528SMauro Carvalho Chehab 		ret = 0;
2569a0bf528SMauro Carvalho Chehab 
2579a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
2589a0bf528SMauro Carvalho Chehab 	return ret;
2599a0bf528SMauro Carvalho Chehab }
2609a0bf528SMauro Carvalho Chehab 
dib0090_fw_read_reg(struct dib0090_fw_state * state,u8 reg)2619a0bf528SMauro Carvalho Chehab static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
2629a0bf528SMauro Carvalho Chehab {
2639a0bf528SMauro Carvalho Chehab 	u16 ret;
2649a0bf528SMauro Carvalho Chehab 
2659a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2664bd1a8ddSMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
2679a0bf528SMauro Carvalho Chehab 		return 0;
2689a0bf528SMauro Carvalho Chehab 	}
2699a0bf528SMauro Carvalho Chehab 
2709a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = reg;
2719a0bf528SMauro Carvalho Chehab 
2729a0bf528SMauro Carvalho Chehab 	memset(&state->msg, 0, sizeof(struct i2c_msg));
2739a0bf528SMauro Carvalho Chehab 	state->msg.addr = reg;
2749a0bf528SMauro Carvalho Chehab 	state->msg.flags = I2C_M_RD;
2759a0bf528SMauro Carvalho Chehab 	state->msg.buf = state->i2c_read_buffer;
2769a0bf528SMauro Carvalho Chehab 	state->msg.len = 2;
2779a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
2784bd1a8ddSMauro Carvalho Chehab 		pr_warn("DiB0090 I2C read failed\n");
2799a0bf528SMauro Carvalho Chehab 		ret = 0;
2809a0bf528SMauro Carvalho Chehab 	} else
2819a0bf528SMauro Carvalho Chehab 		ret = (state->i2c_read_buffer[0] << 8)
2829a0bf528SMauro Carvalho Chehab 			| state->i2c_read_buffer[1];
2839a0bf528SMauro Carvalho Chehab 
2849a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
2859a0bf528SMauro Carvalho Chehab 	return ret;
2869a0bf528SMauro Carvalho Chehab }
2879a0bf528SMauro Carvalho Chehab 
dib0090_fw_write_reg(struct dib0090_fw_state * state,u8 reg,u16 val)2889a0bf528SMauro Carvalho Chehab static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
2899a0bf528SMauro Carvalho Chehab {
2909a0bf528SMauro Carvalho Chehab 	int ret;
2919a0bf528SMauro Carvalho Chehab 
2929a0bf528SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
2934bd1a8ddSMauro Carvalho Chehab 		dprintk("could not acquire lock\n");
2949a0bf528SMauro Carvalho Chehab 		return -EINVAL;
2959a0bf528SMauro Carvalho Chehab 	}
2969a0bf528SMauro Carvalho Chehab 
2979a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[0] = val >> 8;
2989a0bf528SMauro Carvalho Chehab 	state->i2c_write_buffer[1] = val & 0xff;
2999a0bf528SMauro Carvalho Chehab 
3009a0bf528SMauro Carvalho Chehab 	memset(&state->msg, 0, sizeof(struct i2c_msg));
3019a0bf528SMauro Carvalho Chehab 	state->msg.addr = reg;
3029a0bf528SMauro Carvalho Chehab 	state->msg.flags = 0;
3039a0bf528SMauro Carvalho Chehab 	state->msg.buf = state->i2c_write_buffer;
3049a0bf528SMauro Carvalho Chehab 	state->msg.len = 2;
3059a0bf528SMauro Carvalho Chehab 	if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
3064bd1a8ddSMauro Carvalho Chehab 		pr_warn("DiB0090 I2C write failed\n");
3079a0bf528SMauro Carvalho Chehab 		ret = -EREMOTEIO;
3089a0bf528SMauro Carvalho Chehab 	} else
3099a0bf528SMauro Carvalho Chehab 		ret = 0;
3109a0bf528SMauro Carvalho Chehab 
3119a0bf528SMauro Carvalho Chehab 	mutex_unlock(&state->i2c_buffer_lock);
3129a0bf528SMauro Carvalho Chehab 	return ret;
3139a0bf528SMauro Carvalho Chehab }
3149a0bf528SMauro Carvalho Chehab 
3159a0bf528SMauro Carvalho Chehab #define HARD_RESET(state) do {  if (cfg->reset) {  if (cfg->sleep) cfg->sleep(fe, 0); msleep(10);  cfg->reset(fe, 1); msleep(10);  cfg->reset(fe, 0); msleep(10);  }  } while (0)
3169a0bf528SMauro Carvalho Chehab #define ADC_TARGET -220
3179a0bf528SMauro Carvalho Chehab #define GAIN_ALPHA 5
3189a0bf528SMauro Carvalho Chehab #define WBD_ALPHA 6
3199a0bf528SMauro Carvalho Chehab #define LPF	100
dib0090_write_regs(struct dib0090_state * state,u8 r,const u16 * b,u8 c)3209a0bf528SMauro Carvalho Chehab static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c)
3219a0bf528SMauro Carvalho Chehab {
3229a0bf528SMauro Carvalho Chehab 	do {
3239a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, r++, *b++);
3249a0bf528SMauro Carvalho Chehab 	} while (--c);
3259a0bf528SMauro Carvalho Chehab }
3269a0bf528SMauro Carvalho Chehab 
dib0090_identify(struct dvb_frontend * fe)3279a0bf528SMauro Carvalho Chehab static int dib0090_identify(struct dvb_frontend *fe)
3289a0bf528SMauro Carvalho Chehab {
3299a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
3309a0bf528SMauro Carvalho Chehab 	u16 v;
3319a0bf528SMauro Carvalho Chehab 	struct dib0090_identity *identity = &state->identity;
3329a0bf528SMauro Carvalho Chehab 
3339a0bf528SMauro Carvalho Chehab 	v = dib0090_read_reg(state, 0x1a);
3349a0bf528SMauro Carvalho Chehab 
3359a0bf528SMauro Carvalho Chehab 	identity->p1g = 0;
3369a0bf528SMauro Carvalho Chehab 	identity->in_soc = 0;
3379a0bf528SMauro Carvalho Chehab 
3384bd1a8ddSMauro Carvalho Chehab 	dprintk("Tuner identification (Version = 0x%04x)\n", v);
3399a0bf528SMauro Carvalho Chehab 
3409a0bf528SMauro Carvalho Chehab 	/* without PLL lock info */
3419a0bf528SMauro Carvalho Chehab 	v &= ~KROSUS_PLL_LOCKED;
3429a0bf528SMauro Carvalho Chehab 
3439a0bf528SMauro Carvalho Chehab 	identity->version = v & 0xff;
3449a0bf528SMauro Carvalho Chehab 	identity->product = (v >> 8) & 0xf;
3459a0bf528SMauro Carvalho Chehab 
3469a0bf528SMauro Carvalho Chehab 	if (identity->product != KROSUS)
3479a0bf528SMauro Carvalho Chehab 		goto identification_error;
3489a0bf528SMauro Carvalho Chehab 
3499a0bf528SMauro Carvalho Chehab 	if ((identity->version & 0x3) == SOC) {
3509a0bf528SMauro Carvalho Chehab 		identity->in_soc = 1;
3519a0bf528SMauro Carvalho Chehab 		switch (identity->version) {
3529a0bf528SMauro Carvalho Chehab 		case SOC_8090_P1G_11R1:
3534bd1a8ddSMauro Carvalho Chehab 			dprintk("SOC 8090 P1-G11R1 Has been detected\n");
3549a0bf528SMauro Carvalho Chehab 			identity->p1g = 1;
3559a0bf528SMauro Carvalho Chehab 			break;
3569a0bf528SMauro Carvalho Chehab 		case SOC_8090_P1G_21R1:
3574bd1a8ddSMauro Carvalho Chehab 			dprintk("SOC 8090 P1-G21R1 Has been detected\n");
3589a0bf528SMauro Carvalho Chehab 			identity->p1g = 1;
3599a0bf528SMauro Carvalho Chehab 			break;
3609a0bf528SMauro Carvalho Chehab 		case SOC_7090_P1G_11R1:
3614bd1a8ddSMauro Carvalho Chehab 			dprintk("SOC 7090 P1-G11R1 Has been detected\n");
3629a0bf528SMauro Carvalho Chehab 			identity->p1g = 1;
3639a0bf528SMauro Carvalho Chehab 			break;
3649a0bf528SMauro Carvalho Chehab 		case SOC_7090_P1G_21R1:
3654bd1a8ddSMauro Carvalho Chehab 			dprintk("SOC 7090 P1-G21R1 Has been detected\n");
3669a0bf528SMauro Carvalho Chehab 			identity->p1g = 1;
3679a0bf528SMauro Carvalho Chehab 			break;
3689a0bf528SMauro Carvalho Chehab 		default:
3699a0bf528SMauro Carvalho Chehab 			goto identification_error;
3709a0bf528SMauro Carvalho Chehab 		}
3719a0bf528SMauro Carvalho Chehab 	} else {
3729a0bf528SMauro Carvalho Chehab 		switch ((identity->version >> 5) & 0x7) {
3739a0bf528SMauro Carvalho Chehab 		case MP001:
3744bd1a8ddSMauro Carvalho Chehab 			dprintk("MP001 : 9090/8096\n");
3759a0bf528SMauro Carvalho Chehab 			break;
3769a0bf528SMauro Carvalho Chehab 		case MP005:
3774bd1a8ddSMauro Carvalho Chehab 			dprintk("MP005 : Single Sband\n");
3789a0bf528SMauro Carvalho Chehab 			break;
3799a0bf528SMauro Carvalho Chehab 		case MP008:
3804bd1a8ddSMauro Carvalho Chehab 			dprintk("MP008 : diversity VHF-UHF-LBAND\n");
3819a0bf528SMauro Carvalho Chehab 			break;
3829a0bf528SMauro Carvalho Chehab 		case MP009:
3834bd1a8ddSMauro Carvalho Chehab 			dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND\n");
3849a0bf528SMauro Carvalho Chehab 			break;
3859a0bf528SMauro Carvalho Chehab 		default:
3869a0bf528SMauro Carvalho Chehab 			goto identification_error;
3879a0bf528SMauro Carvalho Chehab 		}
3889a0bf528SMauro Carvalho Chehab 
3899a0bf528SMauro Carvalho Chehab 		switch (identity->version & 0x1f) {
3909a0bf528SMauro Carvalho Chehab 		case P1G_21R2:
3914bd1a8ddSMauro Carvalho Chehab 			dprintk("P1G_21R2 detected\n");
3929a0bf528SMauro Carvalho Chehab 			identity->p1g = 1;
3939a0bf528SMauro Carvalho Chehab 			break;
3949a0bf528SMauro Carvalho Chehab 		case P1G:
3954bd1a8ddSMauro Carvalho Chehab 			dprintk("P1G detected\n");
3969a0bf528SMauro Carvalho Chehab 			identity->p1g = 1;
3979a0bf528SMauro Carvalho Chehab 			break;
3989a0bf528SMauro Carvalho Chehab 		case P1D_E_F:
3994bd1a8ddSMauro Carvalho Chehab 			dprintk("P1D/E/F detected\n");
4009a0bf528SMauro Carvalho Chehab 			break;
4019a0bf528SMauro Carvalho Chehab 		case P1C:
4024bd1a8ddSMauro Carvalho Chehab 			dprintk("P1C detected\n");
4039a0bf528SMauro Carvalho Chehab 			break;
4049a0bf528SMauro Carvalho Chehab 		case P1A_B:
4054bd1a8ddSMauro Carvalho Chehab 			dprintk("P1-A/B detected: driver is deactivated - not available\n");
4069a0bf528SMauro Carvalho Chehab 			goto identification_error;
4079a0bf528SMauro Carvalho Chehab 			break;
4089a0bf528SMauro Carvalho Chehab 		default:
4099a0bf528SMauro Carvalho Chehab 			goto identification_error;
4109a0bf528SMauro Carvalho Chehab 		}
4119a0bf528SMauro Carvalho Chehab 	}
4129a0bf528SMauro Carvalho Chehab 
4139a0bf528SMauro Carvalho Chehab 	return 0;
4149a0bf528SMauro Carvalho Chehab 
4159a0bf528SMauro Carvalho Chehab identification_error:
4169a0bf528SMauro Carvalho Chehab 	return -EIO;
4179a0bf528SMauro Carvalho Chehab }
4189a0bf528SMauro Carvalho Chehab 
dib0090_fw_identify(struct dvb_frontend * fe)4199a0bf528SMauro Carvalho Chehab static int dib0090_fw_identify(struct dvb_frontend *fe)
4209a0bf528SMauro Carvalho Chehab {
4219a0bf528SMauro Carvalho Chehab 	struct dib0090_fw_state *state = fe->tuner_priv;
4229a0bf528SMauro Carvalho Chehab 	struct dib0090_identity *identity = &state->identity;
4239a0bf528SMauro Carvalho Chehab 
4249a0bf528SMauro Carvalho Chehab 	u16 v = dib0090_fw_read_reg(state, 0x1a);
4259a0bf528SMauro Carvalho Chehab 	identity->p1g = 0;
4269a0bf528SMauro Carvalho Chehab 	identity->in_soc = 0;
4279a0bf528SMauro Carvalho Chehab 
4284bd1a8ddSMauro Carvalho Chehab 	dprintk("FE: Tuner identification (Version = 0x%04x)\n", v);
4299a0bf528SMauro Carvalho Chehab 
4309a0bf528SMauro Carvalho Chehab 	/* without PLL lock info */
4319a0bf528SMauro Carvalho Chehab 	v &= ~KROSUS_PLL_LOCKED;
4329a0bf528SMauro Carvalho Chehab 
4339a0bf528SMauro Carvalho Chehab 	identity->version = v & 0xff;
4349a0bf528SMauro Carvalho Chehab 	identity->product = (v >> 8) & 0xf;
4359a0bf528SMauro Carvalho Chehab 
4369a0bf528SMauro Carvalho Chehab 	if (identity->product != KROSUS)
4379a0bf528SMauro Carvalho Chehab 		goto identification_error;
4389a0bf528SMauro Carvalho Chehab 
4399a0bf528SMauro Carvalho Chehab 	if ((identity->version & 0x3) == SOC) {
4409a0bf528SMauro Carvalho Chehab 		identity->in_soc = 1;
4419a0bf528SMauro Carvalho Chehab 		switch (identity->version) {
4429a0bf528SMauro Carvalho Chehab 		case SOC_8090_P1G_11R1:
4434bd1a8ddSMauro Carvalho Chehab 			dprintk("SOC 8090 P1-G11R1 Has been detected\n");
4449a0bf528SMauro Carvalho Chehab 			identity->p1g = 1;
4459a0bf528SMauro Carvalho Chehab 			break;
4469a0bf528SMauro Carvalho Chehab 		case SOC_8090_P1G_21R1:
4474bd1a8ddSMauro Carvalho Chehab 			dprintk("SOC 8090 P1-G21R1 Has been detected\n");
4489a0bf528SMauro Carvalho Chehab 			identity->p1g = 1;
4499a0bf528SMauro Carvalho Chehab 			break;
4509a0bf528SMauro Carvalho Chehab 		case SOC_7090_P1G_11R1:
4514bd1a8ddSMauro Carvalho Chehab 			dprintk("SOC 7090 P1-G11R1 Has been detected\n");
4529a0bf528SMauro Carvalho Chehab 			identity->p1g = 1;
4539a0bf528SMauro Carvalho Chehab 			break;
4549a0bf528SMauro Carvalho Chehab 		case SOC_7090_P1G_21R1:
4554bd1a8ddSMauro Carvalho Chehab 			dprintk("SOC 7090 P1-G21R1 Has been detected\n");
4569a0bf528SMauro Carvalho Chehab 			identity->p1g = 1;
4579a0bf528SMauro Carvalho Chehab 			break;
4589a0bf528SMauro Carvalho Chehab 		default:
4599a0bf528SMauro Carvalho Chehab 			goto identification_error;
4609a0bf528SMauro Carvalho Chehab 		}
4619a0bf528SMauro Carvalho Chehab 	} else {
4629a0bf528SMauro Carvalho Chehab 		switch ((identity->version >> 5) & 0x7) {
4639a0bf528SMauro Carvalho Chehab 		case MP001:
4644bd1a8ddSMauro Carvalho Chehab 			dprintk("MP001 : 9090/8096\n");
4659a0bf528SMauro Carvalho Chehab 			break;
4669a0bf528SMauro Carvalho Chehab 		case MP005:
4674bd1a8ddSMauro Carvalho Chehab 			dprintk("MP005 : Single Sband\n");
4689a0bf528SMauro Carvalho Chehab 			break;
4699a0bf528SMauro Carvalho Chehab 		case MP008:
4704bd1a8ddSMauro Carvalho Chehab 			dprintk("MP008 : diversity VHF-UHF-LBAND\n");
4719a0bf528SMauro Carvalho Chehab 			break;
4729a0bf528SMauro Carvalho Chehab 		case MP009:
4734bd1a8ddSMauro Carvalho Chehab 			dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND\n");
4749a0bf528SMauro Carvalho Chehab 			break;
4759a0bf528SMauro Carvalho Chehab 		default:
4769a0bf528SMauro Carvalho Chehab 			goto identification_error;
4779a0bf528SMauro Carvalho Chehab 		}
4789a0bf528SMauro Carvalho Chehab 
4799a0bf528SMauro Carvalho Chehab 		switch (identity->version & 0x1f) {
4809a0bf528SMauro Carvalho Chehab 		case P1G_21R2:
4814bd1a8ddSMauro Carvalho Chehab 			dprintk("P1G_21R2 detected\n");
4829a0bf528SMauro Carvalho Chehab 			identity->p1g = 1;
4839a0bf528SMauro Carvalho Chehab 			break;
4849a0bf528SMauro Carvalho Chehab 		case P1G:
4854bd1a8ddSMauro Carvalho Chehab 			dprintk("P1G detected\n");
4869a0bf528SMauro Carvalho Chehab 			identity->p1g = 1;
4879a0bf528SMauro Carvalho Chehab 			break;
4889a0bf528SMauro Carvalho Chehab 		case P1D_E_F:
4894bd1a8ddSMauro Carvalho Chehab 			dprintk("P1D/E/F detected\n");
4909a0bf528SMauro Carvalho Chehab 			break;
4919a0bf528SMauro Carvalho Chehab 		case P1C:
4924bd1a8ddSMauro Carvalho Chehab 			dprintk("P1C detected\n");
4939a0bf528SMauro Carvalho Chehab 			break;
4949a0bf528SMauro Carvalho Chehab 		case P1A_B:
4954bd1a8ddSMauro Carvalho Chehab 			dprintk("P1-A/B detected: driver is deactivated - not available\n");
4969a0bf528SMauro Carvalho Chehab 			goto identification_error;
4979a0bf528SMauro Carvalho Chehab 			break;
4989a0bf528SMauro Carvalho Chehab 		default:
4999a0bf528SMauro Carvalho Chehab 			goto identification_error;
5009a0bf528SMauro Carvalho Chehab 		}
5019a0bf528SMauro Carvalho Chehab 	}
5029a0bf528SMauro Carvalho Chehab 
5039a0bf528SMauro Carvalho Chehab 	return 0;
5049a0bf528SMauro Carvalho Chehab 
5059a0bf528SMauro Carvalho Chehab identification_error:
5069a0bf528SMauro Carvalho Chehab 	return -EIO;
5079a0bf528SMauro Carvalho Chehab }
5089a0bf528SMauro Carvalho Chehab 
dib0090_reset_digital(struct dvb_frontend * fe,const struct dib0090_config * cfg)5099a0bf528SMauro Carvalho Chehab static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
5109a0bf528SMauro Carvalho Chehab {
5119a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
5129a0bf528SMauro Carvalho Chehab 	u16 PllCfg, i, v;
5139a0bf528SMauro Carvalho Chehab 
5149a0bf528SMauro Carvalho Chehab 	HARD_RESET(state);
5159a0bf528SMauro Carvalho Chehab 	dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
516aedabf7aSOlivier Grenie 	if (cfg->in_soc)
517aedabf7aSOlivier Grenie 		return;
5189a0bf528SMauro Carvalho Chehab 
519aedabf7aSOlivier Grenie 	dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL);	/* PLL, DIG_CLK and CRYSTAL remain */
5209a0bf528SMauro Carvalho Chehab 	/* adcClkOutRatio=8->7, release reset */
5219a0bf528SMauro Carvalho Chehab 	dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);
5229a0bf528SMauro Carvalho Chehab 	if (cfg->clkoutdrive != 0)
5239a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
5249a0bf528SMauro Carvalho Chehab 				| (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
5259a0bf528SMauro Carvalho Chehab 	else
5269a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
5279a0bf528SMauro Carvalho Chehab 				| (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
5289a0bf528SMauro Carvalho Chehab 
5299a0bf528SMauro Carvalho Chehab 	/* Read Pll current config * */
5309a0bf528SMauro Carvalho Chehab 	PllCfg = dib0090_read_reg(state, 0x21);
5319a0bf528SMauro Carvalho Chehab 
5329a0bf528SMauro Carvalho Chehab 	/** Reconfigure PLL if current setting is different from default setting **/
5339a0bf528SMauro Carvalho Chehab 	if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && (!cfg->in_soc)
5349a0bf528SMauro Carvalho Chehab 			&& !cfg->io.pll_bypass) {
5359a0bf528SMauro Carvalho Chehab 
5369a0bf528SMauro Carvalho Chehab 		/* Set Bypass mode */
5379a0bf528SMauro Carvalho Chehab 		PllCfg |= (1 << 15);
5389a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x21, PllCfg);
5399a0bf528SMauro Carvalho Chehab 
5409a0bf528SMauro Carvalho Chehab 		/* Set Reset Pll */
5419a0bf528SMauro Carvalho Chehab 		PllCfg &= ~(1 << 13);
5429a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x21, PllCfg);
5439a0bf528SMauro Carvalho Chehab 
5449a0bf528SMauro Carvalho Chehab 	/*** Set new Pll configuration in bypass and reset state ***/
5459a0bf528SMauro Carvalho Chehab 		PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
5469a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x21, PllCfg);
5479a0bf528SMauro Carvalho Chehab 
5489a0bf528SMauro Carvalho Chehab 		/* Remove Reset Pll */
5499a0bf528SMauro Carvalho Chehab 		PllCfg |= (1 << 13);
5509a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x21, PllCfg);
5519a0bf528SMauro Carvalho Chehab 
5529a0bf528SMauro Carvalho Chehab 	/*** Wait for PLL lock ***/
5539a0bf528SMauro Carvalho Chehab 		i = 100;
5549a0bf528SMauro Carvalho Chehab 		do {
5559a0bf528SMauro Carvalho Chehab 			v = !!(dib0090_read_reg(state, 0x1a) & 0x800);
5569a0bf528SMauro Carvalho Chehab 			if (v)
5579a0bf528SMauro Carvalho Chehab 				break;
5589a0bf528SMauro Carvalho Chehab 		} while (--i);
5599a0bf528SMauro Carvalho Chehab 
5609a0bf528SMauro Carvalho Chehab 		if (i == 0) {
5614bd1a8ddSMauro Carvalho Chehab 			dprintk("Pll: Unable to lock Pll\n");
5629a0bf528SMauro Carvalho Chehab 			return;
5639a0bf528SMauro Carvalho Chehab 		}
5649a0bf528SMauro Carvalho Chehab 
5659a0bf528SMauro Carvalho Chehab 		/* Finally Remove Bypass mode */
5669a0bf528SMauro Carvalho Chehab 		PllCfg &= ~(1 << 15);
5679a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x21, PllCfg);
5689a0bf528SMauro Carvalho Chehab 	}
5699a0bf528SMauro Carvalho Chehab 
5709a0bf528SMauro Carvalho Chehab 	if (cfg->io.pll_bypass) {
5719a0bf528SMauro Carvalho Chehab 		PllCfg |= (cfg->io.pll_bypass << 15);
5729a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x21, PllCfg);
5739a0bf528SMauro Carvalho Chehab 	}
5749a0bf528SMauro Carvalho Chehab }
5759a0bf528SMauro Carvalho Chehab 
dib0090_fw_reset_digital(struct dvb_frontend * fe,const struct dib0090_config * cfg)5769a0bf528SMauro Carvalho Chehab static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
5779a0bf528SMauro Carvalho Chehab {
5789a0bf528SMauro Carvalho Chehab 	struct dib0090_fw_state *state = fe->tuner_priv;
5799a0bf528SMauro Carvalho Chehab 	u16 PllCfg;
5809a0bf528SMauro Carvalho Chehab 	u16 v;
5819a0bf528SMauro Carvalho Chehab 	int i;
5829a0bf528SMauro Carvalho Chehab 
5834bd1a8ddSMauro Carvalho Chehab 	dprintk("fw reset digital\n");
5849a0bf528SMauro Carvalho Chehab 	HARD_RESET(state);
5859a0bf528SMauro Carvalho Chehab 
5869a0bf528SMauro Carvalho Chehab 	dib0090_fw_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
5879a0bf528SMauro Carvalho Chehab 	dib0090_fw_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL);	/* PLL, DIG_CLK and CRYSTAL remain */
5889a0bf528SMauro Carvalho Chehab 
5899a0bf528SMauro Carvalho Chehab 	dib0090_fw_write_reg(state, 0x20,
5909a0bf528SMauro Carvalho Chehab 			((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (cfg->data_tx_drv << 4) | cfg->ls_cfg_pad_drv);
5919a0bf528SMauro Carvalho Chehab 
5929a0bf528SMauro Carvalho Chehab 	v = (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 9) | (0 << 8) | (cfg->clkouttobamse << 4) | (0 << 2) | (0);
5939a0bf528SMauro Carvalho Chehab 	if (cfg->clkoutdrive != 0)
5949a0bf528SMauro Carvalho Chehab 		v |= cfg->clkoutdrive << 5;
5959a0bf528SMauro Carvalho Chehab 	else
5969a0bf528SMauro Carvalho Chehab 		v |= 7 << 5;
5979a0bf528SMauro Carvalho Chehab 
5989a0bf528SMauro Carvalho Chehab 	v |= 2 << 10;
5999a0bf528SMauro Carvalho Chehab 	dib0090_fw_write_reg(state, 0x23, v);
6009a0bf528SMauro Carvalho Chehab 
6019a0bf528SMauro Carvalho Chehab 	/* Read Pll current config * */
6029a0bf528SMauro Carvalho Chehab 	PllCfg = dib0090_fw_read_reg(state, 0x21);
6039a0bf528SMauro Carvalho Chehab 
6049a0bf528SMauro Carvalho Chehab 	/** Reconfigure PLL if current setting is different from default setting **/
6059a0bf528SMauro Carvalho Chehab 	if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && !cfg->io.pll_bypass) {
6069a0bf528SMauro Carvalho Chehab 
6079a0bf528SMauro Carvalho Chehab 		/* Set Bypass mode */
6089a0bf528SMauro Carvalho Chehab 		PllCfg |= (1 << 15);
6099a0bf528SMauro Carvalho Chehab 		dib0090_fw_write_reg(state, 0x21, PllCfg);
6109a0bf528SMauro Carvalho Chehab 
6119a0bf528SMauro Carvalho Chehab 		/* Set Reset Pll */
6129a0bf528SMauro Carvalho Chehab 		PllCfg &= ~(1 << 13);
6139a0bf528SMauro Carvalho Chehab 		dib0090_fw_write_reg(state, 0x21, PllCfg);
6149a0bf528SMauro Carvalho Chehab 
6159a0bf528SMauro Carvalho Chehab 	/*** Set new Pll configuration in bypass and reset state ***/
6169a0bf528SMauro Carvalho Chehab 		PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
6179a0bf528SMauro Carvalho Chehab 		dib0090_fw_write_reg(state, 0x21, PllCfg);
6189a0bf528SMauro Carvalho Chehab 
6199a0bf528SMauro Carvalho Chehab 		/* Remove Reset Pll */
6209a0bf528SMauro Carvalho Chehab 		PllCfg |= (1 << 13);
6219a0bf528SMauro Carvalho Chehab 		dib0090_fw_write_reg(state, 0x21, PllCfg);
6229a0bf528SMauro Carvalho Chehab 
6239a0bf528SMauro Carvalho Chehab 	/*** Wait for PLL lock ***/
6249a0bf528SMauro Carvalho Chehab 		i = 100;
6259a0bf528SMauro Carvalho Chehab 		do {
6269a0bf528SMauro Carvalho Chehab 			v = !!(dib0090_fw_read_reg(state, 0x1a) & 0x800);
6279a0bf528SMauro Carvalho Chehab 			if (v)
6289a0bf528SMauro Carvalho Chehab 				break;
6299a0bf528SMauro Carvalho Chehab 		} while (--i);
6309a0bf528SMauro Carvalho Chehab 
6319a0bf528SMauro Carvalho Chehab 		if (i == 0) {
6324bd1a8ddSMauro Carvalho Chehab 			dprintk("Pll: Unable to lock Pll\n");
6339a0bf528SMauro Carvalho Chehab 			return -EIO;
6349a0bf528SMauro Carvalho Chehab 		}
6359a0bf528SMauro Carvalho Chehab 
6369a0bf528SMauro Carvalho Chehab 		/* Finally Remove Bypass mode */
6379a0bf528SMauro Carvalho Chehab 		PllCfg &= ~(1 << 15);
6389a0bf528SMauro Carvalho Chehab 		dib0090_fw_write_reg(state, 0x21, PllCfg);
6399a0bf528SMauro Carvalho Chehab 	}
6409a0bf528SMauro Carvalho Chehab 
6419a0bf528SMauro Carvalho Chehab 	if (cfg->io.pll_bypass) {
6429a0bf528SMauro Carvalho Chehab 		PllCfg |= (cfg->io.pll_bypass << 15);
6439a0bf528SMauro Carvalho Chehab 		dib0090_fw_write_reg(state, 0x21, PllCfg);
6449a0bf528SMauro Carvalho Chehab 	}
6459a0bf528SMauro Carvalho Chehab 
6469a0bf528SMauro Carvalho Chehab 	return dib0090_fw_identify(fe);
6479a0bf528SMauro Carvalho Chehab }
6489a0bf528SMauro Carvalho Chehab 
dib0090_wakeup(struct dvb_frontend * fe)6499a0bf528SMauro Carvalho Chehab static int dib0090_wakeup(struct dvb_frontend *fe)
6509a0bf528SMauro Carvalho Chehab {
6519a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
6529a0bf528SMauro Carvalho Chehab 	if (state->config->sleep)
6539a0bf528SMauro Carvalho Chehab 		state->config->sleep(fe, 0);
6549a0bf528SMauro Carvalho Chehab 
6559a0bf528SMauro Carvalho Chehab 	/* enable dataTX in case we have been restarted in the wrong moment */
6569a0bf528SMauro Carvalho Chehab 	dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
6579a0bf528SMauro Carvalho Chehab 	return 0;
6589a0bf528SMauro Carvalho Chehab }
6599a0bf528SMauro Carvalho Chehab 
dib0090_sleep(struct dvb_frontend * fe)6609a0bf528SMauro Carvalho Chehab static int dib0090_sleep(struct dvb_frontend *fe)
6619a0bf528SMauro Carvalho Chehab {
6629a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
6639a0bf528SMauro Carvalho Chehab 	if (state->config->sleep)
6649a0bf528SMauro Carvalho Chehab 		state->config->sleep(fe, 1);
6659a0bf528SMauro Carvalho Chehab 	return 0;
6669a0bf528SMauro Carvalho Chehab }
6679a0bf528SMauro Carvalho Chehab 
dib0090_dcc_freq(struct dvb_frontend * fe,u8 fast)6689a0bf528SMauro Carvalho Chehab void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
6699a0bf528SMauro Carvalho Chehab {
6709a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
6719a0bf528SMauro Carvalho Chehab 	if (fast)
6729a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x04, 0);
6739a0bf528SMauro Carvalho Chehab 	else
6749a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x04, 1);
6759a0bf528SMauro Carvalho Chehab }
6769a0bf528SMauro Carvalho Chehab 
6779a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib0090_dcc_freq);
6789a0bf528SMauro Carvalho Chehab 
6799a0bf528SMauro Carvalho Chehab static const u16 bb_ramp_pwm_normal_socs[] = {
6809a0bf528SMauro Carvalho Chehab 	550, /* max BB gain in 10th of dB */
6819a0bf528SMauro Carvalho Chehab 	(1<<9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
6829a0bf528SMauro Carvalho Chehab 	440,
6839a0bf528SMauro Carvalho Chehab 	(4  << 9) | 0, /* BB_RAMP3 = 26dB */
6849a0bf528SMauro Carvalho Chehab 	(0  << 9) | 208, /* BB_RAMP4 */
6859a0bf528SMauro Carvalho Chehab 	(4  << 9) | 208, /* BB_RAMP5 = 29dB */
6869a0bf528SMauro Carvalho Chehab 	(0  << 9) | 440, /* BB_RAMP6 */
6879a0bf528SMauro Carvalho Chehab };
6889a0bf528SMauro Carvalho Chehab 
689aedabf7aSOlivier Grenie static const u16 rf_ramp_pwm_cband_7090p[] = {
6909a0bf528SMauro Carvalho Chehab 	280, /* max RF gain in 10th of dB */
6919a0bf528SMauro Carvalho Chehab 	18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
6929a0bf528SMauro Carvalho Chehab 	504, /* ramp_max = maximum X used on the ramp */
6939a0bf528SMauro Carvalho Chehab 	(29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */
6949a0bf528SMauro Carvalho Chehab 	(0  << 10) | 504, /* RF_RAMP6, LNA 1 */
6959a0bf528SMauro Carvalho Chehab 	(60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */
6969a0bf528SMauro Carvalho Chehab 	(0  << 10) | 364, /* RF_RAMP8, LNA 2 */
6979a0bf528SMauro Carvalho Chehab 	(34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */
6989a0bf528SMauro Carvalho Chehab 	(0  << 10) | 228, /* GAIN_4_2, LNA 3 */
6999a0bf528SMauro Carvalho Chehab 	(37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */
7009a0bf528SMauro Carvalho Chehab 	(0  << 10) | 109, /* RF_RAMP4, LNA 4 */
7019a0bf528SMauro Carvalho Chehab };
7029a0bf528SMauro Carvalho Chehab 
703aedabf7aSOlivier Grenie static const u16 rf_ramp_pwm_cband_7090e_sensitivity[] = {
704aedabf7aSOlivier Grenie 	186, /* max RF gain in 10th of dB */
705aedabf7aSOlivier Grenie 	40, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
706aedabf7aSOlivier Grenie 	746, /* ramp_max = maximum X used on the ramp */
707aedabf7aSOlivier Grenie 	(10 << 10) | 345, /* RF_RAMP5, LNA 1 = 10dB */
708aedabf7aSOlivier Grenie 	(0  << 10) | 746, /* RF_RAMP6, LNA 1 */
709aedabf7aSOlivier Grenie 	(0 << 10) | 0, /* RF_RAMP7, LNA 2 = 0 dB */
710aedabf7aSOlivier Grenie 	(0  << 10) | 0, /* RF_RAMP8, LNA 2 */
711aedabf7aSOlivier Grenie 	(28 << 10) | 200, /* GAIN_4_1, LNA 3 = 6.8dB */ /* 3.61 dB */
712aedabf7aSOlivier Grenie 	(0  << 10) | 345, /* GAIN_4_2, LNA 3 */
713aedabf7aSOlivier Grenie 	(20 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ /* 4.96 dB */
714aedabf7aSOlivier Grenie 	(0  << 10) | 200, /* RF_RAMP4, LNA 4 */
7159a0bf528SMauro Carvalho Chehab };
7169a0bf528SMauro Carvalho Chehab 
717aedabf7aSOlivier Grenie static const u16 rf_ramp_pwm_cband_7090e_aci[] = {
718aedabf7aSOlivier Grenie 	86, /* max RF gain in 10th of dB */
719aedabf7aSOlivier Grenie 	40, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
720aedabf7aSOlivier Grenie 	345, /* ramp_max = maximum X used on the ramp */
721aedabf7aSOlivier Grenie 	(0 << 10) | 0, /* RF_RAMP5, LNA 1 = 8dB */ /* 7.47 dB */
722aedabf7aSOlivier Grenie 	(0 << 10) | 0, /* RF_RAMP6, LNA 1 */
723aedabf7aSOlivier Grenie 	(0 << 10) | 0, /* RF_RAMP7, LNA 2 = 0 dB */
724aedabf7aSOlivier Grenie 	(0 << 10) | 0, /* RF_RAMP8, LNA 2 */
725aedabf7aSOlivier Grenie 	(28 << 10) | 200, /* GAIN_4_1, LNA 3 = 6.8dB */ /* 3.61 dB */
726aedabf7aSOlivier Grenie 	(0  << 10) | 345, /* GAIN_4_2, LNA 3 */
727aedabf7aSOlivier Grenie 	(20 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ /* 4.96 dB */
728aedabf7aSOlivier Grenie 	(0  << 10) | 200, /* RF_RAMP4, LNA 4 */
7299a0bf528SMauro Carvalho Chehab };
7309a0bf528SMauro Carvalho Chehab 
7319a0bf528SMauro Carvalho Chehab static const u16 rf_ramp_pwm_cband_8090[] = {
7329a0bf528SMauro Carvalho Chehab 	345, /* max RF gain in 10th of dB */
7339a0bf528SMauro Carvalho Chehab 	29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
7349a0bf528SMauro Carvalho Chehab 	1000, /* ramp_max = maximum X used on the ramp */
7359a0bf528SMauro Carvalho Chehab 	(35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */
7369a0bf528SMauro Carvalho Chehab 	(0  << 10) | 1000, /* RF_RAMP4, LNA 1 */
7379a0bf528SMauro Carvalho Chehab 	(58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */
7389a0bf528SMauro Carvalho Chehab 	(0  << 10) | 772, /* RF_RAMP6, LNA 2 */
7399a0bf528SMauro Carvalho Chehab 	(27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */
7409a0bf528SMauro Carvalho Chehab 	(0  << 10) | 496, /* RF_RAMP8, LNA 3 */
7419a0bf528SMauro Carvalho Chehab 	(40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */
7429a0bf528SMauro Carvalho Chehab 	(0  << 10) | 200, /* GAIN_4_2, LNA 4 */
7439a0bf528SMauro Carvalho Chehab };
7449a0bf528SMauro Carvalho Chehab 
7459a0bf528SMauro Carvalho Chehab static const u16 rf_ramp_pwm_uhf_7090[] = {
7469a0bf528SMauro Carvalho Chehab 	407, /* max RF gain in 10th of dB */
7479a0bf528SMauro Carvalho Chehab 	13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
7489a0bf528SMauro Carvalho Chehab 	529, /* ramp_max = maximum X used on the ramp */
7499a0bf528SMauro Carvalho Chehab 	(23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
7509a0bf528SMauro Carvalho Chehab 	(0  << 10) | 176, /* RF_RAMP4, LNA 1 */
7519a0bf528SMauro Carvalho Chehab 	(63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */
7529a0bf528SMauro Carvalho Chehab 	(0  << 10) | 529, /* RF_RAMP6, LNA 2 */
7539a0bf528SMauro Carvalho Chehab 	(48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */
7549a0bf528SMauro Carvalho Chehab 	(0  << 10) | 400, /* RF_RAMP8, LNA 3 */
7559a0bf528SMauro Carvalho Chehab 	(29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */
7569a0bf528SMauro Carvalho Chehab 	(0  << 10) | 316, /* GAIN_4_2, LNA 4 */
7579a0bf528SMauro Carvalho Chehab };
7589a0bf528SMauro Carvalho Chehab 
7599a0bf528SMauro Carvalho Chehab static const u16 rf_ramp_pwm_uhf_8090[] = {
7609a0bf528SMauro Carvalho Chehab 	388, /* max RF gain in 10th of dB */
7619a0bf528SMauro Carvalho Chehab 	26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
7629a0bf528SMauro Carvalho Chehab 	1008, /* ramp_max = maximum X used on the ramp */
7639a0bf528SMauro Carvalho Chehab 	(11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
7649a0bf528SMauro Carvalho Chehab 	(0  << 10) | 369, /* RF_RAMP4, LNA 1 */
7659a0bf528SMauro Carvalho Chehab 	(41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */
7669a0bf528SMauro Carvalho Chehab 	(0  << 10) | 1008, /* RF_RAMP6, LNA 2 */
7679a0bf528SMauro Carvalho Chehab 	(27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */
7689a0bf528SMauro Carvalho Chehab 	(0  << 10) | 809, /* RF_RAMP8, LNA 3 */
7699a0bf528SMauro Carvalho Chehab 	(14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */
7709a0bf528SMauro Carvalho Chehab 	(0  << 10) | 659, /* GAIN_4_2, LNA 4 */
7719a0bf528SMauro Carvalho Chehab };
7729a0bf528SMauro Carvalho Chehab 
773aedabf7aSOlivier Grenie /* GENERAL PWM ramp definition for all other Krosus */
774aedabf7aSOlivier Grenie static const u16 bb_ramp_pwm_normal[] = {
775aedabf7aSOlivier Grenie 	500, /* max BB gain in 10th of dB */
776aedabf7aSOlivier Grenie 	8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
777aedabf7aSOlivier Grenie 	400,
778aedabf7aSOlivier Grenie 	(2  << 9) | 0, /* BB_RAMP3 = 21dB */
779aedabf7aSOlivier Grenie 	(0  << 9) | 168, /* BB_RAMP4 */
780aedabf7aSOlivier Grenie 	(2  << 9) | 168, /* BB_RAMP5 = 29dB */
781aedabf7aSOlivier Grenie 	(0  << 9) | 400, /* BB_RAMP6 */
782aedabf7aSOlivier Grenie };
783aedabf7aSOlivier Grenie 
784cf47facaSMauro Carvalho Chehab #if 0
785cf47facaSMauro Carvalho Chehab /* Currently unused */
786aedabf7aSOlivier Grenie static const u16 bb_ramp_pwm_boost[] = {
787aedabf7aSOlivier Grenie 	550, /* max BB gain in 10th of dB */
788aedabf7aSOlivier Grenie 	8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
789aedabf7aSOlivier Grenie 	440,
790aedabf7aSOlivier Grenie 	(2  << 9) | 0, /* BB_RAMP3 = 26dB */
791aedabf7aSOlivier Grenie 	(0  << 9) | 208, /* BB_RAMP4 */
792aedabf7aSOlivier Grenie 	(2  << 9) | 208, /* BB_RAMP5 = 29dB */
793aedabf7aSOlivier Grenie 	(0  << 9) | 440, /* BB_RAMP6 */
794aedabf7aSOlivier Grenie };
795cf47facaSMauro Carvalho Chehab #endif
796aedabf7aSOlivier Grenie 
7979a0bf528SMauro Carvalho Chehab static const u16 rf_ramp_pwm_cband[] = {
798aedabf7aSOlivier Grenie 	314, /* max RF gain in 10th of dB */
799aedabf7aSOlivier Grenie 	33, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
800aedabf7aSOlivier Grenie 	1023, /* ramp_max = maximum X used on the ramp */
801aedabf7aSOlivier Grenie 	(8  << 10) | 743, /* RF_RAMP3, LNA 1 = 0dB */
802aedabf7aSOlivier Grenie 	(0  << 10) | 1023, /* RF_RAMP4, LNA 1 */
803aedabf7aSOlivier Grenie 	(15 << 10) | 469, /* RF_RAMP5, LNA 2 = 0dB */
804aedabf7aSOlivier Grenie 	(0  << 10) | 742, /* RF_RAMP6, LNA 2 */
805aedabf7aSOlivier Grenie 	(9  << 10) | 234, /* RF_RAMP7, LNA 3 = 0dB */
806aedabf7aSOlivier Grenie 	(0  << 10) | 468, /* RF_RAMP8, LNA 3 */
807aedabf7aSOlivier Grenie 	(9  << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
808aedabf7aSOlivier Grenie 	(0  << 10) | 233, /* GAIN_4_2, LNA 4 */
8099a0bf528SMauro Carvalho Chehab };
8109a0bf528SMauro Carvalho Chehab 
8119a0bf528SMauro Carvalho Chehab static const u16 rf_ramp_pwm_vhf[] = {
812aedabf7aSOlivier Grenie 	398, /* max RF gain in 10th of dB */
813aedabf7aSOlivier Grenie 	24, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
814aedabf7aSOlivier Grenie 	954, /* ramp_max = maximum X used on the ramp */
815aedabf7aSOlivier Grenie 	(7  << 10) | 0, /* RF_RAMP3, LNA 1 = 13.2dB */
816aedabf7aSOlivier Grenie 	(0  << 10) | 290, /* RF_RAMP4, LNA 1 */
817aedabf7aSOlivier Grenie 	(16 << 10) | 699, /* RF_RAMP5, LNA 2 = 10.5dB */
818aedabf7aSOlivier Grenie 	(0  << 10) | 954, /* RF_RAMP6, LNA 2 */
819aedabf7aSOlivier Grenie 	(17 << 10) | 580, /* RF_RAMP7, LNA 3 = 5dB */
820aedabf7aSOlivier Grenie 	(0  << 10) | 699, /* RF_RAMP8, LNA 3 */
821aedabf7aSOlivier Grenie 	(7  << 10) | 290, /* GAIN_4_1, LNA 4 = 12.5dB */
822aedabf7aSOlivier Grenie 	(0  << 10) | 580, /* GAIN_4_2, LNA 4 */
8239a0bf528SMauro Carvalho Chehab };
8249a0bf528SMauro Carvalho Chehab 
8259a0bf528SMauro Carvalho Chehab static const u16 rf_ramp_pwm_uhf[] = {
826aedabf7aSOlivier Grenie 	398, /* max RF gain in 10th of dB */
827aedabf7aSOlivier Grenie 	24, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
828aedabf7aSOlivier Grenie 	954, /* ramp_max = maximum X used on the ramp */
829aedabf7aSOlivier Grenie 	(7  << 10) | 0, /* RF_RAMP3, LNA 1 = 13.2dB */
830aedabf7aSOlivier Grenie 	(0  << 10) | 290, /* RF_RAMP4, LNA 1 */
831aedabf7aSOlivier Grenie 	(16 << 10) | 699, /* RF_RAMP5, LNA 2 = 10.5dB */
832aedabf7aSOlivier Grenie 	(0  << 10) | 954, /* RF_RAMP6, LNA 2 */
833aedabf7aSOlivier Grenie 	(17 << 10) | 580, /* RF_RAMP7, LNA 3 = 5dB */
834aedabf7aSOlivier Grenie 	(0  << 10) | 699, /* RF_RAMP8, LNA 3 */
835aedabf7aSOlivier Grenie 	(7  << 10) | 290, /* GAIN_4_1, LNA 4 = 12.5dB */
836aedabf7aSOlivier Grenie 	(0  << 10) | 580, /* GAIN_4_2, LNA 4 */
8379a0bf528SMauro Carvalho Chehab };
8389a0bf528SMauro Carvalho Chehab 
839cf47facaSMauro Carvalho Chehab #if 0
840cf47facaSMauro Carvalho Chehab /* Currently unused */
841aedabf7aSOlivier Grenie static const u16 rf_ramp_pwm_sband[] = {
842aedabf7aSOlivier Grenie 	253, /* max RF gain in 10th of dB */
843aedabf7aSOlivier Grenie 	38, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
844aedabf7aSOlivier Grenie 	961,
845aedabf7aSOlivier Grenie 	(4  << 10) | 0, /* RF_RAMP3, LNA 1 = 14.1dB */
846aedabf7aSOlivier Grenie 	(0  << 10) | 508, /* RF_RAMP4, LNA 1 */
847aedabf7aSOlivier Grenie 	(9  << 10) | 508, /* RF_RAMP5, LNA 2 = 11.2dB */
848aedabf7aSOlivier Grenie 	(0  << 10) | 961, /* RF_RAMP6, LNA 2 */
849aedabf7aSOlivier Grenie 	(0  << 10) | 0, /* RF_RAMP7, LNA 3 = 0dB */
850aedabf7aSOlivier Grenie 	(0  << 10) | 0, /* RF_RAMP8, LNA 3 */
851aedabf7aSOlivier Grenie 	(0  << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
852aedabf7aSOlivier Grenie 	(0  << 10) | 0, /* GAIN_4_2, LNA 4 */
8539a0bf528SMauro Carvalho Chehab };
854cf47facaSMauro Carvalho Chehab #endif
8559a0bf528SMauro Carvalho Chehab 
8569a0bf528SMauro Carvalho Chehab struct slope {
8579a0bf528SMauro Carvalho Chehab 	s16 range;
8589a0bf528SMauro Carvalho Chehab 	s16 slope;
8599a0bf528SMauro Carvalho Chehab };
slopes_to_scale(const struct slope * slopes,u8 num,s16 val)8609a0bf528SMauro Carvalho Chehab static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val)
8619a0bf528SMauro Carvalho Chehab {
8629a0bf528SMauro Carvalho Chehab 	u8 i;
8639a0bf528SMauro Carvalho Chehab 	u16 rest;
8649a0bf528SMauro Carvalho Chehab 	u16 ret = 0;
8659a0bf528SMauro Carvalho Chehab 	for (i = 0; i < num; i++) {
8669a0bf528SMauro Carvalho Chehab 		if (val > slopes[i].range)
8679a0bf528SMauro Carvalho Chehab 			rest = slopes[i].range;
8689a0bf528SMauro Carvalho Chehab 		else
8699a0bf528SMauro Carvalho Chehab 			rest = val;
8709a0bf528SMauro Carvalho Chehab 		ret += (rest * slopes[i].slope) / slopes[i].range;
8719a0bf528SMauro Carvalho Chehab 		val -= rest;
8729a0bf528SMauro Carvalho Chehab 	}
8739a0bf528SMauro Carvalho Chehab 	return ret;
8749a0bf528SMauro Carvalho Chehab }
8759a0bf528SMauro Carvalho Chehab 
8769a0bf528SMauro Carvalho Chehab static const struct slope dib0090_wbd_slopes[3] = {
8779a0bf528SMauro Carvalho Chehab 	{66, 120},		/* -64,-52: offset -   65 */
8789a0bf528SMauro Carvalho Chehab 	{600, 170},		/* -52,-35: 65     -  665 */
8799a0bf528SMauro Carvalho Chehab 	{170, 250},		/* -45,-10: 665    - 835 */
8809a0bf528SMauro Carvalho Chehab };
8819a0bf528SMauro Carvalho Chehab 
dib0090_wbd_to_db(struct dib0090_state * state,u16 wbd)8829a0bf528SMauro Carvalho Chehab static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd)
8839a0bf528SMauro Carvalho Chehab {
8849a0bf528SMauro Carvalho Chehab 	wbd &= 0x3ff;
8859a0bf528SMauro Carvalho Chehab 	if (wbd < state->wbd_offset)
8869a0bf528SMauro Carvalho Chehab 		wbd = 0;
8879a0bf528SMauro Carvalho Chehab 	else
8889a0bf528SMauro Carvalho Chehab 		wbd -= state->wbd_offset;
8899a0bf528SMauro Carvalho Chehab 	/* -64dB is the floor */
8909a0bf528SMauro Carvalho Chehab 	return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd);
8919a0bf528SMauro Carvalho Chehab }
8929a0bf528SMauro Carvalho Chehab 
dib0090_wbd_target(struct dib0090_state * state,u32 rf)8939a0bf528SMauro Carvalho Chehab static void dib0090_wbd_target(struct dib0090_state *state, u32 rf)
8949a0bf528SMauro Carvalho Chehab {
8959a0bf528SMauro Carvalho Chehab 	u16 offset = 250;
8969a0bf528SMauro Carvalho Chehab 
8979a0bf528SMauro Carvalho Chehab 	/* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */
8989a0bf528SMauro Carvalho Chehab 
8999a0bf528SMauro Carvalho Chehab 	if (state->current_band == BAND_VHF)
9009a0bf528SMauro Carvalho Chehab 		offset = 650;
9019a0bf528SMauro Carvalho Chehab #ifndef FIRMWARE_FIREFLY
9029a0bf528SMauro Carvalho Chehab 	if (state->current_band == BAND_VHF)
9039a0bf528SMauro Carvalho Chehab 		offset = state->config->wbd_vhf_offset;
9049a0bf528SMauro Carvalho Chehab 	if (state->current_band == BAND_CBAND)
9059a0bf528SMauro Carvalho Chehab 		offset = state->config->wbd_cband_offset;
9069a0bf528SMauro Carvalho Chehab #endif
9079a0bf528SMauro Carvalho Chehab 
9089a0bf528SMauro Carvalho Chehab 	state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset);
9094bd1a8ddSMauro Carvalho Chehab 	dprintk("wbd-target: %d dB\n", (u32) state->wbd_target);
9109a0bf528SMauro Carvalho Chehab }
9119a0bf528SMauro Carvalho Chehab 
9129a0bf528SMauro Carvalho Chehab static const int gain_reg_addr[4] = {
9139a0bf528SMauro Carvalho Chehab 	0x08, 0x0a, 0x0f, 0x01
9149a0bf528SMauro Carvalho Chehab };
9159a0bf528SMauro Carvalho Chehab 
dib0090_gain_apply(struct dib0090_state * state,s16 gain_delta,s16 top_delta,u8 force)9169a0bf528SMauro Carvalho Chehab static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force)
9179a0bf528SMauro Carvalho Chehab {
9189a0bf528SMauro Carvalho Chehab 	u16 rf, bb, ref;
9199a0bf528SMauro Carvalho Chehab 	u16 i, v, gain_reg[4] = { 0 }, gain;
9209a0bf528SMauro Carvalho Chehab 	const u16 *g;
9219a0bf528SMauro Carvalho Chehab 
9229a0bf528SMauro Carvalho Chehab 	if (top_delta < -511)
9239a0bf528SMauro Carvalho Chehab 		top_delta = -511;
9249a0bf528SMauro Carvalho Chehab 	if (top_delta > 511)
9259a0bf528SMauro Carvalho Chehab 		top_delta = 511;
9269a0bf528SMauro Carvalho Chehab 
9279a0bf528SMauro Carvalho Chehab 	if (force) {
9289a0bf528SMauro Carvalho Chehab 		top_delta *= (1 << WBD_ALPHA);
9299a0bf528SMauro Carvalho Chehab 		gain_delta *= (1 << GAIN_ALPHA);
9309a0bf528SMauro Carvalho Chehab 	}
9319a0bf528SMauro Carvalho Chehab 
9329a0bf528SMauro Carvalho Chehab 	if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit))	/* overflow */
9339a0bf528SMauro Carvalho Chehab 		state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
9349a0bf528SMauro Carvalho Chehab 	else
9359a0bf528SMauro Carvalho Chehab 		state->rf_gain_limit += top_delta;
9369a0bf528SMauro Carvalho Chehab 
9379a0bf528SMauro Carvalho Chehab 	if (state->rf_gain_limit < 0)	/*underflow */
9389a0bf528SMauro Carvalho Chehab 		state->rf_gain_limit = 0;
9399a0bf528SMauro Carvalho Chehab 
9409a0bf528SMauro Carvalho Chehab 	/* use gain as a temporary variable and correct current_gain */
9419a0bf528SMauro Carvalho Chehab 	gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA;
9429a0bf528SMauro Carvalho Chehab 	if (gain_delta >= ((s16) gain - state->current_gain))	/* overflow */
9439a0bf528SMauro Carvalho Chehab 		state->current_gain = gain;
9449a0bf528SMauro Carvalho Chehab 	else
9459a0bf528SMauro Carvalho Chehab 		state->current_gain += gain_delta;
9469a0bf528SMauro Carvalho Chehab 	/* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */
9479a0bf528SMauro Carvalho Chehab 	if (state->current_gain < 0)
9489a0bf528SMauro Carvalho Chehab 		state->current_gain = 0;
9499a0bf528SMauro Carvalho Chehab 
9509a0bf528SMauro Carvalho Chehab 	/* now split total gain to rf and bb gain */
9519a0bf528SMauro Carvalho Chehab 	gain = state->current_gain >> GAIN_ALPHA;
9529a0bf528SMauro Carvalho Chehab 
9539a0bf528SMauro Carvalho Chehab 	/* requested gain is bigger than rf gain limit - ACI/WBD adjustment */
9549a0bf528SMauro Carvalho Chehab 	if (gain > (state->rf_gain_limit >> WBD_ALPHA)) {
9559a0bf528SMauro Carvalho Chehab 		rf = state->rf_gain_limit >> WBD_ALPHA;
9569a0bf528SMauro Carvalho Chehab 		bb = gain - rf;
9579a0bf528SMauro Carvalho Chehab 		if (bb > state->bb_ramp[0])
9589a0bf528SMauro Carvalho Chehab 			bb = state->bb_ramp[0];
9599a0bf528SMauro Carvalho Chehab 	} else {		/* high signal level -> all gains put on RF */
9609a0bf528SMauro Carvalho Chehab 		rf = gain;
9619a0bf528SMauro Carvalho Chehab 		bb = 0;
9629a0bf528SMauro Carvalho Chehab 	}
9639a0bf528SMauro Carvalho Chehab 
9649a0bf528SMauro Carvalho Chehab 	state->gain[0] = rf;
9659a0bf528SMauro Carvalho Chehab 	state->gain[1] = bb;
9669a0bf528SMauro Carvalho Chehab 
9679a0bf528SMauro Carvalho Chehab 	/* software ramp */
9689a0bf528SMauro Carvalho Chehab 	/* Start with RF gains */
9699a0bf528SMauro Carvalho Chehab 	g = state->rf_ramp + 1;	/* point on RF LNA1 max gain */
9709a0bf528SMauro Carvalho Chehab 	ref = rf;
9719a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 7; i++) {	/* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */
9729a0bf528SMauro Carvalho Chehab 		if (g[0] == 0 || ref < (g[1] - g[0]))	/* if total gain of the current amp is null or this amp is not concerned because it starts to work from an higher gain value */
9739a0bf528SMauro Carvalho Chehab 			v = 0;	/* force the gain to write for the current amp to be null */
9749a0bf528SMauro Carvalho Chehab 		else if (ref >= g[1])	/* Gain to set is higher than the high working point of this amp */
9759a0bf528SMauro Carvalho Chehab 			v = g[2];	/* force this amp to be full gain */
9769a0bf528SMauro Carvalho Chehab 		else		/* compute the value to set to this amp because we are somewhere in his range */
9779a0bf528SMauro Carvalho Chehab 			v = ((ref - (g[1] - g[0])) * g[2]) / g[0];
9789a0bf528SMauro Carvalho Chehab 
9799a0bf528SMauro Carvalho Chehab 		if (i == 0)	/* LNA 1 reg mapping */
9809a0bf528SMauro Carvalho Chehab 			gain_reg[0] = v;
9819a0bf528SMauro Carvalho Chehab 		else if (i == 1)	/* LNA 2 reg mapping */
9829a0bf528SMauro Carvalho Chehab 			gain_reg[0] |= v << 7;
9839a0bf528SMauro Carvalho Chehab 		else if (i == 2)	/* LNA 3 reg mapping */
9849a0bf528SMauro Carvalho Chehab 			gain_reg[1] = v;
9859a0bf528SMauro Carvalho Chehab 		else if (i == 3)	/* LNA 4 reg mapping */
9869a0bf528SMauro Carvalho Chehab 			gain_reg[1] |= v << 7;
9879a0bf528SMauro Carvalho Chehab 		else if (i == 4)	/* CBAND LNA reg mapping */
9889a0bf528SMauro Carvalho Chehab 			gain_reg[2] = v | state->rf_lt_def;
9899a0bf528SMauro Carvalho Chehab 		else if (i == 5)	/* BB gain 1 reg mapping */
9909a0bf528SMauro Carvalho Chehab 			gain_reg[3] = v << 3;
9919a0bf528SMauro Carvalho Chehab 		else if (i == 6)	/* BB gain 2 reg mapping */
9929a0bf528SMauro Carvalho Chehab 			gain_reg[3] |= v << 8;
9939a0bf528SMauro Carvalho Chehab 
9949a0bf528SMauro Carvalho Chehab 		g += 3;		/* go to next gain bloc */
9959a0bf528SMauro Carvalho Chehab 
9969a0bf528SMauro Carvalho Chehab 		/* When RF is finished, start with BB */
9979a0bf528SMauro Carvalho Chehab 		if (i == 4) {
9989a0bf528SMauro Carvalho Chehab 			g = state->bb_ramp + 1;	/* point on BB gain 1 max gain */
9999a0bf528SMauro Carvalho Chehab 			ref = bb;
10009a0bf528SMauro Carvalho Chehab 		}
10019a0bf528SMauro Carvalho Chehab 	}
10029a0bf528SMauro Carvalho Chehab 	gain_reg[3] |= state->bb_1_def;
10039a0bf528SMauro Carvalho Chehab 	gain_reg[3] |= ((bb % 10) * 100) / 125;
10049a0bf528SMauro Carvalho Chehab 
10059a0bf528SMauro Carvalho Chehab #ifdef DEBUG_AGC
10064bd1a8ddSMauro Carvalho Chehab 	dprintk("GA CALC: DB: %3d(rf) + %3d(bb) = %3d gain_reg[0]=%04x gain_reg[1]=%04x gain_reg[2]=%04x gain_reg[0]=%04x\n", rf, bb, rf + bb,
10079a0bf528SMauro Carvalho Chehab 		gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]);
10089a0bf528SMauro Carvalho Chehab #endif
10099a0bf528SMauro Carvalho Chehab 
10109a0bf528SMauro Carvalho Chehab 	/* Write the amplifier regs */
10119a0bf528SMauro Carvalho Chehab 	for (i = 0; i < 4; i++) {
10129a0bf528SMauro Carvalho Chehab 		v = gain_reg[i];
10139a0bf528SMauro Carvalho Chehab 		if (force || state->gain_reg[i] != v) {
10149a0bf528SMauro Carvalho Chehab 			state->gain_reg[i] = v;
10159a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, gain_reg_addr[i], v);
10169a0bf528SMauro Carvalho Chehab 		}
10179a0bf528SMauro Carvalho Chehab 	}
10189a0bf528SMauro Carvalho Chehab }
10199a0bf528SMauro Carvalho Chehab 
dib0090_set_boost(struct dib0090_state * state,int onoff)10209a0bf528SMauro Carvalho Chehab static void dib0090_set_boost(struct dib0090_state *state, int onoff)
10219a0bf528SMauro Carvalho Chehab {
10229a0bf528SMauro Carvalho Chehab 	state->bb_1_def &= 0xdfff;
10239a0bf528SMauro Carvalho Chehab 	state->bb_1_def |= onoff << 13;
10249a0bf528SMauro Carvalho Chehab }
10259a0bf528SMauro Carvalho Chehab 
dib0090_set_rframp(struct dib0090_state * state,const u16 * cfg)10269a0bf528SMauro Carvalho Chehab static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg)
10279a0bf528SMauro Carvalho Chehab {
10289a0bf528SMauro Carvalho Chehab 	state->rf_ramp = cfg;
10299a0bf528SMauro Carvalho Chehab }
10309a0bf528SMauro Carvalho Chehab 
dib0090_set_rframp_pwm(struct dib0090_state * state,const u16 * cfg)10319a0bf528SMauro Carvalho Chehab static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg)
10329a0bf528SMauro Carvalho Chehab {
10339a0bf528SMauro Carvalho Chehab 	state->rf_ramp = cfg;
10349a0bf528SMauro Carvalho Chehab 
10359a0bf528SMauro Carvalho Chehab 	dib0090_write_reg(state, 0x2a, 0xffff);
10369a0bf528SMauro Carvalho Chehab 
10374bd1a8ddSMauro Carvalho Chehab 	dprintk("total RF gain: %ddB, step: %d\n", (u32) cfg[0], dib0090_read_reg(state, 0x2a));
10389a0bf528SMauro Carvalho Chehab 
10399a0bf528SMauro Carvalho Chehab 	dib0090_write_regs(state, 0x2c, cfg + 3, 6);
10409a0bf528SMauro Carvalho Chehab 	dib0090_write_regs(state, 0x3e, cfg + 9, 2);
10419a0bf528SMauro Carvalho Chehab }
10429a0bf528SMauro Carvalho Chehab 
dib0090_set_bbramp(struct dib0090_state * state,const u16 * cfg)10439a0bf528SMauro Carvalho Chehab static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg)
10449a0bf528SMauro Carvalho Chehab {
10459a0bf528SMauro Carvalho Chehab 	state->bb_ramp = cfg;
10469a0bf528SMauro Carvalho Chehab 	dib0090_set_boost(state, cfg[0] > 500);	/* we want the boost if the gain is higher that 50dB */
10479a0bf528SMauro Carvalho Chehab }
10489a0bf528SMauro Carvalho Chehab 
dib0090_set_bbramp_pwm(struct dib0090_state * state,const u16 * cfg)10499a0bf528SMauro Carvalho Chehab static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
10509a0bf528SMauro Carvalho Chehab {
10519a0bf528SMauro Carvalho Chehab 	state->bb_ramp = cfg;
10529a0bf528SMauro Carvalho Chehab 
10539a0bf528SMauro Carvalho Chehab 	dib0090_set_boost(state, cfg[0] > 500);	/* we want the boost if the gain is higher that 50dB */
10549a0bf528SMauro Carvalho Chehab 
10559a0bf528SMauro Carvalho Chehab 	dib0090_write_reg(state, 0x33, 0xffff);
10564bd1a8ddSMauro Carvalho Chehab 	dprintk("total BB gain: %ddB, step: %d\n", (u32) cfg[0], dib0090_read_reg(state, 0x33));
10579a0bf528SMauro Carvalho Chehab 	dib0090_write_regs(state, 0x35, cfg + 3, 4);
10589a0bf528SMauro Carvalho Chehab }
10599a0bf528SMauro Carvalho Chehab 
dib0090_pwm_gain_reset(struct dvb_frontend * fe)10609a0bf528SMauro Carvalho Chehab void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
10619a0bf528SMauro Carvalho Chehab {
10629a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
10636c0943cdSHans Verkuil 	const u16 *bb_ramp = bb_ramp_pwm_normal; /* default baseband config */
10646c0943cdSHans Verkuil 	const u16 *rf_ramp = NULL;
1065aedabf7aSOlivier Grenie 	u8 en_pwm_rf_mux = 1;
10669a0bf528SMauro Carvalho Chehab 
1067aedabf7aSOlivier Grenie 	/* reset the AGC */
10689a0bf528SMauro Carvalho Chehab 	if (state->config->use_pwm_agc) {
10699a0bf528SMauro Carvalho Chehab 		if (state->current_band == BAND_CBAND) {
10709a0bf528SMauro Carvalho Chehab 			if (state->identity.in_soc) {
10716c0943cdSHans Verkuil 				bb_ramp = bb_ramp_pwm_normal_socs;
10729a0bf528SMauro Carvalho Chehab 				if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
10736c0943cdSHans Verkuil 					rf_ramp = rf_ramp_pwm_cband_8090;
1074aedabf7aSOlivier Grenie 				else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) {
10759a0bf528SMauro Carvalho Chehab 					if (state->config->is_dib7090e) {
10769a0bf528SMauro Carvalho Chehab 						if (state->rf_ramp == NULL)
10776c0943cdSHans Verkuil 							rf_ramp = rf_ramp_pwm_cband_7090e_sensitivity;
10789a0bf528SMauro Carvalho Chehab 						else
10796c0943cdSHans Verkuil 							rf_ramp = state->rf_ramp;
10809a0bf528SMauro Carvalho Chehab 					} else
10816c0943cdSHans Verkuil 						rf_ramp = rf_ramp_pwm_cband_7090p;
10829a0bf528SMauro Carvalho Chehab 				}
10839a0bf528SMauro Carvalho Chehab 			} else
10846c0943cdSHans Verkuil 				rf_ramp = rf_ramp_pwm_cband;
1085aedabf7aSOlivier Grenie 		} else
1086aedabf7aSOlivier Grenie 
10879a0bf528SMauro Carvalho Chehab 			if (state->current_band == BAND_VHF) {
10889a0bf528SMauro Carvalho Chehab 				if (state->identity.in_soc) {
10896c0943cdSHans Verkuil 					bb_ramp = bb_ramp_pwm_normal_socs;
1090aedabf7aSOlivier Grenie 					/* rf_ramp = &rf_ramp_pwm_vhf_socs; */ /* TODO */
10919a0bf528SMauro Carvalho Chehab 				} else
10926c0943cdSHans Verkuil 					rf_ramp = rf_ramp_pwm_vhf;
1093aedabf7aSOlivier Grenie 			} else if (state->current_band == BAND_UHF) {
10949a0bf528SMauro Carvalho Chehab 				if (state->identity.in_soc) {
10956c0943cdSHans Verkuil 					bb_ramp = bb_ramp_pwm_normal_socs;
10969a0bf528SMauro Carvalho Chehab 					if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
10976c0943cdSHans Verkuil 						rf_ramp = rf_ramp_pwm_uhf_8090;
10989a0bf528SMauro Carvalho Chehab 					else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
10996c0943cdSHans Verkuil 						rf_ramp = rf_ramp_pwm_uhf_7090;
1100aedabf7aSOlivier Grenie 				} else
11016c0943cdSHans Verkuil 					rf_ramp = rf_ramp_pwm_uhf;
11029a0bf528SMauro Carvalho Chehab 			}
1103aedabf7aSOlivier Grenie 		if (rf_ramp)
1104aedabf7aSOlivier Grenie 			dib0090_set_rframp_pwm(state, rf_ramp);
1105aedabf7aSOlivier Grenie 		dib0090_set_bbramp_pwm(state, bb_ramp);
11069a0bf528SMauro Carvalho Chehab 
1107aedabf7aSOlivier Grenie 		/* activate the ramp generator using PWM control */
110857bcbde9SMauro Carvalho Chehab 		if (state->rf_ramp)
11094bd1a8ddSMauro Carvalho Chehab 			dprintk("ramp RF gain = %d BAND = %s version = %d\n",
1110e76bea9aSMauro Carvalho Chehab 				state->rf_ramp[0],
1111e76bea9aSMauro Carvalho Chehab 				(state->current_band == BAND_CBAND) ? "CBAND" : "NOT CBAND",
1112e76bea9aSMauro Carvalho Chehab 				state->identity.version & 0x1f);
1113aedabf7aSOlivier Grenie 
11145848adbeSHans Verkuil 		if (rf_ramp && ((state->rf_ramp && state->rf_ramp[0] == 0) ||
1115e76bea9aSMauro Carvalho Chehab 		    (state->current_band == BAND_CBAND &&
1116e76bea9aSMauro Carvalho Chehab 		    (state->identity.version & 0x1f) <= P1D_E_F))) {
11174bd1a8ddSMauro Carvalho Chehab 			dprintk("DE-Engage mux for direct gain reg control\n");
1118aedabf7aSOlivier Grenie 			en_pwm_rf_mux = 0;
1119aedabf7aSOlivier Grenie 		} else
11204bd1a8ddSMauro Carvalho Chehab 			dprintk("Engage mux for PWM control\n");
1121aedabf7aSOlivier Grenie 
1122aedabf7aSOlivier Grenie 		dib0090_write_reg(state, 0x32, (en_pwm_rf_mux << 12) | (en_pwm_rf_mux << 11));
1123aedabf7aSOlivier Grenie 
1124aedabf7aSOlivier Grenie 		/* Set fast servo cutoff to start AGC; 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast*/
1125aedabf7aSOlivier Grenie 		if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
1126aedabf7aSOlivier Grenie 			dib0090_write_reg(state, 0x04, 3);
11279a0bf528SMauro Carvalho Chehab 		else
1128aedabf7aSOlivier Grenie 			dib0090_write_reg(state, 0x04, 1);
1129aedabf7aSOlivier Grenie 		dib0090_write_reg(state, 0x39, (1 << 10)); /* 0 gain by default */
11309a0bf528SMauro Carvalho Chehab 	}
11319a0bf528SMauro Carvalho Chehab }
11329a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib0090_pwm_gain_reset);
11339a0bf528SMauro Carvalho Chehab 
dib0090_set_dc_servo(struct dvb_frontend * fe,u8 DC_servo_cutoff)11349a0bf528SMauro Carvalho Chehab void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff)
11359a0bf528SMauro Carvalho Chehab {
11369a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
11379a0bf528SMauro Carvalho Chehab 	if (DC_servo_cutoff < 4)
11389a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x04, DC_servo_cutoff);
11399a0bf528SMauro Carvalho Chehab }
11409a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib0090_set_dc_servo);
11419a0bf528SMauro Carvalho Chehab 
dib0090_get_slow_adc_val(struct dib0090_state * state)11429a0bf528SMauro Carvalho Chehab static u32 dib0090_get_slow_adc_val(struct dib0090_state *state)
11439a0bf528SMauro Carvalho Chehab {
11449a0bf528SMauro Carvalho Chehab 	u16 adc_val = dib0090_read_reg(state, 0x1d);
11459a0bf528SMauro Carvalho Chehab 	if (state->identity.in_soc)
11469a0bf528SMauro Carvalho Chehab 		adc_val >>= 2;
11479a0bf528SMauro Carvalho Chehab 	return adc_val;
11489a0bf528SMauro Carvalho Chehab }
11499a0bf528SMauro Carvalho Chehab 
dib0090_gain_control(struct dvb_frontend * fe)11509a0bf528SMauro Carvalho Chehab int dib0090_gain_control(struct dvb_frontend *fe)
11519a0bf528SMauro Carvalho Chehab {
11529a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
11539a0bf528SMauro Carvalho Chehab 	enum frontend_tune_state *tune_state = &state->tune_state;
11549a0bf528SMauro Carvalho Chehab 	int ret = 10;
11559a0bf528SMauro Carvalho Chehab 
11569a0bf528SMauro Carvalho Chehab 	u16 wbd_val = 0;
11579a0bf528SMauro Carvalho Chehab 	u8 apply_gain_immediatly = 1;
11589a0bf528SMauro Carvalho Chehab 	s16 wbd_error = 0, adc_error = 0;
11599a0bf528SMauro Carvalho Chehab 
11609a0bf528SMauro Carvalho Chehab 	if (*tune_state == CT_AGC_START) {
11619a0bf528SMauro Carvalho Chehab 		state->agc_freeze = 0;
11629a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x04, 0x0);
11639a0bf528SMauro Carvalho Chehab 
11649a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_SBAND
11659a0bf528SMauro Carvalho Chehab 		if (state->current_band == BAND_SBAND) {
11669a0bf528SMauro Carvalho Chehab 			dib0090_set_rframp(state, rf_ramp_sband);
11679a0bf528SMauro Carvalho Chehab 			dib0090_set_bbramp(state, bb_ramp_boost);
11689a0bf528SMauro Carvalho Chehab 		} else
11699a0bf528SMauro Carvalho Chehab #endif
11709a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_VHF
11719a0bf528SMauro Carvalho Chehab 		if (state->current_band == BAND_VHF && !state->identity.p1g) {
1172aedabf7aSOlivier Grenie 			dib0090_set_rframp(state, rf_ramp_pwm_vhf);
1173aedabf7aSOlivier Grenie 			dib0090_set_bbramp(state, bb_ramp_pwm_normal);
11749a0bf528SMauro Carvalho Chehab 		} else
11759a0bf528SMauro Carvalho Chehab #endif
11769a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_CBAND
11779a0bf528SMauro Carvalho Chehab 		if (state->current_band == BAND_CBAND && !state->identity.p1g) {
1178aedabf7aSOlivier Grenie 			dib0090_set_rframp(state, rf_ramp_pwm_cband);
1179aedabf7aSOlivier Grenie 			dib0090_set_bbramp(state, bb_ramp_pwm_normal);
11809a0bf528SMauro Carvalho Chehab 		} else
11819a0bf528SMauro Carvalho Chehab #endif
11829a0bf528SMauro Carvalho Chehab 		if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) {
1183aedabf7aSOlivier Grenie 			dib0090_set_rframp(state, rf_ramp_pwm_cband_7090p);
1184aedabf7aSOlivier Grenie 			dib0090_set_bbramp(state, bb_ramp_pwm_normal_socs);
11859a0bf528SMauro Carvalho Chehab 		} else {
1186aedabf7aSOlivier Grenie 			dib0090_set_rframp(state, rf_ramp_pwm_uhf);
1187aedabf7aSOlivier Grenie 			dib0090_set_bbramp(state, bb_ramp_pwm_normal);
11889a0bf528SMauro Carvalho Chehab 		}
11899a0bf528SMauro Carvalho Chehab 
11909a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x32, 0);
11919a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x39, 0);
11929a0bf528SMauro Carvalho Chehab 
11939a0bf528SMauro Carvalho Chehab 		dib0090_wbd_target(state, state->current_rf);
11949a0bf528SMauro Carvalho Chehab 
11959a0bf528SMauro Carvalho Chehab 		state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
11969a0bf528SMauro Carvalho Chehab 		state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA;
11979a0bf528SMauro Carvalho Chehab 
11989a0bf528SMauro Carvalho Chehab 		*tune_state = CT_AGC_STEP_0;
11999a0bf528SMauro Carvalho Chehab 	} else if (!state->agc_freeze) {
12009a0bf528SMauro Carvalho Chehab 		s16 wbd = 0, i, cnt;
12019a0bf528SMauro Carvalho Chehab 
12029a0bf528SMauro Carvalho Chehab 		int adc;
12039a0bf528SMauro Carvalho Chehab 		wbd_val = dib0090_get_slow_adc_val(state);
12049a0bf528SMauro Carvalho Chehab 
12059a0bf528SMauro Carvalho Chehab 		if (*tune_state == CT_AGC_STEP_0)
12069a0bf528SMauro Carvalho Chehab 			cnt = 5;
12079a0bf528SMauro Carvalho Chehab 		else
12089a0bf528SMauro Carvalho Chehab 			cnt = 1;
12099a0bf528SMauro Carvalho Chehab 
12109a0bf528SMauro Carvalho Chehab 		for (i = 0; i < cnt; i++) {
12119a0bf528SMauro Carvalho Chehab 			wbd_val = dib0090_get_slow_adc_val(state);
12129a0bf528SMauro Carvalho Chehab 			wbd += dib0090_wbd_to_db(state, wbd_val);
12139a0bf528SMauro Carvalho Chehab 		}
12149a0bf528SMauro Carvalho Chehab 		wbd /= cnt;
12159a0bf528SMauro Carvalho Chehab 		wbd_error = state->wbd_target - wbd;
12169a0bf528SMauro Carvalho Chehab 
12179a0bf528SMauro Carvalho Chehab 		if (*tune_state == CT_AGC_STEP_0) {
12189a0bf528SMauro Carvalho Chehab 			if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) {
12199a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_CBAND
12209a0bf528SMauro Carvalho Chehab 				/* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */
12219a0bf528SMauro Carvalho Chehab 				u8 ltg2 = (state->rf_lt_def >> 10) & 0x7;
12229a0bf528SMauro Carvalho Chehab 				if (state->current_band == BAND_CBAND && ltg2) {
12239a0bf528SMauro Carvalho Chehab 					ltg2 >>= 1;
12249a0bf528SMauro Carvalho Chehab 					state->rf_lt_def &= ltg2 << 10;	/* reduce in 3 steps from 7 to 0 */
12259a0bf528SMauro Carvalho Chehab 				}
12269a0bf528SMauro Carvalho Chehab #endif
12279a0bf528SMauro Carvalho Chehab 			} else {
12289a0bf528SMauro Carvalho Chehab 				state->agc_step = 0;
12299a0bf528SMauro Carvalho Chehab 				*tune_state = CT_AGC_STEP_1;
12309a0bf528SMauro Carvalho Chehab 			}
12319a0bf528SMauro Carvalho Chehab 		} else {
12329a0bf528SMauro Carvalho Chehab 			/* calc the adc power */
12339a0bf528SMauro Carvalho Chehab 			adc = state->config->get_adc_power(fe);
12349a0bf528SMauro Carvalho Chehab 			adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21;	/* included in [0:-700] */
12359a0bf528SMauro Carvalho Chehab 
12369a0bf528SMauro Carvalho Chehab 			adc_error = (s16) (((s32) ADC_TARGET) - adc);
12379a0bf528SMauro Carvalho Chehab #ifdef CONFIG_STANDARD_DAB
12389a0bf528SMauro Carvalho Chehab 			if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB)
12399a0bf528SMauro Carvalho Chehab 				adc_error -= 10;
12409a0bf528SMauro Carvalho Chehab #endif
12419a0bf528SMauro Carvalho Chehab #ifdef CONFIG_STANDARD_DVBT
12429a0bf528SMauro Carvalho Chehab 			if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT &&
12439a0bf528SMauro Carvalho Chehab 					(state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16))
12449a0bf528SMauro Carvalho Chehab 				adc_error += 60;
12459a0bf528SMauro Carvalho Chehab #endif
12469a0bf528SMauro Carvalho Chehab #ifdef CONFIG_SYS_ISDBT
12479a0bf528SMauro Carvalho Chehab 			if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) && (((state->fe->dtv_property_cache.layer[0].segment_count >
12489a0bf528SMauro Carvalho Chehab 								0)
12499a0bf528SMauro Carvalho Chehab 							&&
12509a0bf528SMauro Carvalho Chehab 							((state->fe->dtv_property_cache.layer[0].modulation ==
12519a0bf528SMauro Carvalho Chehab 							  QAM_64)
12529a0bf528SMauro Carvalho Chehab 							 || (state->fe->dtv_property_cache.
12539a0bf528SMauro Carvalho Chehab 								 layer[0].modulation == QAM_16)))
12549a0bf528SMauro Carvalho Chehab 						||
12559a0bf528SMauro Carvalho Chehab 						((state->fe->dtv_property_cache.layer[1].segment_count >
12569a0bf528SMauro Carvalho Chehab 						  0)
12579a0bf528SMauro Carvalho Chehab 						 &&
12589a0bf528SMauro Carvalho Chehab 						 ((state->fe->dtv_property_cache.layer[1].modulation ==
12599a0bf528SMauro Carvalho Chehab 						   QAM_64)
12609a0bf528SMauro Carvalho Chehab 						  || (state->fe->dtv_property_cache.
12619a0bf528SMauro Carvalho Chehab 							  layer[1].modulation == QAM_16)))
12629a0bf528SMauro Carvalho Chehab 						||
12639a0bf528SMauro Carvalho Chehab 						((state->fe->dtv_property_cache.layer[2].segment_count >
12649a0bf528SMauro Carvalho Chehab 						  0)
12659a0bf528SMauro Carvalho Chehab 						 &&
12669a0bf528SMauro Carvalho Chehab 						 ((state->fe->dtv_property_cache.layer[2].modulation ==
12679a0bf528SMauro Carvalho Chehab 						   QAM_64)
12689a0bf528SMauro Carvalho Chehab 						  || (state->fe->dtv_property_cache.
12699a0bf528SMauro Carvalho Chehab 							  layer[2].modulation == QAM_16)))
12709a0bf528SMauro Carvalho Chehab 						)
12719a0bf528SMauro Carvalho Chehab 				)
12729a0bf528SMauro Carvalho Chehab 				adc_error += 60;
12739a0bf528SMauro Carvalho Chehab #endif
12749a0bf528SMauro Carvalho Chehab 
12759a0bf528SMauro Carvalho Chehab 			if (*tune_state == CT_AGC_STEP_1) {	/* quickly go to the correct range of the ADC power */
12767aa92c42SDan Gopstein 				if (abs(adc_error) < 50 || state->agc_step++ > 5) {
12779a0bf528SMauro Carvalho Chehab 
12789a0bf528SMauro Carvalho Chehab #ifdef CONFIG_STANDARD_DAB
12799a0bf528SMauro Carvalho Chehab 					if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) {
12809a0bf528SMauro Carvalho Chehab 						dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63));	/* cap value = 63 : narrow BB filter : Fc = 1.8MHz */
12819a0bf528SMauro Carvalho Chehab 						dib0090_write_reg(state, 0x04, 0x0);
12829a0bf528SMauro Carvalho Chehab 					} else
12839a0bf528SMauro Carvalho Chehab #endif
12849a0bf528SMauro Carvalho Chehab 					{
12859a0bf528SMauro Carvalho Chehab 						dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32));
12869a0bf528SMauro Carvalho Chehab 						dib0090_write_reg(state, 0x04, 0x01);	/*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */
12879a0bf528SMauro Carvalho Chehab 					}
12889a0bf528SMauro Carvalho Chehab 
12899a0bf528SMauro Carvalho Chehab 					*tune_state = CT_AGC_STOP;
12909a0bf528SMauro Carvalho Chehab 				}
12919a0bf528SMauro Carvalho Chehab 			} else {
12929a0bf528SMauro Carvalho Chehab 				/* everything higher than or equal to CT_AGC_STOP means tracking */
12939a0bf528SMauro Carvalho Chehab 				ret = 100;	/* 10ms interval */
12949a0bf528SMauro Carvalho Chehab 				apply_gain_immediatly = 0;
12959a0bf528SMauro Carvalho Chehab 			}
12969a0bf528SMauro Carvalho Chehab 		}
12979a0bf528SMauro Carvalho Chehab #ifdef DEBUG_AGC
12989a0bf528SMauro Carvalho Chehab 		dprintk
12999a0bf528SMauro Carvalho Chehab 			("tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm",
13009a0bf528SMauro Carvalho Chehab 			 (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val,
13019a0bf528SMauro Carvalho Chehab 			 (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA));
13029a0bf528SMauro Carvalho Chehab #endif
13039a0bf528SMauro Carvalho Chehab 	}
13049a0bf528SMauro Carvalho Chehab 
13059a0bf528SMauro Carvalho Chehab 	/* apply gain */
13069a0bf528SMauro Carvalho Chehab 	if (!state->agc_freeze)
13079a0bf528SMauro Carvalho Chehab 		dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly);
13089a0bf528SMauro Carvalho Chehab 	return ret;
13099a0bf528SMauro Carvalho Chehab }
13109a0bf528SMauro Carvalho Chehab 
13119a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib0090_gain_control);
13129a0bf528SMauro Carvalho Chehab 
dib0090_get_current_gain(struct dvb_frontend * fe,u16 * rf,u16 * bb,u16 * rf_gain_limit,u16 * rflt)13139a0bf528SMauro Carvalho Chehab void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
13149a0bf528SMauro Carvalho Chehab {
13159a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
13169a0bf528SMauro Carvalho Chehab 	if (rf)
13179a0bf528SMauro Carvalho Chehab 		*rf = state->gain[0];
13189a0bf528SMauro Carvalho Chehab 	if (bb)
13199a0bf528SMauro Carvalho Chehab 		*bb = state->gain[1];
13209a0bf528SMauro Carvalho Chehab 	if (rf_gain_limit)
13219a0bf528SMauro Carvalho Chehab 		*rf_gain_limit = state->rf_gain_limit;
13229a0bf528SMauro Carvalho Chehab 	if (rflt)
13239a0bf528SMauro Carvalho Chehab 		*rflt = (state->rf_lt_def >> 10) & 0x7;
13249a0bf528SMauro Carvalho Chehab }
13259a0bf528SMauro Carvalho Chehab 
13269a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib0090_get_current_gain);
13279a0bf528SMauro Carvalho Chehab 
dib0090_get_wbd_target(struct dvb_frontend * fe)13289a0bf528SMauro Carvalho Chehab u16 dib0090_get_wbd_target(struct dvb_frontend *fe)
13299a0bf528SMauro Carvalho Chehab {
13309a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
13319a0bf528SMauro Carvalho Chehab 	u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000;
13329a0bf528SMauro Carvalho Chehab 	s32 current_temp = state->temperature;
13339a0bf528SMauro Carvalho Chehab 	s32 wbd_thot, wbd_tcold;
13349a0bf528SMauro Carvalho Chehab 	const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
13359a0bf528SMauro Carvalho Chehab 
13369a0bf528SMauro Carvalho Chehab 	while (f_MHz > wbd->max_freq)
13379a0bf528SMauro Carvalho Chehab 		wbd++;
13389a0bf528SMauro Carvalho Chehab 
13394bd1a8ddSMauro Carvalho Chehab 	dprintk("using wbd-table-entry with max freq %d\n", wbd->max_freq);
13409a0bf528SMauro Carvalho Chehab 
13419a0bf528SMauro Carvalho Chehab 	if (current_temp < 0)
13429a0bf528SMauro Carvalho Chehab 		current_temp = 0;
13439a0bf528SMauro Carvalho Chehab 	if (current_temp > 128)
13449a0bf528SMauro Carvalho Chehab 		current_temp = 128;
13459a0bf528SMauro Carvalho Chehab 
13469a0bf528SMauro Carvalho Chehab 	state->wbdmux &= ~(7 << 13);
13479a0bf528SMauro Carvalho Chehab 	if (wbd->wbd_gain != 0)
13489a0bf528SMauro Carvalho Chehab 		state->wbdmux |= (wbd->wbd_gain << 13);
13499a0bf528SMauro Carvalho Chehab 	else
13509a0bf528SMauro Carvalho Chehab 		state->wbdmux |= (4 << 13);
13519a0bf528SMauro Carvalho Chehab 
13529a0bf528SMauro Carvalho Chehab 	dib0090_write_reg(state, 0x10, state->wbdmux);
13539a0bf528SMauro Carvalho Chehab 
13549a0bf528SMauro Carvalho Chehab 	wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6);
13559a0bf528SMauro Carvalho Chehab 	wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6);
13569a0bf528SMauro Carvalho Chehab 
13579a0bf528SMauro Carvalho Chehab 	wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7;
13589a0bf528SMauro Carvalho Chehab 
13599a0bf528SMauro Carvalho Chehab 	state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold);
13604bd1a8ddSMauro Carvalho Chehab 	dprintk("wbd-target: %d dB\n", (u32) state->wbd_target);
13614bd1a8ddSMauro Carvalho Chehab 	dprintk("wbd offset applied is %d\n", wbd_tcold);
13629a0bf528SMauro Carvalho Chehab 
13639a0bf528SMauro Carvalho Chehab 	return state->wbd_offset + wbd_tcold;
13649a0bf528SMauro Carvalho Chehab }
13659a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib0090_get_wbd_target);
13669a0bf528SMauro Carvalho Chehab 
dib0090_get_wbd_offset(struct dvb_frontend * fe)13679a0bf528SMauro Carvalho Chehab u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
13689a0bf528SMauro Carvalho Chehab {
13699a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
13709a0bf528SMauro Carvalho Chehab 	return state->wbd_offset;
13719a0bf528SMauro Carvalho Chehab }
13729a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib0090_get_wbd_offset);
13739a0bf528SMauro Carvalho Chehab 
dib0090_set_switch(struct dvb_frontend * fe,u8 sw1,u8 sw2,u8 sw3)13749a0bf528SMauro Carvalho Chehab int dib0090_set_switch(struct dvb_frontend *fe, u8 sw1, u8 sw2, u8 sw3)
13759a0bf528SMauro Carvalho Chehab {
13769a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
13779a0bf528SMauro Carvalho Chehab 
13789a0bf528SMauro Carvalho Chehab 	dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xfff8)
13799a0bf528SMauro Carvalho Chehab 			| ((sw3 & 1) << 2) | ((sw2 & 1) << 1) | (sw1 & 1));
13809a0bf528SMauro Carvalho Chehab 
13819a0bf528SMauro Carvalho Chehab 	return 0;
13829a0bf528SMauro Carvalho Chehab }
13839a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib0090_set_switch);
13849a0bf528SMauro Carvalho Chehab 
dib0090_set_vga(struct dvb_frontend * fe,u8 onoff)13859a0bf528SMauro Carvalho Chehab int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff)
13869a0bf528SMauro Carvalho Chehab {
13879a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
13889a0bf528SMauro Carvalho Chehab 
13899a0bf528SMauro Carvalho Chehab 	dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x7fff)
13909a0bf528SMauro Carvalho Chehab 			| ((onoff & 1) << 15));
13919a0bf528SMauro Carvalho Chehab 	return 0;
13929a0bf528SMauro Carvalho Chehab }
13939a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib0090_set_vga);
13949a0bf528SMauro Carvalho Chehab 
dib0090_update_rframp_7090(struct dvb_frontend * fe,u8 cfg_sensitivity)13959a0bf528SMauro Carvalho Chehab int dib0090_update_rframp_7090(struct dvb_frontend *fe, u8 cfg_sensitivity)
13969a0bf528SMauro Carvalho Chehab {
13979a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
13989a0bf528SMauro Carvalho Chehab 
13999a0bf528SMauro Carvalho Chehab 	if ((!state->identity.p1g) || (!state->identity.in_soc)
14009a0bf528SMauro Carvalho Chehab 			|| ((state->identity.version != SOC_7090_P1G_21R1)
14019a0bf528SMauro Carvalho Chehab 				&& (state->identity.version != SOC_7090_P1G_11R1))) {
14024bd1a8ddSMauro Carvalho Chehab 		dprintk("%s() function can only be used for dib7090P\n", __func__);
14039a0bf528SMauro Carvalho Chehab 		return -ENODEV;
14049a0bf528SMauro Carvalho Chehab 	}
14059a0bf528SMauro Carvalho Chehab 
14069a0bf528SMauro Carvalho Chehab 	if (cfg_sensitivity)
14076c0943cdSHans Verkuil 		state->rf_ramp = rf_ramp_pwm_cband_7090e_sensitivity;
14089a0bf528SMauro Carvalho Chehab 	else
14096c0943cdSHans Verkuil 		state->rf_ramp = rf_ramp_pwm_cband_7090e_aci;
14109a0bf528SMauro Carvalho Chehab 	dib0090_pwm_gain_reset(fe);
14119a0bf528SMauro Carvalho Chehab 
14129a0bf528SMauro Carvalho Chehab 	return 0;
14139a0bf528SMauro Carvalho Chehab }
14149a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib0090_update_rframp_7090);
14159a0bf528SMauro Carvalho Chehab 
14169a0bf528SMauro Carvalho Chehab static const u16 dib0090_defaults[] = {
14179a0bf528SMauro Carvalho Chehab 
14189a0bf528SMauro Carvalho Chehab 	25, 0x01,
14199a0bf528SMauro Carvalho Chehab 	0x0000,
14209a0bf528SMauro Carvalho Chehab 	0x99a0,
14219a0bf528SMauro Carvalho Chehab 	0x6008,
14229a0bf528SMauro Carvalho Chehab 	0x0000,
14239a0bf528SMauro Carvalho Chehab 	0x8bcb,
14249a0bf528SMauro Carvalho Chehab 	0x0000,
14259a0bf528SMauro Carvalho Chehab 	0x0405,
14269a0bf528SMauro Carvalho Chehab 	0x0000,
14279a0bf528SMauro Carvalho Chehab 	0x0000,
14289a0bf528SMauro Carvalho Chehab 	0x0000,
14299a0bf528SMauro Carvalho Chehab 	0xb802,
14309a0bf528SMauro Carvalho Chehab 	0x0300,
14319a0bf528SMauro Carvalho Chehab 	0x2d12,
14329a0bf528SMauro Carvalho Chehab 	0xbac0,
14339a0bf528SMauro Carvalho Chehab 	0x7c00,
14349a0bf528SMauro Carvalho Chehab 	0xdbb9,
14359a0bf528SMauro Carvalho Chehab 	0x0954,
14369a0bf528SMauro Carvalho Chehab 	0x0743,
14379a0bf528SMauro Carvalho Chehab 	0x8000,
14389a0bf528SMauro Carvalho Chehab 	0x0001,
14399a0bf528SMauro Carvalho Chehab 	0x0040,
14409a0bf528SMauro Carvalho Chehab 	0x0100,
14419a0bf528SMauro Carvalho Chehab 	0x0000,
14429a0bf528SMauro Carvalho Chehab 	0xe910,
14439a0bf528SMauro Carvalho Chehab 	0x149e,
14449a0bf528SMauro Carvalho Chehab 
14459a0bf528SMauro Carvalho Chehab 	1, 0x1c,
14469a0bf528SMauro Carvalho Chehab 	0xff2d,
14479a0bf528SMauro Carvalho Chehab 
14489a0bf528SMauro Carvalho Chehab 	1, 0x39,
14499a0bf528SMauro Carvalho Chehab 	0x0000,
14509a0bf528SMauro Carvalho Chehab 
14519a0bf528SMauro Carvalho Chehab 	2, 0x1e,
14529a0bf528SMauro Carvalho Chehab 	0x07FF,
14539a0bf528SMauro Carvalho Chehab 	0x0007,
14549a0bf528SMauro Carvalho Chehab 
14559a0bf528SMauro Carvalho Chehab 	1, 0x24,
14569a0bf528SMauro Carvalho Chehab 	EN_UHF | EN_CRYSTAL,
14579a0bf528SMauro Carvalho Chehab 
14589a0bf528SMauro Carvalho Chehab 	2, 0x3c,
14599a0bf528SMauro Carvalho Chehab 	0x3ff,
14609a0bf528SMauro Carvalho Chehab 	0x111,
14619a0bf528SMauro Carvalho Chehab 	0
14629a0bf528SMauro Carvalho Chehab };
14639a0bf528SMauro Carvalho Chehab 
14649a0bf528SMauro Carvalho Chehab static const u16 dib0090_p1g_additionnal_defaults[] = {
14659a0bf528SMauro Carvalho Chehab 	1, 0x05,
14669a0bf528SMauro Carvalho Chehab 	0xabcd,
14679a0bf528SMauro Carvalho Chehab 
14689a0bf528SMauro Carvalho Chehab 	1, 0x11,
14699a0bf528SMauro Carvalho Chehab 	0x00b4,
14709a0bf528SMauro Carvalho Chehab 
14719a0bf528SMauro Carvalho Chehab 	1, 0x1c,
14729a0bf528SMauro Carvalho Chehab 	0xfffd,
14739a0bf528SMauro Carvalho Chehab 
14749a0bf528SMauro Carvalho Chehab 	1, 0x40,
14759a0bf528SMauro Carvalho Chehab 	0x108,
14769a0bf528SMauro Carvalho Chehab 	0
14779a0bf528SMauro Carvalho Chehab };
14789a0bf528SMauro Carvalho Chehab 
dib0090_set_default_config(struct dib0090_state * state,const u16 * n)14799a0bf528SMauro Carvalho Chehab static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n)
14809a0bf528SMauro Carvalho Chehab {
14819a0bf528SMauro Carvalho Chehab 	u16 l, r;
14829a0bf528SMauro Carvalho Chehab 
14839a0bf528SMauro Carvalho Chehab 	l = pgm_read_word(n++);
14849a0bf528SMauro Carvalho Chehab 	while (l) {
14859a0bf528SMauro Carvalho Chehab 		r = pgm_read_word(n++);
14869a0bf528SMauro Carvalho Chehab 		do {
14879a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, r, pgm_read_word(n++));
14889a0bf528SMauro Carvalho Chehab 			r++;
14899a0bf528SMauro Carvalho Chehab 		} while (--l);
14909a0bf528SMauro Carvalho Chehab 		l = pgm_read_word(n++);
14919a0bf528SMauro Carvalho Chehab 	}
14929a0bf528SMauro Carvalho Chehab }
14939a0bf528SMauro Carvalho Chehab 
14949a0bf528SMauro Carvalho Chehab #define CAP_VALUE_MIN (u8)  9
14959a0bf528SMauro Carvalho Chehab #define CAP_VALUE_MAX (u8) 40
14969a0bf528SMauro Carvalho Chehab #define HR_MIN	      (u8) 25
14979a0bf528SMauro Carvalho Chehab #define HR_MAX	      (u8) 40
14989a0bf528SMauro Carvalho Chehab #define POLY_MIN      (u8)  0
14999a0bf528SMauro Carvalho Chehab #define POLY_MAX      (u8)  8
15009a0bf528SMauro Carvalho Chehab 
dib0090_set_EFUSE(struct dib0090_state * state)15019a0bf528SMauro Carvalho Chehab static void dib0090_set_EFUSE(struct dib0090_state *state)
15029a0bf528SMauro Carvalho Chehab {
15039a0bf528SMauro Carvalho Chehab 	u8 c, h, n;
15049a0bf528SMauro Carvalho Chehab 	u16 e2, e4;
15059a0bf528SMauro Carvalho Chehab 	u16 cal;
15069a0bf528SMauro Carvalho Chehab 
15079a0bf528SMauro Carvalho Chehab 	e2 = dib0090_read_reg(state, 0x26);
15089a0bf528SMauro Carvalho Chehab 	e4 = dib0090_read_reg(state, 0x28);
15099a0bf528SMauro Carvalho Chehab 
15109a0bf528SMauro Carvalho Chehab 	if ((state->identity.version == P1D_E_F) ||
15119a0bf528SMauro Carvalho Chehab 			(state->identity.version == P1G) || (e2 == 0xffff)) {
15129a0bf528SMauro Carvalho Chehab 
15139a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x22, 0x10);
15149a0bf528SMauro Carvalho Chehab 		cal = (dib0090_read_reg(state, 0x22) >> 6) & 0x3ff;
15159a0bf528SMauro Carvalho Chehab 
15169a0bf528SMauro Carvalho Chehab 		if ((cal < 670) || (cal == 1023))
15179a0bf528SMauro Carvalho Chehab 			cal = 850;
15189a0bf528SMauro Carvalho Chehab 		n = 165 - ((cal * 10)>>6) ;
15199a0bf528SMauro Carvalho Chehab 		e2 = e4 = (3<<12) | (34<<6) | (n);
15209a0bf528SMauro Carvalho Chehab 	}
15219a0bf528SMauro Carvalho Chehab 
15229a0bf528SMauro Carvalho Chehab 	if (e2 != e4)
15239a0bf528SMauro Carvalho Chehab 		e2 &= e4; /* Remove the redundancy  */
15249a0bf528SMauro Carvalho Chehab 
15259a0bf528SMauro Carvalho Chehab 	if (e2 != 0xffff) {
15269a0bf528SMauro Carvalho Chehab 		c = e2 & 0x3f;
15279a0bf528SMauro Carvalho Chehab 		n = (e2 >> 12) & 0xf;
15289a0bf528SMauro Carvalho Chehab 		h = (e2 >> 6) & 0x3f;
15299a0bf528SMauro Carvalho Chehab 
15309a0bf528SMauro Carvalho Chehab 		if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN))
15319a0bf528SMauro Carvalho Chehab 			c = 32;
1532aedabf7aSOlivier Grenie 		else
1533aedabf7aSOlivier Grenie 			c += 14;
15349a0bf528SMauro Carvalho Chehab 		if ((h >= HR_MAX) || (h <= HR_MIN))
15359a0bf528SMauro Carvalho Chehab 			h = 34;
15369a0bf528SMauro Carvalho Chehab 		if ((n >= POLY_MAX) || (n <= POLY_MIN))
15379a0bf528SMauro Carvalho Chehab 			n = 3;
15389a0bf528SMauro Carvalho Chehab 
15399a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x13, (h << 10));
1540aedabf7aSOlivier Grenie 		e2 = (n << 11) | ((h >> 2)<<6) | c;
15419a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x2, e2); /* Load the BB_2 */
15429a0bf528SMauro Carvalho Chehab 	}
15439a0bf528SMauro Carvalho Chehab }
15449a0bf528SMauro Carvalho Chehab 
dib0090_reset(struct dvb_frontend * fe)15459a0bf528SMauro Carvalho Chehab static int dib0090_reset(struct dvb_frontend *fe)
15469a0bf528SMauro Carvalho Chehab {
15479a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
15489a0bf528SMauro Carvalho Chehab 
15499a0bf528SMauro Carvalho Chehab 	dib0090_reset_digital(fe, state->config);
15509a0bf528SMauro Carvalho Chehab 	if (dib0090_identify(fe) < 0)
15519a0bf528SMauro Carvalho Chehab 		return -EIO;
15529a0bf528SMauro Carvalho Chehab 
15539a0bf528SMauro Carvalho Chehab #ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT
15549a0bf528SMauro Carvalho Chehab 	if (!(state->identity.version & 0x1))	/* it is P1B - reset is already done */
15559a0bf528SMauro Carvalho Chehab 		return 0;
15569a0bf528SMauro Carvalho Chehab #endif
15579a0bf528SMauro Carvalho Chehab 
15589a0bf528SMauro Carvalho Chehab 	if (!state->identity.in_soc) {
15599a0bf528SMauro Carvalho Chehab 		if ((dib0090_read_reg(state, 0x1a) >> 5) & 0x2)
15609a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, 0x1b, (EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL));
15619a0bf528SMauro Carvalho Chehab 		else
15629a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, 0x1b, (EN_DIGCLK | EN_PLL | EN_CRYSTAL));
15639a0bf528SMauro Carvalho Chehab 	}
15649a0bf528SMauro Carvalho Chehab 
15659a0bf528SMauro Carvalho Chehab 	dib0090_set_default_config(state, dib0090_defaults);
15669a0bf528SMauro Carvalho Chehab 
15679a0bf528SMauro Carvalho Chehab 	if (state->identity.in_soc)
15689a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x18, 0x2910);  /* charge pump current = 0 */
15699a0bf528SMauro Carvalho Chehab 
15709a0bf528SMauro Carvalho Chehab 	if (state->identity.p1g)
15719a0bf528SMauro Carvalho Chehab 		dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults);
15729a0bf528SMauro Carvalho Chehab 
15739a0bf528SMauro Carvalho Chehab 	/* Update the efuse : Only available for KROSUS > P1C  and SOC as well*/
15749a0bf528SMauro Carvalho Chehab 	if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc))
15759a0bf528SMauro Carvalho Chehab 		dib0090_set_EFUSE(state);
15769a0bf528SMauro Carvalho Chehab 
15779a0bf528SMauro Carvalho Chehab 	/* Congigure in function of the crystal */
15789a0bf528SMauro Carvalho Chehab 	if (state->config->force_crystal_mode != 0)
15799a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x14,
15809a0bf528SMauro Carvalho Chehab 				state->config->force_crystal_mode & 3);
15819a0bf528SMauro Carvalho Chehab 	else if (state->config->io.clock_khz >= 24000)
15829a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x14, 1);
15839a0bf528SMauro Carvalho Chehab 	else
15849a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x14, 2);
15854bd1a8ddSMauro Carvalho Chehab 	dprintk("Pll lock : %d\n", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1);
15869a0bf528SMauro Carvalho Chehab 
15879a0bf528SMauro Carvalho Chehab 	state->calibrate = DC_CAL | WBD_CAL | TEMP_CAL;	/* enable iq-offset-calibration and wbd-calibration when tuning next time */
15889a0bf528SMauro Carvalho Chehab 
15899a0bf528SMauro Carvalho Chehab 	return 0;
15909a0bf528SMauro Carvalho Chehab }
15919a0bf528SMauro Carvalho Chehab 
15929a0bf528SMauro Carvalho Chehab #define steps(u) (((u) > 15) ? ((u)-16) : (u))
15939a0bf528SMauro Carvalho Chehab #define INTERN_WAIT 10
dib0090_get_offset(struct dib0090_state * state,enum frontend_tune_state * tune_state)15949a0bf528SMauro Carvalho Chehab static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state)
15959a0bf528SMauro Carvalho Chehab {
15969a0bf528SMauro Carvalho Chehab 	int ret = INTERN_WAIT * 10;
15979a0bf528SMauro Carvalho Chehab 
15989a0bf528SMauro Carvalho Chehab 	switch (*tune_state) {
15999a0bf528SMauro Carvalho Chehab 	case CT_TUNER_STEP_2:
16009a0bf528SMauro Carvalho Chehab 		/* Turns to positive */
16019a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x1f, 0x7);
16029a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_STEP_3;
16039a0bf528SMauro Carvalho Chehab 		break;
16049a0bf528SMauro Carvalho Chehab 
16059a0bf528SMauro Carvalho Chehab 	case CT_TUNER_STEP_3:
16069a0bf528SMauro Carvalho Chehab 		state->adc_diff = dib0090_read_reg(state, 0x1d);
16079a0bf528SMauro Carvalho Chehab 
16089a0bf528SMauro Carvalho Chehab 		/* Turns to negative */
16099a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x1f, 0x4);
16109a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_STEP_4;
16119a0bf528SMauro Carvalho Chehab 		break;
16129a0bf528SMauro Carvalho Chehab 
16139a0bf528SMauro Carvalho Chehab 	case CT_TUNER_STEP_4:
16149a0bf528SMauro Carvalho Chehab 		state->adc_diff -= dib0090_read_reg(state, 0x1d);
16159a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_STEP_5;
16169a0bf528SMauro Carvalho Chehab 		ret = 0;
16179a0bf528SMauro Carvalho Chehab 		break;
16189a0bf528SMauro Carvalho Chehab 
16199a0bf528SMauro Carvalho Chehab 	default:
16209a0bf528SMauro Carvalho Chehab 		break;
16219a0bf528SMauro Carvalho Chehab 	}
16229a0bf528SMauro Carvalho Chehab 
16239a0bf528SMauro Carvalho Chehab 	return ret;
16249a0bf528SMauro Carvalho Chehab }
16259a0bf528SMauro Carvalho Chehab 
16269a0bf528SMauro Carvalho Chehab struct dc_calibration {
16279a0bf528SMauro Carvalho Chehab 	u8 addr;
16289a0bf528SMauro Carvalho Chehab 	u8 offset;
16299a0bf528SMauro Carvalho Chehab 	u8 pga:1;
16309a0bf528SMauro Carvalho Chehab 	u16 bb1;
16319a0bf528SMauro Carvalho Chehab 	u8 i:1;
16329a0bf528SMauro Carvalho Chehab };
16339a0bf528SMauro Carvalho Chehab 
16349a0bf528SMauro Carvalho Chehab static const struct dc_calibration dc_table[] = {
16359a0bf528SMauro Carvalho Chehab 	/* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
16369a0bf528SMauro Carvalho Chehab 	{0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1},
16379a0bf528SMauro Carvalho Chehab 	{0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0},
16389a0bf528SMauro Carvalho Chehab 	/* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
16399a0bf528SMauro Carvalho Chehab 	{0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1},
16409a0bf528SMauro Carvalho Chehab 	{0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0},
16419a0bf528SMauro Carvalho Chehab 	{0},
16429a0bf528SMauro Carvalho Chehab };
16439a0bf528SMauro Carvalho Chehab 
16449a0bf528SMauro Carvalho Chehab static const struct dc_calibration dc_p1g_table[] = {
16459a0bf528SMauro Carvalho Chehab 	/* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
16469a0bf528SMauro Carvalho Chehab 	/* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */
16479a0bf528SMauro Carvalho Chehab 	{0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1},
16489a0bf528SMauro Carvalho Chehab 	{0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0},
16499a0bf528SMauro Carvalho Chehab 	/* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
16509a0bf528SMauro Carvalho Chehab 	{0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1},
16519a0bf528SMauro Carvalho Chehab 	{0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0},
16529a0bf528SMauro Carvalho Chehab 	{0},
16539a0bf528SMauro Carvalho Chehab };
16549a0bf528SMauro Carvalho Chehab 
dib0090_set_trim(struct dib0090_state * state)16559a0bf528SMauro Carvalho Chehab static void dib0090_set_trim(struct dib0090_state *state)
16569a0bf528SMauro Carvalho Chehab {
16579a0bf528SMauro Carvalho Chehab 	u16 *val;
16589a0bf528SMauro Carvalho Chehab 
16599a0bf528SMauro Carvalho Chehab 	if (state->dc->addr == 0x07)
16609a0bf528SMauro Carvalho Chehab 		val = &state->bb7;
16619a0bf528SMauro Carvalho Chehab 	else
16629a0bf528SMauro Carvalho Chehab 		val = &state->bb6;
16639a0bf528SMauro Carvalho Chehab 
16649a0bf528SMauro Carvalho Chehab 	*val &= ~(0x1f << state->dc->offset);
16659a0bf528SMauro Carvalho Chehab 	*val |= state->step << state->dc->offset;
16669a0bf528SMauro Carvalho Chehab 
16679a0bf528SMauro Carvalho Chehab 	dib0090_write_reg(state, state->dc->addr, *val);
16689a0bf528SMauro Carvalho Chehab }
16699a0bf528SMauro Carvalho Chehab 
dib0090_dc_offset_calibration(struct dib0090_state * state,enum frontend_tune_state * tune_state)16709a0bf528SMauro Carvalho Chehab static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
16719a0bf528SMauro Carvalho Chehab {
16729a0bf528SMauro Carvalho Chehab 	int ret = 0;
16739a0bf528SMauro Carvalho Chehab 	u16 reg;
16749a0bf528SMauro Carvalho Chehab 
16759a0bf528SMauro Carvalho Chehab 	switch (*tune_state) {
16769a0bf528SMauro Carvalho Chehab 	case CT_TUNER_START:
16779a0bf528SMauro Carvalho Chehab 		dprintk("Start DC offset calibration");
16789a0bf528SMauro Carvalho Chehab 
16799a0bf528SMauro Carvalho Chehab 		/* force vcm2 = 0.8V */
16809a0bf528SMauro Carvalho Chehab 		state->bb6 = 0;
16819a0bf528SMauro Carvalho Chehab 		state->bb7 = 0x040d;
16829a0bf528SMauro Carvalho Chehab 
16839a0bf528SMauro Carvalho Chehab 		/* the LNA AND LO are off */
16849a0bf528SMauro Carvalho Chehab 		reg = dib0090_read_reg(state, 0x24) & 0x0ffb;	/* shutdown lna and lo */
16859a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x24, reg);
16869a0bf528SMauro Carvalho Chehab 
16879a0bf528SMauro Carvalho Chehab 		state->wbdmux = dib0090_read_reg(state, 0x10);
16889a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3);
16899a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
16909a0bf528SMauro Carvalho Chehab 
16919a0bf528SMauro Carvalho Chehab 		state->dc = dc_table;
16929a0bf528SMauro Carvalho Chehab 
16939a0bf528SMauro Carvalho Chehab 		if (state->identity.p1g)
16949a0bf528SMauro Carvalho Chehab 			state->dc = dc_p1g_table;
16959a0bf528SMauro Carvalho Chehab 
1696df561f66SGustavo A. R. Silva 		fallthrough;
16979a0bf528SMauro Carvalho Chehab 	case CT_TUNER_STEP_0:
16984bd1a8ddSMauro Carvalho Chehab 		dprintk("Start/continue DC calibration for %s path\n",
16994bd1a8ddSMauro Carvalho Chehab 			(state->dc->i == 1) ? "I" : "Q");
17009a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x01, state->dc->bb1);
17019a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7));
17029a0bf528SMauro Carvalho Chehab 
17039a0bf528SMauro Carvalho Chehab 		state->step = 0;
17049a0bf528SMauro Carvalho Chehab 		state->min_adc_diff = 1023;
17059a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_STEP_1;
17069a0bf528SMauro Carvalho Chehab 		ret = 50;
17079a0bf528SMauro Carvalho Chehab 		break;
17089a0bf528SMauro Carvalho Chehab 
17099a0bf528SMauro Carvalho Chehab 	case CT_TUNER_STEP_1:
17109a0bf528SMauro Carvalho Chehab 		dib0090_set_trim(state);
17119a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_STEP_2;
17129a0bf528SMauro Carvalho Chehab 		break;
17139a0bf528SMauro Carvalho Chehab 
17149a0bf528SMauro Carvalho Chehab 	case CT_TUNER_STEP_2:
17159a0bf528SMauro Carvalho Chehab 	case CT_TUNER_STEP_3:
17169a0bf528SMauro Carvalho Chehab 	case CT_TUNER_STEP_4:
17179a0bf528SMauro Carvalho Chehab 		ret = dib0090_get_offset(state, tune_state);
17189a0bf528SMauro Carvalho Chehab 		break;
17199a0bf528SMauro Carvalho Chehab 
17209a0bf528SMauro Carvalho Chehab 	case CT_TUNER_STEP_5:	/* found an offset */
17214bd1a8ddSMauro Carvalho Chehab 		dprintk("adc_diff = %d, current step= %d\n", (u32) state->adc_diff, state->step);
17229a0bf528SMauro Carvalho Chehab 		if (state->step == 0 && state->adc_diff < 0) {
17239a0bf528SMauro Carvalho Chehab 			state->min_adc_diff = -1023;
17244bd1a8ddSMauro Carvalho Chehab 			dprintk("Change of sign of the minimum adc diff\n");
17259a0bf528SMauro Carvalho Chehab 		}
17269a0bf528SMauro Carvalho Chehab 
17274bd1a8ddSMauro Carvalho Chehab 		dprintk("adc_diff = %d, min_adc_diff = %d current_step = %d\n", state->adc_diff, state->min_adc_diff, state->step);
17289a0bf528SMauro Carvalho Chehab 
17299a0bf528SMauro Carvalho Chehab 		/* first turn for this frequency */
17309a0bf528SMauro Carvalho Chehab 		if (state->step == 0) {
17319a0bf528SMauro Carvalho Chehab 			if (state->dc->pga && state->adc_diff < 0)
17329a0bf528SMauro Carvalho Chehab 				state->step = 0x10;
17339a0bf528SMauro Carvalho Chehab 			if (state->dc->pga == 0 && state->adc_diff > 0)
17349a0bf528SMauro Carvalho Chehab 				state->step = 0x10;
17359a0bf528SMauro Carvalho Chehab 		}
17369a0bf528SMauro Carvalho Chehab 
17379a0bf528SMauro Carvalho Chehab 		/* Look for a change of Sign in the Adc_diff.min_adc_diff is used to STORE the setp N-1 */
17389a0bf528SMauro Carvalho Chehab 		if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) {
17399a0bf528SMauro Carvalho Chehab 			/* stop search when the delta the sign is changing and Steps =15 and Step=0 is force for continuance */
17409a0bf528SMauro Carvalho Chehab 			state->step++;
17419a0bf528SMauro Carvalho Chehab 			state->min_adc_diff = state->adc_diff;
17429a0bf528SMauro Carvalho Chehab 			*tune_state = CT_TUNER_STEP_1;
17439a0bf528SMauro Carvalho Chehab 		} else {
17449a0bf528SMauro Carvalho Chehab 			/* the minimum was what we have seen in the step before */
17457aa92c42SDan Gopstein 			if (abs(state->adc_diff) > abs(state->min_adc_diff)) {
17464bd1a8ddSMauro Carvalho Chehab 				dprintk("Since adc_diff N = %d  > adc_diff step N-1 = %d, Come back one step\n", state->adc_diff, state->min_adc_diff);
17479a0bf528SMauro Carvalho Chehab 				state->step--;
17489a0bf528SMauro Carvalho Chehab 			}
17499a0bf528SMauro Carvalho Chehab 
17509a0bf528SMauro Carvalho Chehab 			dib0090_set_trim(state);
17519fcfae8aSSean Young 			dprintk("BB Offset Cal, BBreg=%u,Offset=%d,Value Set=%d\n",
17529fcfae8aSSean Young 				state->dc->addr, state->adc_diff, state->step);
17539a0bf528SMauro Carvalho Chehab 
17549a0bf528SMauro Carvalho Chehab 			state->dc++;
17559a0bf528SMauro Carvalho Chehab 			if (state->dc->addr == 0)	/* done */
17569a0bf528SMauro Carvalho Chehab 				*tune_state = CT_TUNER_STEP_6;
17579a0bf528SMauro Carvalho Chehab 			else
17589a0bf528SMauro Carvalho Chehab 				*tune_state = CT_TUNER_STEP_0;
17599a0bf528SMauro Carvalho Chehab 
17609a0bf528SMauro Carvalho Chehab 		}
17619a0bf528SMauro Carvalho Chehab 		break;
17629a0bf528SMauro Carvalho Chehab 
17639a0bf528SMauro Carvalho Chehab 	case CT_TUNER_STEP_6:
17649a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008);
17659a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x1f, 0x7);
17669a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_START;	/* reset done -> real tuning can now begin */
17679a0bf528SMauro Carvalho Chehab 		state->calibrate &= ~DC_CAL;
1768af7ab662SGustavo A. R. Silva 		break;
1769af7ab662SGustavo A. R. Silva 
17709a0bf528SMauro Carvalho Chehab 	default:
17719a0bf528SMauro Carvalho Chehab 		break;
17729a0bf528SMauro Carvalho Chehab 	}
17739a0bf528SMauro Carvalho Chehab 	return ret;
17749a0bf528SMauro Carvalho Chehab }
17759a0bf528SMauro Carvalho Chehab 
dib0090_wbd_calibration(struct dib0090_state * state,enum frontend_tune_state * tune_state)17769a0bf528SMauro Carvalho Chehab static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
17779a0bf528SMauro Carvalho Chehab {
17789a0bf528SMauro Carvalho Chehab 	u8 wbd_gain;
17799a0bf528SMauro Carvalho Chehab 	const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
17809a0bf528SMauro Carvalho Chehab 
17819a0bf528SMauro Carvalho Chehab 	switch (*tune_state) {
17829a0bf528SMauro Carvalho Chehab 	case CT_TUNER_START:
17839a0bf528SMauro Carvalho Chehab 		while (state->current_rf / 1000 > wbd->max_freq)
17849a0bf528SMauro Carvalho Chehab 			wbd++;
17859a0bf528SMauro Carvalho Chehab 		if (wbd->wbd_gain != 0)
17869a0bf528SMauro Carvalho Chehab 			wbd_gain = wbd->wbd_gain;
17879a0bf528SMauro Carvalho Chehab 		else {
17889a0bf528SMauro Carvalho Chehab 			wbd_gain = 4;
17899a0bf528SMauro Carvalho Chehab #if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND)
17909a0bf528SMauro Carvalho Chehab 			if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND))
17919a0bf528SMauro Carvalho Chehab 				wbd_gain = 2;
17929a0bf528SMauro Carvalho Chehab #endif
17939a0bf528SMauro Carvalho Chehab 		}
17949a0bf528SMauro Carvalho Chehab 
17959a0bf528SMauro Carvalho Chehab 		if (wbd_gain == state->wbd_calibration_gain) {	/* the WBD calibration has already been done */
17969a0bf528SMauro Carvalho Chehab 			*tune_state = CT_TUNER_START;
17979a0bf528SMauro Carvalho Chehab 			state->calibrate &= ~WBD_CAL;
17989a0bf528SMauro Carvalho Chehab 			return 0;
17999a0bf528SMauro Carvalho Chehab 		}
18009a0bf528SMauro Carvalho Chehab 
18019a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3));
18029a0bf528SMauro Carvalho Chehab 
18039a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1)));
18049a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_STEP_0;
18059a0bf528SMauro Carvalho Chehab 		state->wbd_calibration_gain = wbd_gain;
18069a0bf528SMauro Carvalho Chehab 		return 90;	/* wait for the WBDMUX to switch and for the ADC to sample */
18079a0bf528SMauro Carvalho Chehab 
18089a0bf528SMauro Carvalho Chehab 	case CT_TUNER_STEP_0:
18099a0bf528SMauro Carvalho Chehab 		state->wbd_offset = dib0090_get_slow_adc_val(state);
18104bd1a8ddSMauro Carvalho Chehab 		dprintk("WBD calibration offset = %d\n", state->wbd_offset);
18119a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_START;	/* reset done -> real tuning can now begin */
18129a0bf528SMauro Carvalho Chehab 		state->calibrate &= ~WBD_CAL;
18139a0bf528SMauro Carvalho Chehab 		break;
18149a0bf528SMauro Carvalho Chehab 
18159a0bf528SMauro Carvalho Chehab 	default:
18169a0bf528SMauro Carvalho Chehab 		break;
18179a0bf528SMauro Carvalho Chehab 	}
18189a0bf528SMauro Carvalho Chehab 	return 0;
18199a0bf528SMauro Carvalho Chehab }
18209a0bf528SMauro Carvalho Chehab 
dib0090_set_bandwidth(struct dib0090_state * state)18219a0bf528SMauro Carvalho Chehab static void dib0090_set_bandwidth(struct dib0090_state *state)
18229a0bf528SMauro Carvalho Chehab {
18239a0bf528SMauro Carvalho Chehab 	u16 tmp;
18249a0bf528SMauro Carvalho Chehab 
18259a0bf528SMauro Carvalho Chehab 	if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000)
18269a0bf528SMauro Carvalho Chehab 		tmp = (3 << 14);
18279a0bf528SMauro Carvalho Chehab 	else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000)
18289a0bf528SMauro Carvalho Chehab 		tmp = (2 << 14);
18299a0bf528SMauro Carvalho Chehab 	else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000)
18309a0bf528SMauro Carvalho Chehab 		tmp = (1 << 14);
18319a0bf528SMauro Carvalho Chehab 	else
18329a0bf528SMauro Carvalho Chehab 		tmp = (0 << 14);
18339a0bf528SMauro Carvalho Chehab 
18349a0bf528SMauro Carvalho Chehab 	state->bb_1_def &= 0x3fff;
18359a0bf528SMauro Carvalho Chehab 	state->bb_1_def |= tmp;
18369a0bf528SMauro Carvalho Chehab 
18379a0bf528SMauro Carvalho Chehab 	dib0090_write_reg(state, 0x01, state->bb_1_def);	/* be sure that we have the right bb-filter */
18389a0bf528SMauro Carvalho Chehab 
18399a0bf528SMauro Carvalho Chehab 	dib0090_write_reg(state, 0x03, 0x6008);	/* = 0x6008 : vcm3_trim = 1 ; filter2_gm1_trim = 8 ; filter2_cutoff_freq = 0 */
18409a0bf528SMauro Carvalho Chehab 	dib0090_write_reg(state, 0x04, 0x1);	/* 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast */
18419a0bf528SMauro Carvalho Chehab 	if (state->identity.in_soc) {
18429a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x05, 0x9bcf); /* attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 1 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 15 */
18439a0bf528SMauro Carvalho Chehab 	} else {
18449a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x02, (5 << 11) | (8 << 6) | (22 & 0x3f));	/* 22 = cap_value */
18459a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x05, 0xabcd);	/* = 0xabcd : attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 2 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 13 */
18469a0bf528SMauro Carvalho Chehab 	}
18479a0bf528SMauro Carvalho Chehab }
18489a0bf528SMauro Carvalho Chehab 
18499a0bf528SMauro Carvalho Chehab static const struct dib0090_pll dib0090_pll_table[] = {
18509a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_CBAND
18519a0bf528SMauro Carvalho Chehab 	{56000, 0, 9, 48, 6},
18529a0bf528SMauro Carvalho Chehab 	{70000, 1, 9, 48, 6},
18539a0bf528SMauro Carvalho Chehab 	{87000, 0, 8, 32, 4},
18549a0bf528SMauro Carvalho Chehab 	{105000, 1, 8, 32, 4},
18559a0bf528SMauro Carvalho Chehab 	{115000, 0, 7, 24, 6},
18569a0bf528SMauro Carvalho Chehab 	{140000, 1, 7, 24, 6},
18579a0bf528SMauro Carvalho Chehab 	{170000, 0, 6, 16, 4},
18589a0bf528SMauro Carvalho Chehab #endif
18599a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_VHF
18609a0bf528SMauro Carvalho Chehab 	{200000, 1, 6, 16, 4},
18619a0bf528SMauro Carvalho Chehab 	{230000, 0, 5, 12, 6},
18629a0bf528SMauro Carvalho Chehab 	{280000, 1, 5, 12, 6},
18639a0bf528SMauro Carvalho Chehab 	{340000, 0, 4, 8, 4},
18649a0bf528SMauro Carvalho Chehab 	{380000, 1, 4, 8, 4},
18659a0bf528SMauro Carvalho Chehab 	{450000, 0, 3, 6, 6},
18669a0bf528SMauro Carvalho Chehab #endif
18679a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_UHF
18689a0bf528SMauro Carvalho Chehab 	{580000, 1, 3, 6, 6},
18699a0bf528SMauro Carvalho Chehab 	{700000, 0, 2, 4, 4},
18709a0bf528SMauro Carvalho Chehab 	{860000, 1, 2, 4, 4},
18719a0bf528SMauro Carvalho Chehab #endif
18729a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_LBAND
18739a0bf528SMauro Carvalho Chehab 	{1800000, 1, 0, 2, 4},
18749a0bf528SMauro Carvalho Chehab #endif
18759a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_SBAND
18769a0bf528SMauro Carvalho Chehab 	{2900000, 0, 14, 1, 4},
18779a0bf528SMauro Carvalho Chehab #endif
18789a0bf528SMauro Carvalho Chehab };
18799a0bf528SMauro Carvalho Chehab 
18809a0bf528SMauro Carvalho Chehab static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = {
18819a0bf528SMauro Carvalho Chehab 
18829a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_CBAND
18839a0bf528SMauro Carvalho Chehab 	{184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
18849a0bf528SMauro Carvalho Chehab 	{227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
18859a0bf528SMauro Carvalho Chehab 	{380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
18869a0bf528SMauro Carvalho Chehab #endif
18879a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_UHF
18889a0bf528SMauro Carvalho Chehab 	{520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
18899a0bf528SMauro Carvalho Chehab 	{550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
18909a0bf528SMauro Carvalho Chehab 	{650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
18919a0bf528SMauro Carvalho Chehab 	{750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
18929a0bf528SMauro Carvalho Chehab 	{850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
18939a0bf528SMauro Carvalho Chehab 	{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
18949a0bf528SMauro Carvalho Chehab #endif
18959a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_LBAND
18969a0bf528SMauro Carvalho Chehab 	{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
18979a0bf528SMauro Carvalho Chehab 	{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
18989a0bf528SMauro Carvalho Chehab 	{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
18999a0bf528SMauro Carvalho Chehab #endif
19009a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_SBAND
19019a0bf528SMauro Carvalho Chehab 	{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
19029a0bf528SMauro Carvalho Chehab 	{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
19039a0bf528SMauro Carvalho Chehab #endif
19049a0bf528SMauro Carvalho Chehab };
19059a0bf528SMauro Carvalho Chehab 
19069a0bf528SMauro Carvalho Chehab static const struct dib0090_tuning dib0090_tuning_table[] = {
19079a0bf528SMauro Carvalho Chehab 
19089a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_CBAND
19099a0bf528SMauro Carvalho Chehab 	{170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
19109a0bf528SMauro Carvalho Chehab #endif
19119a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_VHF
19129a0bf528SMauro Carvalho Chehab 	{184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
19139a0bf528SMauro Carvalho Chehab 	{227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
19149a0bf528SMauro Carvalho Chehab 	{380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
19159a0bf528SMauro Carvalho Chehab #endif
19169a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_UHF
19179a0bf528SMauro Carvalho Chehab 	{520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
19189a0bf528SMauro Carvalho Chehab 	{550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
19199a0bf528SMauro Carvalho Chehab 	{650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
19209a0bf528SMauro Carvalho Chehab 	{750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
19219a0bf528SMauro Carvalho Chehab 	{850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
19229a0bf528SMauro Carvalho Chehab 	{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
19239a0bf528SMauro Carvalho Chehab #endif
19249a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_LBAND
19259a0bf528SMauro Carvalho Chehab 	{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
19269a0bf528SMauro Carvalho Chehab 	{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
19279a0bf528SMauro Carvalho Chehab 	{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
19289a0bf528SMauro Carvalho Chehab #endif
19299a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_SBAND
19309a0bf528SMauro Carvalho Chehab 	{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
19319a0bf528SMauro Carvalho Chehab 	{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
19329a0bf528SMauro Carvalho Chehab #endif
19339a0bf528SMauro Carvalho Chehab };
19349a0bf528SMauro Carvalho Chehab 
19359a0bf528SMauro Carvalho Chehab static const struct dib0090_tuning dib0090_p1g_tuning_table[] = {
19369a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_CBAND
19379a0bf528SMauro Carvalho Chehab 	{170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB},
19389a0bf528SMauro Carvalho Chehab #endif
19399a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_VHF
19409a0bf528SMauro Carvalho Chehab 	{184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
19419a0bf528SMauro Carvalho Chehab 	{227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
19429a0bf528SMauro Carvalho Chehab 	{380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
19439a0bf528SMauro Carvalho Chehab #endif
19449a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_UHF
19459a0bf528SMauro Carvalho Chehab 	{510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
19469a0bf528SMauro Carvalho Chehab 	{540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
19479a0bf528SMauro Carvalho Chehab 	{600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
19489a0bf528SMauro Carvalho Chehab 	{630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
19499a0bf528SMauro Carvalho Chehab 	{680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
19509a0bf528SMauro Carvalho Chehab 	{720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
19519a0bf528SMauro Carvalho Chehab 	{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
19529a0bf528SMauro Carvalho Chehab #endif
19539a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_LBAND
19549a0bf528SMauro Carvalho Chehab 	{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
19559a0bf528SMauro Carvalho Chehab 	{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
19569a0bf528SMauro Carvalho Chehab 	{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
19579a0bf528SMauro Carvalho Chehab #endif
19589a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_SBAND
19599a0bf528SMauro Carvalho Chehab 	{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
19609a0bf528SMauro Carvalho Chehab 	{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
19619a0bf528SMauro Carvalho Chehab #endif
19629a0bf528SMauro Carvalho Chehab };
19639a0bf528SMauro Carvalho Chehab 
19649a0bf528SMauro Carvalho Chehab static const struct dib0090_pll dib0090_p1g_pll_table[] = {
19659a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_CBAND
19669a0bf528SMauro Carvalho Chehab 	{57000, 0, 11, 48, 6},
19679a0bf528SMauro Carvalho Chehab 	{70000, 1, 11, 48, 6},
19689a0bf528SMauro Carvalho Chehab 	{86000, 0, 10, 32, 4},
19699a0bf528SMauro Carvalho Chehab 	{105000, 1, 10, 32, 4},
19709a0bf528SMauro Carvalho Chehab 	{115000, 0, 9, 24, 6},
19719a0bf528SMauro Carvalho Chehab 	{140000, 1, 9, 24, 6},
19729a0bf528SMauro Carvalho Chehab 	{170000, 0, 8, 16, 4},
19739a0bf528SMauro Carvalho Chehab #endif
19749a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_VHF
19759a0bf528SMauro Carvalho Chehab 	{200000, 1, 8, 16, 4},
19769a0bf528SMauro Carvalho Chehab 	{230000, 0, 7, 12, 6},
19779a0bf528SMauro Carvalho Chehab 	{280000, 1, 7, 12, 6},
19789a0bf528SMauro Carvalho Chehab 	{340000, 0, 6, 8, 4},
19799a0bf528SMauro Carvalho Chehab 	{380000, 1, 6, 8, 4},
19809a0bf528SMauro Carvalho Chehab 	{455000, 0, 5, 6, 6},
19819a0bf528SMauro Carvalho Chehab #endif
19829a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_UHF
19839a0bf528SMauro Carvalho Chehab 	{580000, 1, 5, 6, 6},
19849a0bf528SMauro Carvalho Chehab 	{680000, 0, 4, 4, 4},
19859a0bf528SMauro Carvalho Chehab 	{860000, 1, 4, 4, 4},
19869a0bf528SMauro Carvalho Chehab #endif
19879a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_LBAND
19889a0bf528SMauro Carvalho Chehab 	{1800000, 1, 2, 2, 4},
19899a0bf528SMauro Carvalho Chehab #endif
19909a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_SBAND
19919a0bf528SMauro Carvalho Chehab 	{2900000, 0, 1, 1, 6},
19929a0bf528SMauro Carvalho Chehab #endif
19939a0bf528SMauro Carvalho Chehab };
19949a0bf528SMauro Carvalho Chehab 
19959a0bf528SMauro Carvalho Chehab static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = {
19969a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_CBAND
19979a0bf528SMauro Carvalho Chehab 	{184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
19989a0bf528SMauro Carvalho Chehab 	{227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
19999a0bf528SMauro Carvalho Chehab 	{380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
20009a0bf528SMauro Carvalho Chehab #endif
20019a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_UHF
20029a0bf528SMauro Carvalho Chehab 	{520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
20039a0bf528SMauro Carvalho Chehab 	{550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
20049a0bf528SMauro Carvalho Chehab 	{650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
20059a0bf528SMauro Carvalho Chehab 	{750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
20069a0bf528SMauro Carvalho Chehab 	{850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
20079a0bf528SMauro Carvalho Chehab 	{900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
20089a0bf528SMauro Carvalho Chehab #endif
20099a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_LBAND
20109a0bf528SMauro Carvalho Chehab 	{1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
20119a0bf528SMauro Carvalho Chehab 	{1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
20129a0bf528SMauro Carvalho Chehab 	{1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
20139a0bf528SMauro Carvalho Chehab #endif
20149a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_SBAND
20159a0bf528SMauro Carvalho Chehab 	{2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
20169a0bf528SMauro Carvalho Chehab 	{2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
20179a0bf528SMauro Carvalho Chehab #endif
20189a0bf528SMauro Carvalho Chehab };
20199a0bf528SMauro Carvalho Chehab 
20209a0bf528SMauro Carvalho Chehab static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = {
20219a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_CBAND
20229a0bf528SMauro Carvalho Chehab 	{300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
20239a0bf528SMauro Carvalho Chehab 	{380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
20249a0bf528SMauro Carvalho Chehab 	{570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
20259a0bf528SMauro Carvalho Chehab 	{858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
20269a0bf528SMauro Carvalho Chehab #endif
20279a0bf528SMauro Carvalho Chehab };
20289a0bf528SMauro Carvalho Chehab 
20299a0bf528SMauro Carvalho Chehab static const struct dib0090_tuning dib0090_tuning_table_cband_7090e_sensitivity[] = {
20309a0bf528SMauro Carvalho Chehab #ifdef CONFIG_BAND_CBAND
20319a0bf528SMauro Carvalho Chehab 	{ 300000,  0 ,  3,  0x8105, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
20329a0bf528SMauro Carvalho Chehab 	{ 380000,  0 ,  10, 0x810F, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
20339a0bf528SMauro Carvalho Chehab 	{ 600000,  0 ,  10, 0x815E, 0x280, 0x2d12, 0xb84e, EN_CAB },
20349a0bf528SMauro Carvalho Chehab 	{ 660000,  0 ,  5,  0x85E3, 0x280, 0x2d12, 0xb84e, EN_CAB },
20359a0bf528SMauro Carvalho Chehab 	{ 720000,  0 ,  5,  0x852E, 0x280, 0x2d12, 0xb84e, EN_CAB },
20369a0bf528SMauro Carvalho Chehab 	{ 860000,  0 ,  4,  0x85E5, 0x280, 0x2d12, 0xb84e, EN_CAB },
20379a0bf528SMauro Carvalho Chehab #endif
20389a0bf528SMauro Carvalho Chehab };
20399a0bf528SMauro Carvalho Chehab 
dib0090_update_tuning_table_7090(struct dvb_frontend * fe,u8 cfg_sensitivity)20409a0bf528SMauro Carvalho Chehab int dib0090_update_tuning_table_7090(struct dvb_frontend *fe,
20419a0bf528SMauro Carvalho Chehab 		u8 cfg_sensitivity)
20429a0bf528SMauro Carvalho Chehab {
20439a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
20449a0bf528SMauro Carvalho Chehab 	const struct dib0090_tuning *tune =
20459a0bf528SMauro Carvalho Chehab 		dib0090_tuning_table_cband_7090e_sensitivity;
20466e4e4447SColin Ian King 	static const struct dib0090_tuning dib0090_tuning_table_cband_7090e_aci[] = {
20479a0bf528SMauro Carvalho Chehab 		{ 300000,  0 ,  3,  0x8165, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
20489a0bf528SMauro Carvalho Chehab 		{ 650000,  0 ,  4,  0x815B, 0x280, 0x2d12, 0xb84e, EN_CAB },
20499a0bf528SMauro Carvalho Chehab 		{ 860000,  0 ,  5,  0x84EF, 0x280, 0x2d12, 0xb84e, EN_CAB },
20509a0bf528SMauro Carvalho Chehab 	};
20519a0bf528SMauro Carvalho Chehab 
20529a0bf528SMauro Carvalho Chehab 	if ((!state->identity.p1g) || (!state->identity.in_soc)
20539a0bf528SMauro Carvalho Chehab 			|| ((state->identity.version != SOC_7090_P1G_21R1)
20549a0bf528SMauro Carvalho Chehab 				&& (state->identity.version != SOC_7090_P1G_11R1))) {
20554bd1a8ddSMauro Carvalho Chehab 		dprintk("%s() function can only be used for dib7090\n", __func__);
20569a0bf528SMauro Carvalho Chehab 		return -ENODEV;
20579a0bf528SMauro Carvalho Chehab 	}
20589a0bf528SMauro Carvalho Chehab 
20599a0bf528SMauro Carvalho Chehab 	if (cfg_sensitivity)
20609a0bf528SMauro Carvalho Chehab 		tune = dib0090_tuning_table_cband_7090e_sensitivity;
20619a0bf528SMauro Carvalho Chehab 	else
20629a0bf528SMauro Carvalho Chehab 		tune = dib0090_tuning_table_cband_7090e_aci;
20639a0bf528SMauro Carvalho Chehab 
20649a0bf528SMauro Carvalho Chehab 	while (state->rf_request > tune->max_freq)
20659a0bf528SMauro Carvalho Chehab 		tune++;
20669a0bf528SMauro Carvalho Chehab 
20679a0bf528SMauro Carvalho Chehab 	dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x8000)
20689a0bf528SMauro Carvalho Chehab 			| (tune->lna_bias & 0x7fff));
20699a0bf528SMauro Carvalho Chehab 	dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xf83f)
20709a0bf528SMauro Carvalho Chehab 			| ((tune->lna_tune << 6) & 0x07c0));
20719a0bf528SMauro Carvalho Chehab 	return 0;
20729a0bf528SMauro Carvalho Chehab }
20739a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib0090_update_tuning_table_7090);
20749a0bf528SMauro Carvalho Chehab 
dib0090_captrim_search(struct dib0090_state * state,enum frontend_tune_state * tune_state)20759a0bf528SMauro Carvalho Chehab static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state)
20769a0bf528SMauro Carvalho Chehab {
20779a0bf528SMauro Carvalho Chehab 	int ret = 0;
20789a0bf528SMauro Carvalho Chehab 	u16 lo4 = 0xe900;
20799a0bf528SMauro Carvalho Chehab 
20809a0bf528SMauro Carvalho Chehab 	s16 adc_target;
20819a0bf528SMauro Carvalho Chehab 	u16 adc;
20829a0bf528SMauro Carvalho Chehab 	s8 step_sign;
20839a0bf528SMauro Carvalho Chehab 	u8 force_soft_search = 0;
20849a0bf528SMauro Carvalho Chehab 
20859a0bf528SMauro Carvalho Chehab 	if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
20869a0bf528SMauro Carvalho Chehab 		force_soft_search = 1;
20879a0bf528SMauro Carvalho Chehab 
20889a0bf528SMauro Carvalho Chehab 	if (*tune_state == CT_TUNER_START) {
20894bd1a8ddSMauro Carvalho Chehab 		dprintk("Start Captrim search : %s\n",
20904bd1a8ddSMauro Carvalho Chehab 			(force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO");
20919a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x10, 0x2B1);
20929a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x1e, 0x0032);
20939a0bf528SMauro Carvalho Chehab 
20949a0bf528SMauro Carvalho Chehab 		if (!state->tuner_is_tuned) {
20959a0bf528SMauro Carvalho Chehab 			/* prepare a complete captrim */
20969a0bf528SMauro Carvalho Chehab 			if (!state->identity.p1g || force_soft_search)
20979a0bf528SMauro Carvalho Chehab 				state->step = state->captrim = state->fcaptrim = 64;
20989a0bf528SMauro Carvalho Chehab 
20999a0bf528SMauro Carvalho Chehab 			state->current_rf = state->rf_request;
21009a0bf528SMauro Carvalho Chehab 		} else {	/* we are already tuned to this frequency - the configuration is correct  */
21019a0bf528SMauro Carvalho Chehab 			if (!state->identity.p1g || force_soft_search) {
21029a0bf528SMauro Carvalho Chehab 				/* do a minimal captrim even if the frequency has not changed */
21039a0bf528SMauro Carvalho Chehab 				state->step = 4;
21049a0bf528SMauro Carvalho Chehab 				state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f;
21059a0bf528SMauro Carvalho Chehab 			}
21069a0bf528SMauro Carvalho Chehab 		}
21079a0bf528SMauro Carvalho Chehab 		state->adc_diff = 3000;
21089a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_STEP_0;
21099a0bf528SMauro Carvalho Chehab 
21109a0bf528SMauro Carvalho Chehab 	} else if (*tune_state == CT_TUNER_STEP_0) {
21119a0bf528SMauro Carvalho Chehab 		if (state->identity.p1g && !force_soft_search) {
21129a0bf528SMauro Carvalho Chehab 			u8 ratio = 31;
21139a0bf528SMauro Carvalho Chehab 
21149a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1);
21159a0bf528SMauro Carvalho Chehab 			dib0090_read_reg(state, 0x40);
21169a0bf528SMauro Carvalho Chehab 			ret = 50;
21179a0bf528SMauro Carvalho Chehab 		} else {
21189a0bf528SMauro Carvalho Chehab 			state->step /= 2;
21199a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, 0x18, lo4 | state->captrim);
21209a0bf528SMauro Carvalho Chehab 
21219a0bf528SMauro Carvalho Chehab 			if (state->identity.in_soc)
21229a0bf528SMauro Carvalho Chehab 				ret = 25;
21239a0bf528SMauro Carvalho Chehab 		}
21249a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_STEP_1;
21259a0bf528SMauro Carvalho Chehab 
21269a0bf528SMauro Carvalho Chehab 	} else if (*tune_state == CT_TUNER_STEP_1) {
21279a0bf528SMauro Carvalho Chehab 		if (state->identity.p1g && !force_soft_search) {
21289a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, 0x40, 0x18c | (0 << 1) | 0);
21299a0bf528SMauro Carvalho Chehab 			dib0090_read_reg(state, 0x40);
21309a0bf528SMauro Carvalho Chehab 
21319a0bf528SMauro Carvalho Chehab 			state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F;
21324bd1a8ddSMauro Carvalho Chehab 			dprintk("***Final Captrim= 0x%x\n", state->fcaptrim);
21339a0bf528SMauro Carvalho Chehab 			*tune_state = CT_TUNER_STEP_3;
21349a0bf528SMauro Carvalho Chehab 
21359a0bf528SMauro Carvalho Chehab 		} else {
21369a0bf528SMauro Carvalho Chehab 			/* MERGE for all krosus before P1G */
21379a0bf528SMauro Carvalho Chehab 			adc = dib0090_get_slow_adc_val(state);
21384bd1a8ddSMauro Carvalho Chehab 			dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV\n", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024);
21399a0bf528SMauro Carvalho Chehab 
21409a0bf528SMauro Carvalho Chehab 			if (state->rest == 0 || state->identity.in_soc) {	/* Just for 8090P SOCS where auto captrim HW bug : TO CHECK IN ACI for SOCS !!! if 400 for 8090p SOC => tune issue !!! */
21419a0bf528SMauro Carvalho Chehab 				adc_target = 200;
21429a0bf528SMauro Carvalho Chehab 			} else
21439a0bf528SMauro Carvalho Chehab 				adc_target = 400;
21449a0bf528SMauro Carvalho Chehab 
21459a0bf528SMauro Carvalho Chehab 			if (adc >= adc_target) {
21469a0bf528SMauro Carvalho Chehab 				adc -= adc_target;
21479a0bf528SMauro Carvalho Chehab 				step_sign = -1;
21489a0bf528SMauro Carvalho Chehab 			} else {
21499a0bf528SMauro Carvalho Chehab 				adc = adc_target - adc;
21509a0bf528SMauro Carvalho Chehab 				step_sign = 1;
21519a0bf528SMauro Carvalho Chehab 			}
21529a0bf528SMauro Carvalho Chehab 
21539a0bf528SMauro Carvalho Chehab 			if (adc < state->adc_diff) {
21544bd1a8ddSMauro Carvalho Chehab 				dprintk("CAPTRIM=%d is closer to target (%d/%d)\n", (u32) state->captrim, (u32) adc, (u32) state->adc_diff);
21559a0bf528SMauro Carvalho Chehab 				state->adc_diff = adc;
21569a0bf528SMauro Carvalho Chehab 				state->fcaptrim = state->captrim;
21579a0bf528SMauro Carvalho Chehab 			}
21589a0bf528SMauro Carvalho Chehab 
21599a0bf528SMauro Carvalho Chehab 			state->captrim += step_sign * state->step;
21609a0bf528SMauro Carvalho Chehab 			if (state->step >= 1)
21619a0bf528SMauro Carvalho Chehab 				*tune_state = CT_TUNER_STEP_0;
21629a0bf528SMauro Carvalho Chehab 			else
21639a0bf528SMauro Carvalho Chehab 				*tune_state = CT_TUNER_STEP_2;
21649a0bf528SMauro Carvalho Chehab 
21659a0bf528SMauro Carvalho Chehab 			ret = 25;
21669a0bf528SMauro Carvalho Chehab 		}
21679a0bf528SMauro Carvalho Chehab 	} else if (*tune_state == CT_TUNER_STEP_2) {	/* this step is only used by krosus < P1G */
21689a0bf528SMauro Carvalho Chehab 		/*write the final cptrim config */
21699a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim);
21709a0bf528SMauro Carvalho Chehab 
21719a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_STEP_3;
21729a0bf528SMauro Carvalho Chehab 
21739a0bf528SMauro Carvalho Chehab 	} else if (*tune_state == CT_TUNER_STEP_3) {
21749a0bf528SMauro Carvalho Chehab 		state->calibrate &= ~CAPTRIM_CAL;
21759a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_STEP_0;
21769a0bf528SMauro Carvalho Chehab 	}
21779a0bf528SMauro Carvalho Chehab 
21789a0bf528SMauro Carvalho Chehab 	return ret;
21799a0bf528SMauro Carvalho Chehab }
21809a0bf528SMauro Carvalho Chehab 
dib0090_get_temperature(struct dib0090_state * state,enum frontend_tune_state * tune_state)21819a0bf528SMauro Carvalho Chehab static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state)
21829a0bf528SMauro Carvalho Chehab {
21839a0bf528SMauro Carvalho Chehab 	int ret = 15;
21849a0bf528SMauro Carvalho Chehab 	s16 val;
21859a0bf528SMauro Carvalho Chehab 
21869a0bf528SMauro Carvalho Chehab 	switch (*tune_state) {
21879a0bf528SMauro Carvalho Chehab 	case CT_TUNER_START:
21889a0bf528SMauro Carvalho Chehab 		state->wbdmux = dib0090_read_reg(state, 0x10);
21899a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3));
21909a0bf528SMauro Carvalho Chehab 
21919a0bf528SMauro Carvalho Chehab 		state->bias = dib0090_read_reg(state, 0x13);
21929a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8));
21939a0bf528SMauro Carvalho Chehab 
21949a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_STEP_0;
21959a0bf528SMauro Carvalho Chehab 		/* wait for the WBDMUX to switch and for the ADC to sample */
21969a0bf528SMauro Carvalho Chehab 		break;
21979a0bf528SMauro Carvalho Chehab 
21989a0bf528SMauro Carvalho Chehab 	case CT_TUNER_STEP_0:
21999a0bf528SMauro Carvalho Chehab 		state->adc_diff = dib0090_get_slow_adc_val(state);
22009a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8));
22019a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_STEP_1;
22029a0bf528SMauro Carvalho Chehab 		break;
22039a0bf528SMauro Carvalho Chehab 
22049a0bf528SMauro Carvalho Chehab 	case CT_TUNER_STEP_1:
22059a0bf528SMauro Carvalho Chehab 		val = dib0090_get_slow_adc_val(state);
22069a0bf528SMauro Carvalho Chehab 		state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55;
22079a0bf528SMauro Carvalho Chehab 
22084bd1a8ddSMauro Carvalho Chehab 		dprintk("temperature: %d C\n", state->temperature - 30);
22099a0bf528SMauro Carvalho Chehab 
22109a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_STEP_2;
22119a0bf528SMauro Carvalho Chehab 		break;
22129a0bf528SMauro Carvalho Chehab 
22139a0bf528SMauro Carvalho Chehab 	case CT_TUNER_STEP_2:
22149a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x13, state->bias);
22159a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x10, state->wbdmux);	/* write back original WBDMUX */
22169a0bf528SMauro Carvalho Chehab 
22179a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_START;
22189a0bf528SMauro Carvalho Chehab 		state->calibrate &= ~TEMP_CAL;
22199a0bf528SMauro Carvalho Chehab 		if (state->config->analog_output == 0)
22209a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
22219a0bf528SMauro Carvalho Chehab 
22229a0bf528SMauro Carvalho Chehab 		break;
22239a0bf528SMauro Carvalho Chehab 
22249a0bf528SMauro Carvalho Chehab 	default:
22259a0bf528SMauro Carvalho Chehab 		ret = 0;
22269a0bf528SMauro Carvalho Chehab 		break;
22279a0bf528SMauro Carvalho Chehab 	}
22289a0bf528SMauro Carvalho Chehab 	return ret;
22299a0bf528SMauro Carvalho Chehab }
22309a0bf528SMauro Carvalho Chehab 
22319a0bf528SMauro Carvalho Chehab #define WBD     0x781		/* 1 1 1 1 0000 0 0 1 */
dib0090_tune(struct dvb_frontend * fe)22329a0bf528SMauro Carvalho Chehab static int dib0090_tune(struct dvb_frontend *fe)
22339a0bf528SMauro Carvalho Chehab {
22349a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
22359a0bf528SMauro Carvalho Chehab 	const struct dib0090_tuning *tune = state->current_tune_table_index;
22369a0bf528SMauro Carvalho Chehab 	const struct dib0090_pll *pll = state->current_pll_table_index;
22379a0bf528SMauro Carvalho Chehab 	enum frontend_tune_state *tune_state = &state->tune_state;
22389a0bf528SMauro Carvalho Chehab 
22399a0bf528SMauro Carvalho Chehab 	u16 lo5, lo6, Den, tmp;
22409a0bf528SMauro Carvalho Chehab 	u32 FBDiv, Rest, FREF, VCOF_kHz = 0;
22419a0bf528SMauro Carvalho Chehab 	int ret = 10;		/* 1ms is the default delay most of the time */
22429a0bf528SMauro Carvalho Chehab 	u8 c, i;
22439a0bf528SMauro Carvalho Chehab 
22449a0bf528SMauro Carvalho Chehab 	/************************* VCO ***************************/
22459a0bf528SMauro Carvalho Chehab 	/* Default values for FG                                 */
22469a0bf528SMauro Carvalho Chehab 	/* from these are needed :                               */
22479a0bf528SMauro Carvalho Chehab 	/* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv             */
22489a0bf528SMauro Carvalho Chehab 
22499a0bf528SMauro Carvalho Chehab 	/* in any case we first need to do a calibration if needed */
22509a0bf528SMauro Carvalho Chehab 	if (*tune_state == CT_TUNER_START) {
22519a0bf528SMauro Carvalho Chehab 		/* deactivate DataTX before some calibrations */
22529a0bf528SMauro Carvalho Chehab 		if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL))
22539a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
22549a0bf528SMauro Carvalho Chehab 		else
22559a0bf528SMauro Carvalho Chehab 			/* Activate DataTX in case a calibration has been done before */
22569a0bf528SMauro Carvalho Chehab 			if (state->config->analog_output == 0)
22579a0bf528SMauro Carvalho Chehab 				dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
22589a0bf528SMauro Carvalho Chehab 	}
22599a0bf528SMauro Carvalho Chehab 
22609a0bf528SMauro Carvalho Chehab 	if (state->calibrate & DC_CAL)
22619a0bf528SMauro Carvalho Chehab 		return dib0090_dc_offset_calibration(state, tune_state);
22629a0bf528SMauro Carvalho Chehab 	else if (state->calibrate & WBD_CAL) {
22639a0bf528SMauro Carvalho Chehab 		if (state->current_rf == 0)
22649a0bf528SMauro Carvalho Chehab 			state->current_rf = state->fe->dtv_property_cache.frequency / 1000;
22659a0bf528SMauro Carvalho Chehab 		return dib0090_wbd_calibration(state, tune_state);
22669a0bf528SMauro Carvalho Chehab 	} else if (state->calibrate & TEMP_CAL)
22679a0bf528SMauro Carvalho Chehab 		return dib0090_get_temperature(state, tune_state);
22689a0bf528SMauro Carvalho Chehab 	else if (state->calibrate & CAPTRIM_CAL)
22699a0bf528SMauro Carvalho Chehab 		return dib0090_captrim_search(state, tune_state);
22709a0bf528SMauro Carvalho Chehab 
22719a0bf528SMauro Carvalho Chehab 	if (*tune_state == CT_TUNER_START) {
22729a0bf528SMauro Carvalho Chehab 		/* if soc and AGC pwm control, disengage mux to be able to R/W access to 0x01 register to set the right filter (cutoff_freq_select) during the tune sequence, otherwise, SOC SERPAR error when accessing to 0x01 */
22739a0bf528SMauro Carvalho Chehab 		if (state->config->use_pwm_agc && state->identity.in_soc) {
22749a0bf528SMauro Carvalho Chehab 			tmp = dib0090_read_reg(state, 0x39);
22759a0bf528SMauro Carvalho Chehab 			if ((tmp >> 10) & 0x1)
22769a0bf528SMauro Carvalho Chehab 				dib0090_write_reg(state, 0x39, tmp & ~(1 << 10));
22779a0bf528SMauro Carvalho Chehab 		}
22789a0bf528SMauro Carvalho Chehab 
22799a0bf528SMauro Carvalho Chehab 		state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000);
22809a0bf528SMauro Carvalho Chehab 		state->rf_request =
22819a0bf528SMauro Carvalho Chehab 			state->fe->dtv_property_cache.frequency / 1000 + (state->current_band ==
22829a0bf528SMauro Carvalho Chehab 					BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->
22839a0bf528SMauro Carvalho Chehab 					freq_offset_khz_vhf);
22849a0bf528SMauro Carvalho Chehab 
22859a0bf528SMauro Carvalho Chehab 		/* in ISDB-T 1seg we shift tuning frequency */
22869a0bf528SMauro Carvalho Chehab 		if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1
22879a0bf528SMauro Carvalho Chehab 					&& state->fe->dtv_property_cache.isdbt_partial_reception == 0)) {
22889a0bf528SMauro Carvalho Chehab 			const struct dib0090_low_if_offset_table *LUT_offset = state->config->low_if;
22899a0bf528SMauro Carvalho Chehab 			u8 found_offset = 0;
22909a0bf528SMauro Carvalho Chehab 			u32 margin_khz = 100;
22919a0bf528SMauro Carvalho Chehab 
22929a0bf528SMauro Carvalho Chehab 			if (LUT_offset != NULL) {
22939a0bf528SMauro Carvalho Chehab 				while (LUT_offset->RF_freq != 0xffff) {
22949a0bf528SMauro Carvalho Chehab 					if (((state->rf_request > (LUT_offset->RF_freq - margin_khz))
22959a0bf528SMauro Carvalho Chehab 								&& (state->rf_request < (LUT_offset->RF_freq + margin_khz)))
22969a0bf528SMauro Carvalho Chehab 							&& LUT_offset->std == state->fe->dtv_property_cache.delivery_system) {
22979a0bf528SMauro Carvalho Chehab 						state->rf_request += LUT_offset->offset_khz;
22989a0bf528SMauro Carvalho Chehab 						found_offset = 1;
22999a0bf528SMauro Carvalho Chehab 						break;
23009a0bf528SMauro Carvalho Chehab 					}
23019a0bf528SMauro Carvalho Chehab 					LUT_offset++;
23029a0bf528SMauro Carvalho Chehab 				}
23039a0bf528SMauro Carvalho Chehab 			}
23049a0bf528SMauro Carvalho Chehab 
23059a0bf528SMauro Carvalho Chehab 			if (found_offset == 0)
23069a0bf528SMauro Carvalho Chehab 				state->rf_request += 400;
23079a0bf528SMauro Carvalho Chehab 		}
23089a0bf528SMauro Carvalho Chehab 		if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) {
23099a0bf528SMauro Carvalho Chehab 			state->tuner_is_tuned = 0;
23109a0bf528SMauro Carvalho Chehab 			state->current_rf = 0;
23119a0bf528SMauro Carvalho Chehab 			state->current_standard = 0;
23129a0bf528SMauro Carvalho Chehab 
23139a0bf528SMauro Carvalho Chehab 			tune = dib0090_tuning_table;
23149a0bf528SMauro Carvalho Chehab 			if (state->identity.p1g)
23159a0bf528SMauro Carvalho Chehab 				tune = dib0090_p1g_tuning_table;
23169a0bf528SMauro Carvalho Chehab 
23179a0bf528SMauro Carvalho Chehab 			tmp = (state->identity.version >> 5) & 0x7;
23189a0bf528SMauro Carvalho Chehab 
23199a0bf528SMauro Carvalho Chehab 			if (state->identity.in_soc) {
23209a0bf528SMauro Carvalho Chehab 				if (state->config->force_cband_input) {	/* Use the CBAND input for all band */
23219a0bf528SMauro Carvalho Chehab 					if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF
23229a0bf528SMauro Carvalho Chehab 							|| state->current_band & BAND_UHF) {
23239a0bf528SMauro Carvalho Chehab 						state->current_band = BAND_CBAND;
23249a0bf528SMauro Carvalho Chehab 						if (state->config->is_dib7090e)
23259a0bf528SMauro Carvalho Chehab 							tune = dib0090_tuning_table_cband_7090e_sensitivity;
23269a0bf528SMauro Carvalho Chehab 						else
23279a0bf528SMauro Carvalho Chehab 							tune = dib0090_tuning_table_cband_7090;
23289a0bf528SMauro Carvalho Chehab 					}
23299a0bf528SMauro Carvalho Chehab 				} else {	/* Use the CBAND input for all band under UHF */
23309a0bf528SMauro Carvalho Chehab 					if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) {
23319a0bf528SMauro Carvalho Chehab 						state->current_band = BAND_CBAND;
23329a0bf528SMauro Carvalho Chehab 						if (state->config->is_dib7090e)
23339a0bf528SMauro Carvalho Chehab 							tune = dib0090_tuning_table_cband_7090e_sensitivity;
23349a0bf528SMauro Carvalho Chehab 						else
23359a0bf528SMauro Carvalho Chehab 							tune = dib0090_tuning_table_cband_7090;
23369a0bf528SMauro Carvalho Chehab 					}
23379a0bf528SMauro Carvalho Chehab 				}
23389a0bf528SMauro Carvalho Chehab 			} else
23399a0bf528SMauro Carvalho Chehab 			 if (tmp == 0x4 || tmp == 0x7) {
23409a0bf528SMauro Carvalho Chehab 				/* CBAND tuner version for VHF */
23419a0bf528SMauro Carvalho Chehab 				if (state->current_band == BAND_FM || state->current_band == BAND_CBAND || state->current_band == BAND_VHF) {
23429a0bf528SMauro Carvalho Chehab 					state->current_band = BAND_CBAND;	/* Force CBAND */
23439a0bf528SMauro Carvalho Chehab 
23449a0bf528SMauro Carvalho Chehab 					tune = dib0090_tuning_table_fm_vhf_on_cband;
23459a0bf528SMauro Carvalho Chehab 					if (state->identity.p1g)
23469a0bf528SMauro Carvalho Chehab 						tune = dib0090_p1g_tuning_table_fm_vhf_on_cband;
23479a0bf528SMauro Carvalho Chehab 				}
23489a0bf528SMauro Carvalho Chehab 			}
23499a0bf528SMauro Carvalho Chehab 
23509a0bf528SMauro Carvalho Chehab 			pll = dib0090_pll_table;
23519a0bf528SMauro Carvalho Chehab 			if (state->identity.p1g)
23529a0bf528SMauro Carvalho Chehab 				pll = dib0090_p1g_pll_table;
23539a0bf528SMauro Carvalho Chehab 
23549a0bf528SMauro Carvalho Chehab 			/* Look for the interval */
23559a0bf528SMauro Carvalho Chehab 			while (state->rf_request > tune->max_freq)
23569a0bf528SMauro Carvalho Chehab 				tune++;
23579a0bf528SMauro Carvalho Chehab 			while (state->rf_request > pll->max_freq)
23589a0bf528SMauro Carvalho Chehab 				pll++;
23599a0bf528SMauro Carvalho Chehab 
23609a0bf528SMauro Carvalho Chehab 			state->current_tune_table_index = tune;
23619a0bf528SMauro Carvalho Chehab 			state->current_pll_table_index = pll;
23629a0bf528SMauro Carvalho Chehab 
23639a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim));
23649a0bf528SMauro Carvalho Chehab 
23659a0bf528SMauro Carvalho Chehab 			VCOF_kHz = (pll->hfdiv * state->rf_request) * 2;
23669a0bf528SMauro Carvalho Chehab 
23679a0bf528SMauro Carvalho Chehab 			FREF = state->config->io.clock_khz;
23689a0bf528SMauro Carvalho Chehab 			if (state->config->fref_clock_ratio != 0)
23699a0bf528SMauro Carvalho Chehab 				FREF /= state->config->fref_clock_ratio;
23709a0bf528SMauro Carvalho Chehab 
23719a0bf528SMauro Carvalho Chehab 			FBDiv = (VCOF_kHz / pll->topresc / FREF);
23729a0bf528SMauro Carvalho Chehab 			Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF;
23739a0bf528SMauro Carvalho Chehab 
23749a0bf528SMauro Carvalho Chehab 			if (Rest < LPF)
23759a0bf528SMauro Carvalho Chehab 				Rest = 0;
23769a0bf528SMauro Carvalho Chehab 			else if (Rest < 2 * LPF)
23779a0bf528SMauro Carvalho Chehab 				Rest = 2 * LPF;
23789a0bf528SMauro Carvalho Chehab 			else if (Rest > (FREF - LPF)) {
23799a0bf528SMauro Carvalho Chehab 				Rest = 0;
23809a0bf528SMauro Carvalho Chehab 				FBDiv += 1;
23819a0bf528SMauro Carvalho Chehab 			} else if (Rest > (FREF - 2 * LPF))
23829a0bf528SMauro Carvalho Chehab 				Rest = FREF - 2 * LPF;
23839a0bf528SMauro Carvalho Chehab 			Rest = (Rest * 6528) / (FREF / 10);
23849a0bf528SMauro Carvalho Chehab 			state->rest = Rest;
23859a0bf528SMauro Carvalho Chehab 
23869a0bf528SMauro Carvalho Chehab 			/* external loop filter, otherwise:
23879a0bf528SMauro Carvalho Chehab 			 * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4;
23889a0bf528SMauro Carvalho Chehab 			 * lo6 = 0x0e34 */
23899a0bf528SMauro Carvalho Chehab 
23909a0bf528SMauro Carvalho Chehab 			if (Rest == 0) {
23919a0bf528SMauro Carvalho Chehab 				if (pll->vco_band)
23929a0bf528SMauro Carvalho Chehab 					lo5 = 0x049f;
23939a0bf528SMauro Carvalho Chehab 				else
23949a0bf528SMauro Carvalho Chehab 					lo5 = 0x041f;
23959a0bf528SMauro Carvalho Chehab 			} else {
23969a0bf528SMauro Carvalho Chehab 				if (pll->vco_band)
23979a0bf528SMauro Carvalho Chehab 					lo5 = 0x049e;
23989a0bf528SMauro Carvalho Chehab 				else if (state->config->analog_output)
23999a0bf528SMauro Carvalho Chehab 					lo5 = 0x041d;
24009a0bf528SMauro Carvalho Chehab 				else
24019a0bf528SMauro Carvalho Chehab 					lo5 = 0x041c;
24029a0bf528SMauro Carvalho Chehab 			}
24039a0bf528SMauro Carvalho Chehab 
24049a0bf528SMauro Carvalho Chehab 			if (state->identity.p1g) {	/* Bias is done automatically in P1G */
24059a0bf528SMauro Carvalho Chehab 				if (state->identity.in_soc) {
24069a0bf528SMauro Carvalho Chehab 					if (state->identity.version == SOC_8090_P1G_11R1)
24079a0bf528SMauro Carvalho Chehab 						lo5 = 0x46f;
24089a0bf528SMauro Carvalho Chehab 					else
24099a0bf528SMauro Carvalho Chehab 						lo5 = 0x42f;
24109a0bf528SMauro Carvalho Chehab 				} else
24119a0bf528SMauro Carvalho Chehab 					lo5 = 0x42c;
24129a0bf528SMauro Carvalho Chehab 			}
24139a0bf528SMauro Carvalho Chehab 
24149a0bf528SMauro Carvalho Chehab 			lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7);	/* bit 15 is the split to the slave, we do not do it here */
24159a0bf528SMauro Carvalho Chehab 
24169a0bf528SMauro Carvalho Chehab 			if (!state->config->io.pll_int_loop_filt) {
24179a0bf528SMauro Carvalho Chehab 				if (state->identity.in_soc)
24189a0bf528SMauro Carvalho Chehab 					lo6 = 0xff98;
24199a0bf528SMauro Carvalho Chehab 				else if (state->identity.p1g || (Rest == 0))
24209a0bf528SMauro Carvalho Chehab 					lo6 = 0xfff8;
24219a0bf528SMauro Carvalho Chehab 				else
24229a0bf528SMauro Carvalho Chehab 					lo6 = 0xff28;
24239a0bf528SMauro Carvalho Chehab 			} else
24249a0bf528SMauro Carvalho Chehab 				lo6 = (state->config->io.pll_int_loop_filt << 3);
24259a0bf528SMauro Carvalho Chehab 
24269a0bf528SMauro Carvalho Chehab 			Den = 1;
24279a0bf528SMauro Carvalho Chehab 
24289a0bf528SMauro Carvalho Chehab 			if (Rest > 0) {
24299a0bf528SMauro Carvalho Chehab 				lo6 |= (1 << 2) | 2;
24309a0bf528SMauro Carvalho Chehab 				Den = 255;
24319a0bf528SMauro Carvalho Chehab 			}
24329a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, 0x15, (u16) FBDiv);
24339a0bf528SMauro Carvalho Chehab 			if (state->config->fref_clock_ratio != 0)
24349a0bf528SMauro Carvalho Chehab 				dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio);
24359a0bf528SMauro Carvalho Chehab 			else
24369a0bf528SMauro Carvalho Chehab 				dib0090_write_reg(state, 0x16, (Den << 8) | 1);
24379a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, 0x17, (u16) Rest);
24389a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, 0x19, lo5);
24399a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, 0x1c, lo6);
24409a0bf528SMauro Carvalho Chehab 
24419a0bf528SMauro Carvalho Chehab 			lo6 = tune->tuner_enable;
24429a0bf528SMauro Carvalho Chehab 			if (state->config->analog_output)
24439a0bf528SMauro Carvalho Chehab 				lo6 = (lo6 & 0xff9f) | 0x2;
24449a0bf528SMauro Carvalho Chehab 
24459a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL);
24469a0bf528SMauro Carvalho Chehab 
24479a0bf528SMauro Carvalho Chehab 		}
24489a0bf528SMauro Carvalho Chehab 
24499a0bf528SMauro Carvalho Chehab 		state->current_rf = state->rf_request;
24509a0bf528SMauro Carvalho Chehab 		state->current_standard = state->fe->dtv_property_cache.delivery_system;
24519a0bf528SMauro Carvalho Chehab 
24529a0bf528SMauro Carvalho Chehab 		ret = 20;
2453868c9a17SMauro Carvalho Chehab 		state->calibrate = CAPTRIM_CAL;	/* captrim search now */
24549a0bf528SMauro Carvalho Chehab 	}
24559a0bf528SMauro Carvalho Chehab 
24569a0bf528SMauro Carvalho Chehab 	else if (*tune_state == CT_TUNER_STEP_0) {	/* Warning : because of captrim cal, if you change this step, change it also in _cal.c file because it is the step following captrim cal state machine */
24579a0bf528SMauro Carvalho Chehab 		const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
24589a0bf528SMauro Carvalho Chehab 
24599a0bf528SMauro Carvalho Chehab 		while (state->current_rf / 1000 > wbd->max_freq)
24609a0bf528SMauro Carvalho Chehab 			wbd++;
24619a0bf528SMauro Carvalho Chehab 
24629a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x1e, 0x07ff);
24634bd1a8ddSMauro Carvalho Chehab 		dprintk("Final Captrim: %d\n", (u32) state->fcaptrim);
24644bd1a8ddSMauro Carvalho Chehab 		dprintk("HFDIV code: %d\n", (u32) pll->hfdiv_code);
24654bd1a8ddSMauro Carvalho Chehab 		dprintk("VCO = %d\n", (u32) pll->vco_band);
24664bd1a8ddSMauro Carvalho Chehab 		dprintk("VCOF in kHz: %d ((%d*%d) << 1))\n", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request);
24674bd1a8ddSMauro Carvalho Chehab 		dprintk("REFDIV: %d, FREF: %d\n", (u32) 1, (u32) state->config->io.clock_khz);
24684bd1a8ddSMauro Carvalho Chehab 		dprintk("FBDIV: %d, Rest: %d\n", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17));
24694bd1a8ddSMauro Carvalho Chehab 		dprintk("Num: %d, Den: %d, SD: %d\n", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8),
24709a0bf528SMauro Carvalho Chehab 			(u32) dib0090_read_reg(state, 0x1c) & 0x3);
24719a0bf528SMauro Carvalho Chehab 
24729a0bf528SMauro Carvalho Chehab #define WBD     0x781		/* 1 1 1 1 0000 0 0 1 */
24739a0bf528SMauro Carvalho Chehab 		c = 4;
24749a0bf528SMauro Carvalho Chehab 		i = 3;
24759a0bf528SMauro Carvalho Chehab 
24769a0bf528SMauro Carvalho Chehab 		if (wbd->wbd_gain != 0)
24779a0bf528SMauro Carvalho Chehab 			c = wbd->wbd_gain;
24789a0bf528SMauro Carvalho Chehab 
24799a0bf528SMauro Carvalho Chehab 		state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1));
24809a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x10, state->wbdmux);
24819a0bf528SMauro Carvalho Chehab 
24829a0bf528SMauro Carvalho Chehab 		if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) {
24834bd1a8ddSMauro Carvalho Chehab 			dprintk("P1G : The cable band is selected and lna_tune = %d\n", tune->lna_tune);
24849a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, 0x09, tune->lna_bias);
24859a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim));
24869a0bf528SMauro Carvalho Chehab 		} else
24879a0bf528SMauro Carvalho Chehab 			dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | tune->lna_bias);
24889a0bf528SMauro Carvalho Chehab 
24899a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x0c, tune->v2i);
24909a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x0d, tune->mix);
24919a0bf528SMauro Carvalho Chehab 		dib0090_write_reg(state, 0x0e, tune->load);
24929a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_STEP_1;
24939a0bf528SMauro Carvalho Chehab 
24949a0bf528SMauro Carvalho Chehab 	} else if (*tune_state == CT_TUNER_STEP_1) {
24959a0bf528SMauro Carvalho Chehab 		/* initialize the lt gain register */
24969a0bf528SMauro Carvalho Chehab 		state->rf_lt_def = 0x7c00;
24979a0bf528SMauro Carvalho Chehab 
24989a0bf528SMauro Carvalho Chehab 		dib0090_set_bandwidth(state);
24999a0bf528SMauro Carvalho Chehab 		state->tuner_is_tuned = 1;
25009a0bf528SMauro Carvalho Chehab 
25019a0bf528SMauro Carvalho Chehab 		state->calibrate |= WBD_CAL;
25029a0bf528SMauro Carvalho Chehab 		state->calibrate |= TEMP_CAL;
25039a0bf528SMauro Carvalho Chehab 		*tune_state = CT_TUNER_STOP;
25049a0bf528SMauro Carvalho Chehab 	} else
25059a0bf528SMauro Carvalho Chehab 		ret = FE_CALLBACK_TIME_NEVER;
25069a0bf528SMauro Carvalho Chehab 	return ret;
25079a0bf528SMauro Carvalho Chehab }
25089a0bf528SMauro Carvalho Chehab 
dib0090_release(struct dvb_frontend * fe)2509f2709c20SMauro Carvalho Chehab static void dib0090_release(struct dvb_frontend *fe)
2510f2709c20SMauro Carvalho Chehab {
2511f2709c20SMauro Carvalho Chehab 	kfree(fe->tuner_priv);
2512f2709c20SMauro Carvalho Chehab 	fe->tuner_priv = NULL;
2513f2709c20SMauro Carvalho Chehab }
2514f2709c20SMauro Carvalho Chehab 
dib0090_get_tune_state(struct dvb_frontend * fe)25159a0bf528SMauro Carvalho Chehab enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
25169a0bf528SMauro Carvalho Chehab {
25179a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
25189a0bf528SMauro Carvalho Chehab 
25199a0bf528SMauro Carvalho Chehab 	return state->tune_state;
25209a0bf528SMauro Carvalho Chehab }
25219a0bf528SMauro Carvalho Chehab 
25229a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib0090_get_tune_state);
25239a0bf528SMauro Carvalho Chehab 
dib0090_set_tune_state(struct dvb_frontend * fe,enum frontend_tune_state tune_state)25249a0bf528SMauro Carvalho Chehab int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
25259a0bf528SMauro Carvalho Chehab {
25269a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
25279a0bf528SMauro Carvalho Chehab 
25289a0bf528SMauro Carvalho Chehab 	state->tune_state = tune_state;
25299a0bf528SMauro Carvalho Chehab 	return 0;
25309a0bf528SMauro Carvalho Chehab }
25319a0bf528SMauro Carvalho Chehab 
25329a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib0090_set_tune_state);
25339a0bf528SMauro Carvalho Chehab 
dib0090_get_frequency(struct dvb_frontend * fe,u32 * frequency)25349a0bf528SMauro Carvalho Chehab static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
25359a0bf528SMauro Carvalho Chehab {
25369a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
25379a0bf528SMauro Carvalho Chehab 
25389a0bf528SMauro Carvalho Chehab 	*frequency = 1000 * state->current_rf;
25399a0bf528SMauro Carvalho Chehab 	return 0;
25409a0bf528SMauro Carvalho Chehab }
25419a0bf528SMauro Carvalho Chehab 
dib0090_set_params(struct dvb_frontend * fe)25429a0bf528SMauro Carvalho Chehab static int dib0090_set_params(struct dvb_frontend *fe)
25439a0bf528SMauro Carvalho Chehab {
25449a0bf528SMauro Carvalho Chehab 	struct dib0090_state *state = fe->tuner_priv;
25459a0bf528SMauro Carvalho Chehab 	u32 ret;
25469a0bf528SMauro Carvalho Chehab 
25479a0bf528SMauro Carvalho Chehab 	state->tune_state = CT_TUNER_START;
25489a0bf528SMauro Carvalho Chehab 
25499a0bf528SMauro Carvalho Chehab 	do {
25509a0bf528SMauro Carvalho Chehab 		ret = dib0090_tune(fe);
25510de04ca1SMauro Carvalho Chehab 		if (ret == FE_CALLBACK_TIME_NEVER)
25529a0bf528SMauro Carvalho Chehab 			break;
25530de04ca1SMauro Carvalho Chehab 
25540de04ca1SMauro Carvalho Chehab 		/*
25550de04ca1SMauro Carvalho Chehab 		 * Despite dib0090_tune returns time at a 0.1 ms range,
25560de04ca1SMauro Carvalho Chehab 		 * the actual sleep time depends on CONFIG_HZ. The worse case
25570de04ca1SMauro Carvalho Chehab 		 * is when CONFIG_HZ=100. In such case, the minimum granularity
25580de04ca1SMauro Carvalho Chehab 		 * is 10ms. On some real field tests, the tuner sometimes don't
25590de04ca1SMauro Carvalho Chehab 		 * lock when this timer is lower than 10ms. So, enforce a 10ms
25600de04ca1SMauro Carvalho Chehab 		 * granularity and use usleep_range() instead of msleep().
25610de04ca1SMauro Carvalho Chehab 		 */
25620de04ca1SMauro Carvalho Chehab 		ret = 10 * (ret + 99)/100;
25630de04ca1SMauro Carvalho Chehab 		usleep_range(ret * 1000, (ret + 1) * 1000);
25649a0bf528SMauro Carvalho Chehab 	} while (state->tune_state != CT_TUNER_STOP);
25659a0bf528SMauro Carvalho Chehab 
25669a0bf528SMauro Carvalho Chehab 	return 0;
25679a0bf528SMauro Carvalho Chehab }
25689a0bf528SMauro Carvalho Chehab 
25699a0bf528SMauro Carvalho Chehab static const struct dvb_tuner_ops dib0090_ops = {
25709a0bf528SMauro Carvalho Chehab 	.info = {
25719a0bf528SMauro Carvalho Chehab 		 .name = "DiBcom DiB0090",
2572a3f90c75SMauro Carvalho Chehab 		 .frequency_min_hz  =  45 * MHz,
2573a3f90c75SMauro Carvalho Chehab 		 .frequency_max_hz  = 860 * MHz,
2574a3f90c75SMauro Carvalho Chehab 		 .frequency_step_hz =   1 * kHz,
25759a0bf528SMauro Carvalho Chehab 		 },
2576f2709c20SMauro Carvalho Chehab 	.release = dib0090_release,
25779a0bf528SMauro Carvalho Chehab 
25789a0bf528SMauro Carvalho Chehab 	.init = dib0090_wakeup,
25799a0bf528SMauro Carvalho Chehab 	.sleep = dib0090_sleep,
25809a0bf528SMauro Carvalho Chehab 	.set_params = dib0090_set_params,
25819a0bf528SMauro Carvalho Chehab 	.get_frequency = dib0090_get_frequency,
25829a0bf528SMauro Carvalho Chehab };
25839a0bf528SMauro Carvalho Chehab 
25849a0bf528SMauro Carvalho Chehab static const struct dvb_tuner_ops dib0090_fw_ops = {
25859a0bf528SMauro Carvalho Chehab 	.info = {
25869a0bf528SMauro Carvalho Chehab 		 .name = "DiBcom DiB0090",
2587a3f90c75SMauro Carvalho Chehab 		 .frequency_min_hz  =  45 * MHz,
2588a3f90c75SMauro Carvalho Chehab 		 .frequency_max_hz  = 860 * MHz,
2589a3f90c75SMauro Carvalho Chehab 		 .frequency_step_hz =   1 * kHz,
25909a0bf528SMauro Carvalho Chehab 		 },
2591f2709c20SMauro Carvalho Chehab 	.release = dib0090_release,
25929a0bf528SMauro Carvalho Chehab 
25939a0bf528SMauro Carvalho Chehab 	.init = NULL,
25949a0bf528SMauro Carvalho Chehab 	.sleep = NULL,
25959a0bf528SMauro Carvalho Chehab 	.set_params = NULL,
25969a0bf528SMauro Carvalho Chehab 	.get_frequency = NULL,
25979a0bf528SMauro Carvalho Chehab };
25989a0bf528SMauro Carvalho Chehab 
25999a0bf528SMauro Carvalho Chehab static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = {
26009a0bf528SMauro Carvalho Chehab 	{470, 0, 250, 0, 100, 4},
26019a0bf528SMauro Carvalho Chehab 	{860, 51, 866, 21, 375, 4},
26029a0bf528SMauro Carvalho Chehab 	{1700, 0, 800, 0, 850, 4},
26039a0bf528SMauro Carvalho Chehab 	{2900, 0, 250, 0, 100, 6},
26049a0bf528SMauro Carvalho Chehab 	{0xFFFF, 0, 0, 0, 0, 0},
26059a0bf528SMauro Carvalho Chehab };
26069a0bf528SMauro Carvalho Chehab 
dib0090_register(struct dvb_frontend * fe,struct i2c_adapter * i2c,const struct dib0090_config * config)26079a0bf528SMauro Carvalho Chehab struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
26089a0bf528SMauro Carvalho Chehab {
26099a0bf528SMauro Carvalho Chehab 	struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL);
26109a0bf528SMauro Carvalho Chehab 	if (st == NULL)
26119a0bf528SMauro Carvalho Chehab 		return NULL;
26129a0bf528SMauro Carvalho Chehab 
26139a0bf528SMauro Carvalho Chehab 	st->config = config;
26149a0bf528SMauro Carvalho Chehab 	st->i2c = i2c;
26159a0bf528SMauro Carvalho Chehab 	st->fe = fe;
26169a0bf528SMauro Carvalho Chehab 	mutex_init(&st->i2c_buffer_lock);
26179a0bf528SMauro Carvalho Chehab 	fe->tuner_priv = st;
26189a0bf528SMauro Carvalho Chehab 
26199a0bf528SMauro Carvalho Chehab 	if (config->wbd == NULL)
26209a0bf528SMauro Carvalho Chehab 		st->current_wbd_table = dib0090_wbd_table_default;
26219a0bf528SMauro Carvalho Chehab 	else
26229a0bf528SMauro Carvalho Chehab 		st->current_wbd_table = config->wbd;
26239a0bf528SMauro Carvalho Chehab 
26249a0bf528SMauro Carvalho Chehab 	if (dib0090_reset(fe) != 0)
26259a0bf528SMauro Carvalho Chehab 		goto free_mem;
26269a0bf528SMauro Carvalho Chehab 
26274bd1a8ddSMauro Carvalho Chehab 	pr_info("DiB0090: successfully identified\n");
26289a0bf528SMauro Carvalho Chehab 	memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops));
26299a0bf528SMauro Carvalho Chehab 
26309a0bf528SMauro Carvalho Chehab 	return fe;
26319a0bf528SMauro Carvalho Chehab  free_mem:
26329a0bf528SMauro Carvalho Chehab 	kfree(st);
26339a0bf528SMauro Carvalho Chehab 	fe->tuner_priv = NULL;
26349a0bf528SMauro Carvalho Chehab 	return NULL;
26359a0bf528SMauro Carvalho Chehab }
26369a0bf528SMauro Carvalho Chehab 
2637*86495af1SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(dib0090_register);
26389a0bf528SMauro Carvalho Chehab 
dib0090_fw_register(struct dvb_frontend * fe,struct i2c_adapter * i2c,const struct dib0090_config * config)26399a0bf528SMauro Carvalho Chehab struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
26409a0bf528SMauro Carvalho Chehab {
26419a0bf528SMauro Carvalho Chehab 	struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL);
26429a0bf528SMauro Carvalho Chehab 	if (st == NULL)
26439a0bf528SMauro Carvalho Chehab 		return NULL;
26449a0bf528SMauro Carvalho Chehab 
26459a0bf528SMauro Carvalho Chehab 	st->config = config;
26469a0bf528SMauro Carvalho Chehab 	st->i2c = i2c;
26479a0bf528SMauro Carvalho Chehab 	st->fe = fe;
26489a0bf528SMauro Carvalho Chehab 	mutex_init(&st->i2c_buffer_lock);
26499a0bf528SMauro Carvalho Chehab 	fe->tuner_priv = st;
26509a0bf528SMauro Carvalho Chehab 
26519a0bf528SMauro Carvalho Chehab 	if (dib0090_fw_reset_digital(fe, st->config) != 0)
26529a0bf528SMauro Carvalho Chehab 		goto free_mem;
26539a0bf528SMauro Carvalho Chehab 
26544bd1a8ddSMauro Carvalho Chehab 	dprintk("DiB0090 FW: successfully identified\n");
26559a0bf528SMauro Carvalho Chehab 	memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops));
26569a0bf528SMauro Carvalho Chehab 
26579a0bf528SMauro Carvalho Chehab 	return fe;
26589a0bf528SMauro Carvalho Chehab free_mem:
26599a0bf528SMauro Carvalho Chehab 	kfree(st);
26609a0bf528SMauro Carvalho Chehab 	fe->tuner_priv = NULL;
26619a0bf528SMauro Carvalho Chehab 	return NULL;
26629a0bf528SMauro Carvalho Chehab }
2663*86495af1SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(dib0090_fw_register);
26649a0bf528SMauro Carvalho Chehab 
266599e44da7SPatrick Boettcher MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
266699e44da7SPatrick Boettcher MODULE_AUTHOR("Olivier Grenie <olivier.grenie@parrot.com>");
26679a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner");
26689a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
2669