18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <linux/i2c.h>
138c2ecf20Sopenharmony_ci#include <linux/mutex.h>
148c2ecf20Sopenharmony_ci#include <asm/div64.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <media/dvb_math.h>
178c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "dib7000p.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic int debug;
228c2ecf20Sopenharmony_cimodule_param(debug, int, 0644);
238c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic int buggy_sfn_workaround;
268c2ecf20Sopenharmony_cimodule_param(buggy_sfn_workaround, int, 0644);
278c2ecf20Sopenharmony_ciMODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define dprintk(fmt, arg...) do {					\
308c2ecf20Sopenharmony_ci	if (debug)							\
318c2ecf20Sopenharmony_ci		printk(KERN_DEBUG pr_fmt("%s: " fmt),			\
328c2ecf20Sopenharmony_ci		       __func__, ##arg);				\
338c2ecf20Sopenharmony_ci} while (0)
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct i2c_device {
368c2ecf20Sopenharmony_ci	struct i2c_adapter *i2c_adap;
378c2ecf20Sopenharmony_ci	u8 i2c_addr;
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistruct dib7000p_state {
418c2ecf20Sopenharmony_ci	struct dvb_frontend demod;
428c2ecf20Sopenharmony_ci	struct dib7000p_config cfg;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	u8 i2c_addr;
458c2ecf20Sopenharmony_ci	struct i2c_adapter *i2c_adap;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	struct dibx000_i2c_master i2c_master;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	u16 wbd_ref;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	u8 current_band;
528c2ecf20Sopenharmony_ci	u32 current_bandwidth;
538c2ecf20Sopenharmony_ci	struct dibx000_agc_config *current_agc;
548c2ecf20Sopenharmony_ci	u32 timf;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	u8 div_force_off:1;
578c2ecf20Sopenharmony_ci	u8 div_state:1;
588c2ecf20Sopenharmony_ci	u16 div_sync_wait;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	u8 agc_state;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	u16 gpio_dir;
638c2ecf20Sopenharmony_ci	u16 gpio_val;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	u8 sfn_workaround_active:1;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#define SOC7090 0x7090
688c2ecf20Sopenharmony_ci	u16 version;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	u16 tuner_enable;
718c2ecf20Sopenharmony_ci	struct i2c_adapter dib7090_tuner_adap;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	/* for the I2C transfer */
748c2ecf20Sopenharmony_ci	struct i2c_msg msg[2];
758c2ecf20Sopenharmony_ci	u8 i2c_write_buffer[4];
768c2ecf20Sopenharmony_ci	u8 i2c_read_buffer[2];
778c2ecf20Sopenharmony_ci	struct mutex i2c_buffer_lock;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	u8 input_mode_mpeg;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	/* for DVBv5 stats */
828c2ecf20Sopenharmony_ci	s64 old_ucb;
838c2ecf20Sopenharmony_ci	unsigned long per_jiffies_stats;
848c2ecf20Sopenharmony_ci	unsigned long ber_jiffies_stats;
858c2ecf20Sopenharmony_ci	unsigned long get_stats_time;
868c2ecf20Sopenharmony_ci};
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cienum dib7000p_power_mode {
898c2ecf20Sopenharmony_ci	DIB7000P_POWER_ALL = 0,
908c2ecf20Sopenharmony_ci	DIB7000P_POWER_ANALOG_ADC,
918c2ecf20Sopenharmony_ci	DIB7000P_POWER_INTERFACE_ONLY,
928c2ecf20Sopenharmony_ci};
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci/* dib7090 specific functions */
958c2ecf20Sopenharmony_cistatic int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
968c2ecf20Sopenharmony_cistatic int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
978c2ecf20Sopenharmony_cistatic void dib7090_setDibTxMux(struct dib7000p_state *state, int mode);
988c2ecf20Sopenharmony_cistatic void dib7090_setHostBusMux(struct dib7000p_state *state, int mode);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	u16 ret;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
1058c2ecf20Sopenharmony_ci		dprintk("could not acquire lock\n");
1068c2ecf20Sopenharmony_ci		return 0;
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	state->i2c_write_buffer[0] = reg >> 8;
1108c2ecf20Sopenharmony_ci	state->i2c_write_buffer[1] = reg & 0xff;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
1138c2ecf20Sopenharmony_ci	state->msg[0].addr = state->i2c_addr >> 1;
1148c2ecf20Sopenharmony_ci	state->msg[0].flags = 0;
1158c2ecf20Sopenharmony_ci	state->msg[0].buf = state->i2c_write_buffer;
1168c2ecf20Sopenharmony_ci	state->msg[0].len = 2;
1178c2ecf20Sopenharmony_ci	state->msg[1].addr = state->i2c_addr >> 1;
1188c2ecf20Sopenharmony_ci	state->msg[1].flags = I2C_M_RD;
1198c2ecf20Sopenharmony_ci	state->msg[1].buf = state->i2c_read_buffer;
1208c2ecf20Sopenharmony_ci	state->msg[1].len = 2;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
1238c2ecf20Sopenharmony_ci		dprintk("i2c read error on %d\n", reg);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
1268c2ecf20Sopenharmony_ci	mutex_unlock(&state->i2c_buffer_lock);
1278c2ecf20Sopenharmony_ci	return ret;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	int ret;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
1358c2ecf20Sopenharmony_ci		dprintk("could not acquire lock\n");
1368c2ecf20Sopenharmony_ci		return -EINVAL;
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
1408c2ecf20Sopenharmony_ci	state->i2c_write_buffer[1] = reg & 0xff;
1418c2ecf20Sopenharmony_ci	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
1428c2ecf20Sopenharmony_ci	state->i2c_write_buffer[3] = val & 0xff;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
1458c2ecf20Sopenharmony_ci	state->msg[0].addr = state->i2c_addr >> 1;
1468c2ecf20Sopenharmony_ci	state->msg[0].flags = 0;
1478c2ecf20Sopenharmony_ci	state->msg[0].buf = state->i2c_write_buffer;
1488c2ecf20Sopenharmony_ci	state->msg[0].len = 4;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
1518c2ecf20Sopenharmony_ci			-EREMOTEIO : 0);
1528c2ecf20Sopenharmony_ci	mutex_unlock(&state->i2c_buffer_lock);
1538c2ecf20Sopenharmony_ci	return ret;
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	u16 l = 0, r, *n;
1598c2ecf20Sopenharmony_ci	n = buf;
1608c2ecf20Sopenharmony_ci	l = *n++;
1618c2ecf20Sopenharmony_ci	while (l) {
1628c2ecf20Sopenharmony_ci		r = *n++;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci		do {
1658c2ecf20Sopenharmony_ci			dib7000p_write_word(state, r, *n++);
1668c2ecf20Sopenharmony_ci			r++;
1678c2ecf20Sopenharmony_ci		} while (--l);
1688c2ecf20Sopenharmony_ci		l = *n++;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	int ret = 0;
1758c2ecf20Sopenharmony_ci	u16 outreg, fifo_threshold, smo_mode;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	outreg = 0;
1788c2ecf20Sopenharmony_ci	fifo_threshold = 1792;
1798c2ecf20Sopenharmony_ci	smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	dprintk("setting output mode for demod %p to %d\n", &state->demod, mode);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	switch (mode) {
1848c2ecf20Sopenharmony_ci	case OUTMODE_MPEG2_PAR_GATED_CLK:
1858c2ecf20Sopenharmony_ci		outreg = (1 << 10);	/* 0x0400 */
1868c2ecf20Sopenharmony_ci		break;
1878c2ecf20Sopenharmony_ci	case OUTMODE_MPEG2_PAR_CONT_CLK:
1888c2ecf20Sopenharmony_ci		outreg = (1 << 10) | (1 << 6);	/* 0x0440 */
1898c2ecf20Sopenharmony_ci		break;
1908c2ecf20Sopenharmony_ci	case OUTMODE_MPEG2_SERIAL:
1918c2ecf20Sopenharmony_ci		outreg = (1 << 10) | (2 << 6) | (0 << 1);	/* 0x0480 */
1928c2ecf20Sopenharmony_ci		break;
1938c2ecf20Sopenharmony_ci	case OUTMODE_DIVERSITY:
1948c2ecf20Sopenharmony_ci		if (state->cfg.hostbus_diversity)
1958c2ecf20Sopenharmony_ci			outreg = (1 << 10) | (4 << 6);	/* 0x0500 */
1968c2ecf20Sopenharmony_ci		else
1978c2ecf20Sopenharmony_ci			outreg = (1 << 11);
1988c2ecf20Sopenharmony_ci		break;
1998c2ecf20Sopenharmony_ci	case OUTMODE_MPEG2_FIFO:
2008c2ecf20Sopenharmony_ci		smo_mode |= (3 << 1);
2018c2ecf20Sopenharmony_ci		fifo_threshold = 512;
2028c2ecf20Sopenharmony_ci		outreg = (1 << 10) | (5 << 6);
2038c2ecf20Sopenharmony_ci		break;
2048c2ecf20Sopenharmony_ci	case OUTMODE_ANALOG_ADC:
2058c2ecf20Sopenharmony_ci		outreg = (1 << 10) | (3 << 6);
2068c2ecf20Sopenharmony_ci		break;
2078c2ecf20Sopenharmony_ci	case OUTMODE_HIGH_Z:
2088c2ecf20Sopenharmony_ci		outreg = 0;
2098c2ecf20Sopenharmony_ci		break;
2108c2ecf20Sopenharmony_ci	default:
2118c2ecf20Sopenharmony_ci		dprintk("Unhandled output_mode passed to be set for demod %p\n", &state->demod);
2128c2ecf20Sopenharmony_ci		break;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	if (state->cfg.output_mpeg2_in_188_bytes)
2168c2ecf20Sopenharmony_ci		smo_mode |= (1 << 5);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	ret |= dib7000p_write_word(state, 235, smo_mode);
2198c2ecf20Sopenharmony_ci	ret |= dib7000p_write_word(state, 236, fifo_threshold);	/* synchronous fread */
2208c2ecf20Sopenharmony_ci	if (state->version != SOC7090)
2218c2ecf20Sopenharmony_ci		ret |= dib7000p_write_word(state, 1286, outreg);	/* P_Div_active */
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	return ret;
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	struct dib7000p_state *state = demod->demodulator_priv;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	if (state->div_force_off) {
2318c2ecf20Sopenharmony_ci		dprintk("diversity combination deactivated - forced by COFDM parameters\n");
2328c2ecf20Sopenharmony_ci		onoff = 0;
2338c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 207, 0);
2348c2ecf20Sopenharmony_ci	} else
2358c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	state->div_state = (u8) onoff;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	if (onoff) {
2408c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 204, 6);
2418c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 205, 16);
2428c2ecf20Sopenharmony_ci		/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
2438c2ecf20Sopenharmony_ci	} else {
2448c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 204, 1);
2458c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 205, 0);
2468c2ecf20Sopenharmony_ci	}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	return 0;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	/* by default everything is powered off */
2548c2ecf20Sopenharmony_ci	u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	/* now, depending on the requested mode, we power on */
2578c2ecf20Sopenharmony_ci	switch (mode) {
2588c2ecf20Sopenharmony_ci		/* power up everything in the demod */
2598c2ecf20Sopenharmony_ci	case DIB7000P_POWER_ALL:
2608c2ecf20Sopenharmony_ci		reg_774 = 0x0000;
2618c2ecf20Sopenharmony_ci		reg_775 = 0x0000;
2628c2ecf20Sopenharmony_ci		reg_776 = 0x0;
2638c2ecf20Sopenharmony_ci		reg_899 = 0x0;
2648c2ecf20Sopenharmony_ci		if (state->version == SOC7090)
2658c2ecf20Sopenharmony_ci			reg_1280 &= 0x001f;
2668c2ecf20Sopenharmony_ci		else
2678c2ecf20Sopenharmony_ci			reg_1280 &= 0x01ff;
2688c2ecf20Sopenharmony_ci		break;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	case DIB7000P_POWER_ANALOG_ADC:
2718c2ecf20Sopenharmony_ci		/* dem, cfg, iqc, sad, agc */
2728c2ecf20Sopenharmony_ci		reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
2738c2ecf20Sopenharmony_ci		/* nud */
2748c2ecf20Sopenharmony_ci		reg_776 &= ~((1 << 0));
2758c2ecf20Sopenharmony_ci		/* Dout */
2768c2ecf20Sopenharmony_ci		if (state->version != SOC7090)
2778c2ecf20Sopenharmony_ci			reg_1280 &= ~((1 << 11));
2788c2ecf20Sopenharmony_ci		reg_1280 &= ~(1 << 6);
2798c2ecf20Sopenharmony_ci		fallthrough;
2808c2ecf20Sopenharmony_ci	case DIB7000P_POWER_INTERFACE_ONLY:
2818c2ecf20Sopenharmony_ci		/* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
2828c2ecf20Sopenharmony_ci		/* TODO power up either SDIO or I2C */
2838c2ecf20Sopenharmony_ci		if (state->version == SOC7090)
2848c2ecf20Sopenharmony_ci			reg_1280 &= ~((1 << 7) | (1 << 5));
2858c2ecf20Sopenharmony_ci		else
2868c2ecf20Sopenharmony_ci			reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
2878c2ecf20Sopenharmony_ci		break;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 774, reg_774);
2938c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 775, reg_775);
2948c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 776, reg_776);
2958c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1280, reg_1280);
2968c2ecf20Sopenharmony_ci	if (state->version != SOC7090)
2978c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 899, reg_899);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	return 0;
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	u16 reg_908 = 0, reg_909 = 0;
3058c2ecf20Sopenharmony_ci	u16 reg;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (state->version != SOC7090) {
3088c2ecf20Sopenharmony_ci		reg_908 = dib7000p_read_word(state, 908);
3098c2ecf20Sopenharmony_ci		reg_909 = dib7000p_read_word(state, 909);
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	switch (no) {
3138c2ecf20Sopenharmony_ci	case DIBX000_SLOW_ADC_ON:
3148c2ecf20Sopenharmony_ci		if (state->version == SOC7090) {
3158c2ecf20Sopenharmony_ci			reg = dib7000p_read_word(state, 1925);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci			dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2));	/* en_slowAdc = 1 & reset_sladc = 1 */
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci			reg = dib7000p_read_word(state, 1925);	/* read access to make it works... strange ... */
3208c2ecf20Sopenharmony_ci			msleep(200);
3218c2ecf20Sopenharmony_ci			dib7000p_write_word(state, 1925, reg & ~(1 << 4));	/* en_slowAdc = 1 & reset_sladc = 0 */
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci			reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
3248c2ecf20Sopenharmony_ci			dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524);	/* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
3258c2ecf20Sopenharmony_ci		} else {
3268c2ecf20Sopenharmony_ci			reg_909 |= (1 << 1) | (1 << 0);
3278c2ecf20Sopenharmony_ci			dib7000p_write_word(state, 909, reg_909);
3288c2ecf20Sopenharmony_ci			reg_909 &= ~(1 << 1);
3298c2ecf20Sopenharmony_ci		}
3308c2ecf20Sopenharmony_ci		break;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	case DIBX000_SLOW_ADC_OFF:
3338c2ecf20Sopenharmony_ci		if (state->version == SOC7090) {
3348c2ecf20Sopenharmony_ci			reg = dib7000p_read_word(state, 1925);
3358c2ecf20Sopenharmony_ci			dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4));	/* reset_sladc = 1 en_slowAdc = 0 */
3368c2ecf20Sopenharmony_ci		} else
3378c2ecf20Sopenharmony_ci			reg_909 |= (1 << 1) | (1 << 0);
3388c2ecf20Sopenharmony_ci		break;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	case DIBX000_ADC_ON:
3418c2ecf20Sopenharmony_ci		reg_908 &= 0x0fff;
3428c2ecf20Sopenharmony_ci		reg_909 &= 0x0003;
3438c2ecf20Sopenharmony_ci		break;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	case DIBX000_ADC_OFF:
3468c2ecf20Sopenharmony_ci		reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
3478c2ecf20Sopenharmony_ci		reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
3488c2ecf20Sopenharmony_ci		break;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	case DIBX000_VBG_ENABLE:
3518c2ecf20Sopenharmony_ci		reg_908 &= ~(1 << 15);
3528c2ecf20Sopenharmony_ci		break;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	case DIBX000_VBG_DISABLE:
3558c2ecf20Sopenharmony_ci		reg_908 |= (1 << 15);
3568c2ecf20Sopenharmony_ci		break;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	default:
3598c2ecf20Sopenharmony_ci		break;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci//	dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
3658c2ecf20Sopenharmony_ci	reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	if (state->version != SOC7090) {
3688c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 908, reg_908);
3698c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 909, reg_909);
3708c2ecf20Sopenharmony_ci	}
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	u32 timf;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	// store the current bandwidth for later use
3788c2ecf20Sopenharmony_ci	state->current_bandwidth = bw;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	if (state->timf == 0) {
3818c2ecf20Sopenharmony_ci		dprintk("using default timf\n");
3828c2ecf20Sopenharmony_ci		timf = state->cfg.bw->timf;
3838c2ecf20Sopenharmony_ci	} else {
3848c2ecf20Sopenharmony_ci		dprintk("using updated timf\n");
3858c2ecf20Sopenharmony_ci		timf = state->timf;
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	timf = timf * (bw / 50) / 160;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
3918c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	return 0;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_cistatic int dib7000p_sad_calib(struct dib7000p_state *state)
3978c2ecf20Sopenharmony_ci{
3988c2ecf20Sopenharmony_ci/* internal */
3998c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	if (state->version == SOC7090)
4028c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 74, 2048);
4038c2ecf20Sopenharmony_ci	else
4048c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 74, 776);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	/* do the calibration */
4078c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 73, (1 << 0));
4088c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 73, (0 << 0));
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	msleep(1);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	return 0;
4138c2ecf20Sopenharmony_ci}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cistatic int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci	struct dib7000p_state *state = demod->demodulator_priv;
4188c2ecf20Sopenharmony_ci	if (value > 4095)
4198c2ecf20Sopenharmony_ci		value = 4095;
4208c2ecf20Sopenharmony_ci	state->wbd_ref = value;
4218c2ecf20Sopenharmony_ci	return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cistatic int dib7000p_get_agc_values(struct dvb_frontend *fe,
4258c2ecf20Sopenharmony_ci		u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	if (agc_global != NULL)
4308c2ecf20Sopenharmony_ci		*agc_global = dib7000p_read_word(state, 394);
4318c2ecf20Sopenharmony_ci	if (agc1 != NULL)
4328c2ecf20Sopenharmony_ci		*agc1 = dib7000p_read_word(state, 392);
4338c2ecf20Sopenharmony_ci	if (agc2 != NULL)
4348c2ecf20Sopenharmony_ci		*agc2 = dib7000p_read_word(state, 393);
4358c2ecf20Sopenharmony_ci	if (wbd != NULL)
4368c2ecf20Sopenharmony_ci		*wbd = dib7000p_read_word(state, 397);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	return 0;
4398c2ecf20Sopenharmony_ci}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_cistatic int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
4448c2ecf20Sopenharmony_ci	return dib7000p_write_word(state, 108,  v);
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_cistatic void dib7000p_reset_pll(struct dib7000p_state *state)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
4508c2ecf20Sopenharmony_ci	u16 clk_cfg0;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	if (state->version == SOC7090) {
4538c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 1856, (!bw->pll_reset << 13) | (bw->pll_range << 12) | (bw->pll_ratio << 6) | (bw->pll_prediv));
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci		while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
4568c2ecf20Sopenharmony_ci			;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
4598c2ecf20Sopenharmony_ci	} else {
4608c2ecf20Sopenharmony_ci		/* force PLL bypass */
4618c2ecf20Sopenharmony_ci		clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
4628c2ecf20Sopenharmony_ci			(bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 900, clk_cfg0);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci		/* P_pll_cfg */
4678c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
4688c2ecf20Sopenharmony_ci		clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
4698c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 900, clk_cfg0);
4708c2ecf20Sopenharmony_ci	}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
4738c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
4748c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
4758c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 72, bw->sad_cfg);
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_cistatic u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
4838c2ecf20Sopenharmony_ci	internal |= (u32) dib7000p_read_word(state, 19);
4848c2ecf20Sopenharmony_ci	internal /= 1000;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	return internal;
4878c2ecf20Sopenharmony_ci}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_cistatic int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
4928c2ecf20Sopenharmony_ci	u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
4938c2ecf20Sopenharmony_ci	u8 loopdiv, prediv;
4948c2ecf20Sopenharmony_ci	u32 internal, xtal;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	/* get back old values */
4978c2ecf20Sopenharmony_ci	prediv = reg_1856 & 0x3f;
4988c2ecf20Sopenharmony_ci	loopdiv = (reg_1856 >> 6) & 0x3f;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	if (loopdiv && bw && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
5018c2ecf20Sopenharmony_ci		dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)\n", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
5028c2ecf20Sopenharmony_ci		reg_1856 &= 0xf000;
5038c2ecf20Sopenharmony_ci		reg_1857 = dib7000p_read_word(state, 1857);
5048c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci		/* write new system clk into P_sec_len */
5098c2ecf20Sopenharmony_ci		internal = dib7000p_get_internal_freq(state);
5108c2ecf20Sopenharmony_ci		xtal = (internal / loopdiv) * prediv;
5118c2ecf20Sopenharmony_ci		internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio;	/* new internal */
5128c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
5138c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci		while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
5188c2ecf20Sopenharmony_ci			dprintk("Waiting for PLL to lock\n");
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci		return 0;
5218c2ecf20Sopenharmony_ci	}
5228c2ecf20Sopenharmony_ci	return -EIO;
5238c2ecf20Sopenharmony_ci}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_cistatic int dib7000p_reset_gpio(struct dib7000p_state *st)
5268c2ecf20Sopenharmony_ci{
5278c2ecf20Sopenharmony_ci	/* reset the GPIOs */
5288c2ecf20Sopenharmony_ci	dprintk("gpio dir: %x: val: %x, pwm_pos: %x\n", st->gpio_dir, st->gpio_val, st->cfg.gpio_pwm_pos);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	dib7000p_write_word(st, 1029, st->gpio_dir);
5318c2ecf20Sopenharmony_ci	dib7000p_write_word(st, 1030, st->gpio_val);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	/* TODO 1031 is P_gpio_od */
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
5388c2ecf20Sopenharmony_ci	return 0;
5398c2ecf20Sopenharmony_ci}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_cistatic int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
5428c2ecf20Sopenharmony_ci{
5438c2ecf20Sopenharmony_ci	st->gpio_dir = dib7000p_read_word(st, 1029);
5448c2ecf20Sopenharmony_ci	st->gpio_dir &= ~(1 << num);	/* reset the direction bit */
5458c2ecf20Sopenharmony_ci	st->gpio_dir |= (dir & 0x1) << num;	/* set the new direction */
5468c2ecf20Sopenharmony_ci	dib7000p_write_word(st, 1029, st->gpio_dir);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	st->gpio_val = dib7000p_read_word(st, 1030);
5498c2ecf20Sopenharmony_ci	st->gpio_val &= ~(1 << num);	/* reset the direction bit */
5508c2ecf20Sopenharmony_ci	st->gpio_val |= (val & 0x01) << num;	/* set the new value */
5518c2ecf20Sopenharmony_ci	dib7000p_write_word(st, 1030, st->gpio_val);
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	return 0;
5548c2ecf20Sopenharmony_ci}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_cistatic int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	struct dib7000p_state *state = demod->demodulator_priv;
5598c2ecf20Sopenharmony_ci	return dib7000p_cfg_gpio(state, num, dir, val);
5608c2ecf20Sopenharmony_ci}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_cistatic u16 dib7000p_defaults[] = {
5638c2ecf20Sopenharmony_ci	// auto search configuration
5648c2ecf20Sopenharmony_ci	3, 2,
5658c2ecf20Sopenharmony_ci	0x0004,
5668c2ecf20Sopenharmony_ci	(1<<3)|(1<<11)|(1<<12)|(1<<13),
5678c2ecf20Sopenharmony_ci	0x0814,			/* Equal Lock */
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	12, 6,
5708c2ecf20Sopenharmony_ci	0x001b,
5718c2ecf20Sopenharmony_ci	0x7740,
5728c2ecf20Sopenharmony_ci	0x005b,
5738c2ecf20Sopenharmony_ci	0x8d80,
5748c2ecf20Sopenharmony_ci	0x01c9,
5758c2ecf20Sopenharmony_ci	0xc380,
5768c2ecf20Sopenharmony_ci	0x0000,
5778c2ecf20Sopenharmony_ci	0x0080,
5788c2ecf20Sopenharmony_ci	0x0000,
5798c2ecf20Sopenharmony_ci	0x0090,
5808c2ecf20Sopenharmony_ci	0x0001,
5818c2ecf20Sopenharmony_ci	0xd4c0,
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	1, 26,
5848c2ecf20Sopenharmony_ci	0x6680,
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	/* set ADC level to -16 */
5878c2ecf20Sopenharmony_ci	11, 79,
5888c2ecf20Sopenharmony_ci	(1 << 13) - 825 - 117,
5898c2ecf20Sopenharmony_ci	(1 << 13) - 837 - 117,
5908c2ecf20Sopenharmony_ci	(1 << 13) - 811 - 117,
5918c2ecf20Sopenharmony_ci	(1 << 13) - 766 - 117,
5928c2ecf20Sopenharmony_ci	(1 << 13) - 737 - 117,
5938c2ecf20Sopenharmony_ci	(1 << 13) - 693 - 117,
5948c2ecf20Sopenharmony_ci	(1 << 13) - 648 - 117,
5958c2ecf20Sopenharmony_ci	(1 << 13) - 619 - 117,
5968c2ecf20Sopenharmony_ci	(1 << 13) - 575 - 117,
5978c2ecf20Sopenharmony_ci	(1 << 13) - 531 - 117,
5988c2ecf20Sopenharmony_ci	(1 << 13) - 501 - 117,
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	1, 142,
6018c2ecf20Sopenharmony_ci	0x0410,
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	/* disable power smoothing */
6048c2ecf20Sopenharmony_ci	8, 145,
6058c2ecf20Sopenharmony_ci	0,
6068c2ecf20Sopenharmony_ci	0,
6078c2ecf20Sopenharmony_ci	0,
6088c2ecf20Sopenharmony_ci	0,
6098c2ecf20Sopenharmony_ci	0,
6108c2ecf20Sopenharmony_ci	0,
6118c2ecf20Sopenharmony_ci	0,
6128c2ecf20Sopenharmony_ci	0,
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	1, 154,
6158c2ecf20Sopenharmony_ci	1 << 13,
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	1, 168,
6188c2ecf20Sopenharmony_ci	0x0ccd,
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	1, 183,
6218c2ecf20Sopenharmony_ci	0x200f,
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	1, 212,
6248c2ecf20Sopenharmony_ci		0x169,
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	5, 187,
6278c2ecf20Sopenharmony_ci	0x023d,
6288c2ecf20Sopenharmony_ci	0x00a4,
6298c2ecf20Sopenharmony_ci	0x00a4,
6308c2ecf20Sopenharmony_ci	0x7ff0,
6318c2ecf20Sopenharmony_ci	0x3ccc,
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	1, 198,
6348c2ecf20Sopenharmony_ci	0x800,
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	1, 222,
6378c2ecf20Sopenharmony_ci	0x0010,
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	1, 235,
6408c2ecf20Sopenharmony_ci	0x0062,
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	0,
6438c2ecf20Sopenharmony_ci};
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_cistatic void dib7000p_reset_stats(struct dvb_frontend *fe);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_cistatic int dib7000p_demod_reset(struct dib7000p_state *state)
6488c2ecf20Sopenharmony_ci{
6498c2ecf20Sopenharmony_ci	dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	if (state->version == SOC7090)
6528c2ecf20Sopenharmony_ci		dibx000_reset_i2c_master(&state->i2c_master);
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	/* restart all parts */
6578c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 770, 0xffff);
6588c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 771, 0xffff);
6598c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 772, 0x001f);
6608c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 770, 0);
6638c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 771, 0);
6648c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 772, 0);
6658c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1280, 0);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	if (state->version != SOC7090) {
6688c2ecf20Sopenharmony_ci		dib7000p_write_word(state,  898, 0x0003);
6698c2ecf20Sopenharmony_ci		dib7000p_write_word(state,  898, 0);
6708c2ecf20Sopenharmony_ci	}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	/* default */
6738c2ecf20Sopenharmony_ci	dib7000p_reset_pll(state);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	if (dib7000p_reset_gpio(state) != 0)
6768c2ecf20Sopenharmony_ci		dprintk("GPIO reset was not successful.\n");
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	if (state->version == SOC7090) {
6798c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 899, 0);
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci		/* impulse noise */
6828c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
6838c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
6848c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
6858c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 273, (0<<6) | 30);
6868c2ecf20Sopenharmony_ci	}
6878c2ecf20Sopenharmony_ci	if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
6888c2ecf20Sopenharmony_ci		dprintk("OUTPUT_MODE could not be reset.\n");
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
6918c2ecf20Sopenharmony_ci	dib7000p_sad_calib(state);
6928c2ecf20Sopenharmony_ci	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	/* unforce divstr regardless whether i2c enumeration was done or not */
6958c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	dib7000p_set_bandwidth(state, 8000);
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	if (state->version == SOC7090) {
7008c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 36, 0x0755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
7018c2ecf20Sopenharmony_ci	} else {
7028c2ecf20Sopenharmony_ci		if (state->cfg.tuner_is_baseband)
7038c2ecf20Sopenharmony_ci			dib7000p_write_word(state, 36, 0x0755);
7048c2ecf20Sopenharmony_ci		else
7058c2ecf20Sopenharmony_ci			dib7000p_write_word(state, 36, 0x1f55);
7068c2ecf20Sopenharmony_ci	}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	dib7000p_write_tab(state, dib7000p_defaults);
7098c2ecf20Sopenharmony_ci	if (state->version != SOC7090) {
7108c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 901, 0x0006);
7118c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
7128c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 905, 0x2c8e);
7138c2ecf20Sopenharmony_ci	}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	return 0;
7188c2ecf20Sopenharmony_ci}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_cistatic void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
7218c2ecf20Sopenharmony_ci{
7228c2ecf20Sopenharmony_ci	u16 tmp = 0;
7238c2ecf20Sopenharmony_ci	tmp = dib7000p_read_word(state, 903);
7248c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 903, (tmp | 0x1));
7258c2ecf20Sopenharmony_ci	tmp = dib7000p_read_word(state, 900);
7268c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
7278c2ecf20Sopenharmony_ci}
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_cistatic void dib7000p_restart_agc(struct dib7000p_state *state)
7308c2ecf20Sopenharmony_ci{
7318c2ecf20Sopenharmony_ci	// P_restart_iqc & P_restart_agc
7328c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
7338c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 770, 0x0000);
7348c2ecf20Sopenharmony_ci}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_cistatic int dib7000p_update_lna(struct dib7000p_state *state)
7378c2ecf20Sopenharmony_ci{
7388c2ecf20Sopenharmony_ci	u16 dyn_gain;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	if (state->cfg.update_lna) {
7418c2ecf20Sopenharmony_ci		dyn_gain = dib7000p_read_word(state, 394);
7428c2ecf20Sopenharmony_ci		if (state->cfg.update_lna(&state->demod, dyn_gain)) {
7438c2ecf20Sopenharmony_ci			dib7000p_restart_agc(state);
7448c2ecf20Sopenharmony_ci			return 1;
7458c2ecf20Sopenharmony_ci		}
7468c2ecf20Sopenharmony_ci	}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	return 0;
7498c2ecf20Sopenharmony_ci}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_cistatic int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
7528c2ecf20Sopenharmony_ci{
7538c2ecf20Sopenharmony_ci	struct dibx000_agc_config *agc = NULL;
7548c2ecf20Sopenharmony_ci	int i;
7558c2ecf20Sopenharmony_ci	if (state->current_band == band && state->current_agc != NULL)
7568c2ecf20Sopenharmony_ci		return 0;
7578c2ecf20Sopenharmony_ci	state->current_band = band;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	for (i = 0; i < state->cfg.agc_config_count; i++)
7608c2ecf20Sopenharmony_ci		if (state->cfg.agc[i].band_caps & band) {
7618c2ecf20Sopenharmony_ci			agc = &state->cfg.agc[i];
7628c2ecf20Sopenharmony_ci			break;
7638c2ecf20Sopenharmony_ci		}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	if (agc == NULL) {
7668c2ecf20Sopenharmony_ci		dprintk("no valid AGC configuration found for band 0x%02x\n", band);
7678c2ecf20Sopenharmony_ci		return -EINVAL;
7688c2ecf20Sopenharmony_ci	}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	state->current_agc = agc;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	/* AGC */
7738c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 75, agc->setup);
7748c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 76, agc->inv_gain);
7758c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 77, agc->time_stabiliz);
7768c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	// Demod AGC loop configuration
7798c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
7808c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	/* AGC continued */
7838c2ecf20Sopenharmony_ci	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
7848c2ecf20Sopenharmony_ci		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	if (state->wbd_ref != 0)
7878c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
7888c2ecf20Sopenharmony_ci	else
7898c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 107, agc->agc1_max);
7948c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 108, agc->agc1_min);
7958c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 109, agc->agc2_max);
7968c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 110, agc->agc2_min);
7978c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
7988c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 112, agc->agc1_pt3);
7998c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
8008c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
8018c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
8028c2ecf20Sopenharmony_ci	return 0;
8038c2ecf20Sopenharmony_ci}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_cistatic int dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
8068c2ecf20Sopenharmony_ci{
8078c2ecf20Sopenharmony_ci	u32 internal = dib7000p_get_internal_freq(state);
8088c2ecf20Sopenharmony_ci	s32 unit_khz_dds_val;
8098c2ecf20Sopenharmony_ci	u32 abs_offset_khz = abs(offset_khz);
8108c2ecf20Sopenharmony_ci	u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
8118c2ecf20Sopenharmony_ci	u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
8128c2ecf20Sopenharmony_ci	if (internal == 0) {
8138c2ecf20Sopenharmony_ci		pr_warn("DIB7000P: dib7000p_get_internal_freq returned 0\n");
8148c2ecf20Sopenharmony_ci		return -1;
8158c2ecf20Sopenharmony_ci	}
8168c2ecf20Sopenharmony_ci	/* 2**26 / Fsampling is the unit 1KHz offset */
8178c2ecf20Sopenharmony_ci	unit_khz_dds_val = 67108864 / (internal);
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d\n", offset_khz, internal, invert);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	if (offset_khz < 0)
8228c2ecf20Sopenharmony_ci		unit_khz_dds_val *= -1;
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	/* IF tuner */
8258c2ecf20Sopenharmony_ci	if (invert)
8268c2ecf20Sopenharmony_ci		dds -= (abs_offset_khz * unit_khz_dds_val);	/* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */
8278c2ecf20Sopenharmony_ci	else
8288c2ecf20Sopenharmony_ci		dds += (abs_offset_khz * unit_khz_dds_val);
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	if (abs_offset_khz <= (internal / 2)) {	/* Max dds offset is the half of the demod freq */
8318c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
8328c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
8338c2ecf20Sopenharmony_ci	}
8348c2ecf20Sopenharmony_ci	return 0;
8358c2ecf20Sopenharmony_ci}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_cistatic int dib7000p_agc_startup(struct dvb_frontend *demod)
8388c2ecf20Sopenharmony_ci{
8398c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
8408c2ecf20Sopenharmony_ci	struct dib7000p_state *state = demod->demodulator_priv;
8418c2ecf20Sopenharmony_ci	int ret = -1;
8428c2ecf20Sopenharmony_ci	u8 *agc_state = &state->agc_state;
8438c2ecf20Sopenharmony_ci	u8 agc_split;
8448c2ecf20Sopenharmony_ci	u16 reg;
8458c2ecf20Sopenharmony_ci	u32 upd_demod_gain_period = 0x1000;
8468c2ecf20Sopenharmony_ci	s32 frequency_offset = 0;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	switch (state->agc_state) {
8498c2ecf20Sopenharmony_ci	case 0:
8508c2ecf20Sopenharmony_ci		dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
8518c2ecf20Sopenharmony_ci		if (state->version == SOC7090) {
8528c2ecf20Sopenharmony_ci			reg = dib7000p_read_word(state, 0x79b) & 0xff00;
8538c2ecf20Sopenharmony_ci			dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF);	/* lsb */
8548c2ecf20Sopenharmony_ci			dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci			/* enable adc i & q */
8578c2ecf20Sopenharmony_ci			reg = dib7000p_read_word(state, 0x780);
8588c2ecf20Sopenharmony_ci			dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
8598c2ecf20Sopenharmony_ci		} else {
8608c2ecf20Sopenharmony_ci			dib7000p_set_adc_state(state, DIBX000_ADC_ON);
8618c2ecf20Sopenharmony_ci			dib7000p_pll_clk_cfg(state);
8628c2ecf20Sopenharmony_ci		}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci		if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
8658c2ecf20Sopenharmony_ci			return -1;
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci		if (demod->ops.tuner_ops.get_frequency) {
8688c2ecf20Sopenharmony_ci			u32 frequency_tuner;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci			demod->ops.tuner_ops.get_frequency(demod, &frequency_tuner);
8718c2ecf20Sopenharmony_ci			frequency_offset = (s32)frequency_tuner / 1000 - ch->frequency / 1000;
8728c2ecf20Sopenharmony_ci		}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci		if (dib7000p_set_dds(state, frequency_offset) < 0)
8758c2ecf20Sopenharmony_ci			return -1;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci		ret = 7;
8788c2ecf20Sopenharmony_ci		(*agc_state)++;
8798c2ecf20Sopenharmony_ci		break;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	case 1:
8828c2ecf20Sopenharmony_ci		if (state->cfg.agc_control)
8838c2ecf20Sopenharmony_ci			state->cfg.agc_control(&state->demod, 1);
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 78, 32768);
8868c2ecf20Sopenharmony_ci		if (!state->current_agc->perform_agc_softsplit) {
8878c2ecf20Sopenharmony_ci			/* we are using the wbd - so slow AGC startup */
8888c2ecf20Sopenharmony_ci			/* force 0 split on WBD and restart AGC */
8898c2ecf20Sopenharmony_ci			dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
8908c2ecf20Sopenharmony_ci			(*agc_state)++;
8918c2ecf20Sopenharmony_ci			ret = 5;
8928c2ecf20Sopenharmony_ci		} else {
8938c2ecf20Sopenharmony_ci			/* default AGC startup */
8948c2ecf20Sopenharmony_ci			(*agc_state) = 4;
8958c2ecf20Sopenharmony_ci			/* wait AGC rough lock time */
8968c2ecf20Sopenharmony_ci			ret = 7;
8978c2ecf20Sopenharmony_ci		}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci		dib7000p_restart_agc(state);
9008c2ecf20Sopenharmony_ci		break;
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	case 2:		/* fast split search path after 5sec */
9038c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4));	/* freeze AGC loop */
9048c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8));	/* fast split search 0.25kHz */
9058c2ecf20Sopenharmony_ci		(*agc_state)++;
9068c2ecf20Sopenharmony_ci		ret = 14;
9078c2ecf20Sopenharmony_ci		break;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	case 3:		/* split search ended */
9108c2ecf20Sopenharmony_ci		agc_split = (u8) dib7000p_read_word(state, 396);	/* store the split value for the next time */
9118c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 78, dib7000p_read_word(state, 394));	/* set AGC gain start value */
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 75, state->current_agc->setup);	/* std AGC loop */
9148c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split);	/* standard split search */
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci		dib7000p_restart_agc(state);
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci		dprintk("SPLIT %p: %u\n", demod, agc_split);
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci		(*agc_state)++;
9218c2ecf20Sopenharmony_ci		ret = 5;
9228c2ecf20Sopenharmony_ci		break;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	case 4:		/* LNA startup */
9258c2ecf20Sopenharmony_ci		ret = 7;
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci		if (dib7000p_update_lna(state))
9288c2ecf20Sopenharmony_ci			ret = 5;
9298c2ecf20Sopenharmony_ci		else
9308c2ecf20Sopenharmony_ci			(*agc_state)++;
9318c2ecf20Sopenharmony_ci		break;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	case 5:
9348c2ecf20Sopenharmony_ci		if (state->cfg.agc_control)
9358c2ecf20Sopenharmony_ci			state->cfg.agc_control(&state->demod, 0);
9368c2ecf20Sopenharmony_ci		(*agc_state)++;
9378c2ecf20Sopenharmony_ci		break;
9388c2ecf20Sopenharmony_ci	default:
9398c2ecf20Sopenharmony_ci		break;
9408c2ecf20Sopenharmony_ci	}
9418c2ecf20Sopenharmony_ci	return ret;
9428c2ecf20Sopenharmony_ci}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_cistatic void dib7000p_update_timf(struct dib7000p_state *state)
9458c2ecf20Sopenharmony_ci{
9468c2ecf20Sopenharmony_ci	u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
9478c2ecf20Sopenharmony_ci	state->timf = timf * 160 / (state->current_bandwidth / 50);
9488c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 23, (u16) (timf >> 16));
9498c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
9508c2ecf20Sopenharmony_ci	dprintk("updated timf_frequency: %d (default: %d)\n", state->timf, state->cfg.bw->timf);
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_cistatic u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
9558c2ecf20Sopenharmony_ci{
9568c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
9578c2ecf20Sopenharmony_ci	switch (op) {
9588c2ecf20Sopenharmony_ci	case DEMOD_TIMF_SET:
9598c2ecf20Sopenharmony_ci		state->timf = timf;
9608c2ecf20Sopenharmony_ci		break;
9618c2ecf20Sopenharmony_ci	case DEMOD_TIMF_UPDATE:
9628c2ecf20Sopenharmony_ci		dib7000p_update_timf(state);
9638c2ecf20Sopenharmony_ci		break;
9648c2ecf20Sopenharmony_ci	case DEMOD_TIMF_GET:
9658c2ecf20Sopenharmony_ci		break;
9668c2ecf20Sopenharmony_ci	}
9678c2ecf20Sopenharmony_ci	dib7000p_set_bandwidth(state, state->current_bandwidth);
9688c2ecf20Sopenharmony_ci	return state->timf;
9698c2ecf20Sopenharmony_ci}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_cistatic void dib7000p_set_channel(struct dib7000p_state *state,
9728c2ecf20Sopenharmony_ci				 struct dtv_frontend_properties *ch, u8 seq)
9738c2ecf20Sopenharmony_ci{
9748c2ecf20Sopenharmony_ci	u16 value, est[4];
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	/* nfft, guard, qam, alpha */
9798c2ecf20Sopenharmony_ci	value = 0;
9808c2ecf20Sopenharmony_ci	switch (ch->transmission_mode) {
9818c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_2K:
9828c2ecf20Sopenharmony_ci		value |= (0 << 7);
9838c2ecf20Sopenharmony_ci		break;
9848c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_4K:
9858c2ecf20Sopenharmony_ci		value |= (2 << 7);
9868c2ecf20Sopenharmony_ci		break;
9878c2ecf20Sopenharmony_ci	default:
9888c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_8K:
9898c2ecf20Sopenharmony_ci		value |= (1 << 7);
9908c2ecf20Sopenharmony_ci		break;
9918c2ecf20Sopenharmony_ci	}
9928c2ecf20Sopenharmony_ci	switch (ch->guard_interval) {
9938c2ecf20Sopenharmony_ci	case GUARD_INTERVAL_1_32:
9948c2ecf20Sopenharmony_ci		value |= (0 << 5);
9958c2ecf20Sopenharmony_ci		break;
9968c2ecf20Sopenharmony_ci	case GUARD_INTERVAL_1_16:
9978c2ecf20Sopenharmony_ci		value |= (1 << 5);
9988c2ecf20Sopenharmony_ci		break;
9998c2ecf20Sopenharmony_ci	case GUARD_INTERVAL_1_4:
10008c2ecf20Sopenharmony_ci		value |= (3 << 5);
10018c2ecf20Sopenharmony_ci		break;
10028c2ecf20Sopenharmony_ci	default:
10038c2ecf20Sopenharmony_ci	case GUARD_INTERVAL_1_8:
10048c2ecf20Sopenharmony_ci		value |= (2 << 5);
10058c2ecf20Sopenharmony_ci		break;
10068c2ecf20Sopenharmony_ci	}
10078c2ecf20Sopenharmony_ci	switch (ch->modulation) {
10088c2ecf20Sopenharmony_ci	case QPSK:
10098c2ecf20Sopenharmony_ci		value |= (0 << 3);
10108c2ecf20Sopenharmony_ci		break;
10118c2ecf20Sopenharmony_ci	case QAM_16:
10128c2ecf20Sopenharmony_ci		value |= (1 << 3);
10138c2ecf20Sopenharmony_ci		break;
10148c2ecf20Sopenharmony_ci	default:
10158c2ecf20Sopenharmony_ci	case QAM_64:
10168c2ecf20Sopenharmony_ci		value |= (2 << 3);
10178c2ecf20Sopenharmony_ci		break;
10188c2ecf20Sopenharmony_ci	}
10198c2ecf20Sopenharmony_ci	switch (HIERARCHY_1) {
10208c2ecf20Sopenharmony_ci	case HIERARCHY_2:
10218c2ecf20Sopenharmony_ci		value |= 2;
10228c2ecf20Sopenharmony_ci		break;
10238c2ecf20Sopenharmony_ci	case HIERARCHY_4:
10248c2ecf20Sopenharmony_ci		value |= 4;
10258c2ecf20Sopenharmony_ci		break;
10268c2ecf20Sopenharmony_ci	default:
10278c2ecf20Sopenharmony_ci	case HIERARCHY_1:
10288c2ecf20Sopenharmony_ci		value |= 1;
10298c2ecf20Sopenharmony_ci		break;
10308c2ecf20Sopenharmony_ci	}
10318c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 0, value);
10328c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 5, (seq << 4) | 1);	/* do not force tps, search list 0 */
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	/* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
10358c2ecf20Sopenharmony_ci	value = 0;
10368c2ecf20Sopenharmony_ci	if (1 != 0)
10378c2ecf20Sopenharmony_ci		value |= (1 << 6);
10388c2ecf20Sopenharmony_ci	if (ch->hierarchy == 1)
10398c2ecf20Sopenharmony_ci		value |= (1 << 4);
10408c2ecf20Sopenharmony_ci	if (1 == 1)
10418c2ecf20Sopenharmony_ci		value |= 1;
10428c2ecf20Sopenharmony_ci	switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
10438c2ecf20Sopenharmony_ci	case FEC_2_3:
10448c2ecf20Sopenharmony_ci		value |= (2 << 1);
10458c2ecf20Sopenharmony_ci		break;
10468c2ecf20Sopenharmony_ci	case FEC_3_4:
10478c2ecf20Sopenharmony_ci		value |= (3 << 1);
10488c2ecf20Sopenharmony_ci		break;
10498c2ecf20Sopenharmony_ci	case FEC_5_6:
10508c2ecf20Sopenharmony_ci		value |= (5 << 1);
10518c2ecf20Sopenharmony_ci		break;
10528c2ecf20Sopenharmony_ci	case FEC_7_8:
10538c2ecf20Sopenharmony_ci		value |= (7 << 1);
10548c2ecf20Sopenharmony_ci		break;
10558c2ecf20Sopenharmony_ci	default:
10568c2ecf20Sopenharmony_ci	case FEC_1_2:
10578c2ecf20Sopenharmony_ci		value |= (1 << 1);
10588c2ecf20Sopenharmony_ci		break;
10598c2ecf20Sopenharmony_ci	}
10608c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 208, value);
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	/* offset loop parameters */
10638c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 26, 0x6680);
10648c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 32, 0x0003);
10658c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 29, 0x1273);
10668c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 33, 0x0005);
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	/* P_dvsy_sync_wait */
10698c2ecf20Sopenharmony_ci	switch (ch->transmission_mode) {
10708c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_8K:
10718c2ecf20Sopenharmony_ci		value = 256;
10728c2ecf20Sopenharmony_ci		break;
10738c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_4K:
10748c2ecf20Sopenharmony_ci		value = 128;
10758c2ecf20Sopenharmony_ci		break;
10768c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_2K:
10778c2ecf20Sopenharmony_ci	default:
10788c2ecf20Sopenharmony_ci		value = 64;
10798c2ecf20Sopenharmony_ci		break;
10808c2ecf20Sopenharmony_ci	}
10818c2ecf20Sopenharmony_ci	switch (ch->guard_interval) {
10828c2ecf20Sopenharmony_ci	case GUARD_INTERVAL_1_16:
10838c2ecf20Sopenharmony_ci		value *= 2;
10848c2ecf20Sopenharmony_ci		break;
10858c2ecf20Sopenharmony_ci	case GUARD_INTERVAL_1_8:
10868c2ecf20Sopenharmony_ci		value *= 4;
10878c2ecf20Sopenharmony_ci		break;
10888c2ecf20Sopenharmony_ci	case GUARD_INTERVAL_1_4:
10898c2ecf20Sopenharmony_ci		value *= 8;
10908c2ecf20Sopenharmony_ci		break;
10918c2ecf20Sopenharmony_ci	default:
10928c2ecf20Sopenharmony_ci	case GUARD_INTERVAL_1_32:
10938c2ecf20Sopenharmony_ci		value *= 1;
10948c2ecf20Sopenharmony_ci		break;
10958c2ecf20Sopenharmony_ci	}
10968c2ecf20Sopenharmony_ci	if (state->cfg.diversity_delay == 0)
10978c2ecf20Sopenharmony_ci		state->div_sync_wait = (value * 3) / 2 + 48;
10988c2ecf20Sopenharmony_ci	else
10998c2ecf20Sopenharmony_ci		state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	/* deactivate the possibility of diversity reception if extended interleaver */
11028c2ecf20Sopenharmony_ci	state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K;
11038c2ecf20Sopenharmony_ci	dib7000p_set_diversity_in(&state->demod, state->div_state);
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	/* channel estimation fine configuration */
11068c2ecf20Sopenharmony_ci	switch (ch->modulation) {
11078c2ecf20Sopenharmony_ci	case QAM_64:
11088c2ecf20Sopenharmony_ci		est[0] = 0x0148;	/* P_adp_regul_cnt 0.04 */
11098c2ecf20Sopenharmony_ci		est[1] = 0xfff0;	/* P_adp_noise_cnt -0.002 */
11108c2ecf20Sopenharmony_ci		est[2] = 0x00a4;	/* P_adp_regul_ext 0.02 */
11118c2ecf20Sopenharmony_ci		est[3] = 0xfff8;	/* P_adp_noise_ext -0.001 */
11128c2ecf20Sopenharmony_ci		break;
11138c2ecf20Sopenharmony_ci	case QAM_16:
11148c2ecf20Sopenharmony_ci		est[0] = 0x023d;	/* P_adp_regul_cnt 0.07 */
11158c2ecf20Sopenharmony_ci		est[1] = 0xffdf;	/* P_adp_noise_cnt -0.004 */
11168c2ecf20Sopenharmony_ci		est[2] = 0x00a4;	/* P_adp_regul_ext 0.02 */
11178c2ecf20Sopenharmony_ci		est[3] = 0xfff0;	/* P_adp_noise_ext -0.002 */
11188c2ecf20Sopenharmony_ci		break;
11198c2ecf20Sopenharmony_ci	default:
11208c2ecf20Sopenharmony_ci		est[0] = 0x099a;	/* P_adp_regul_cnt 0.3 */
11218c2ecf20Sopenharmony_ci		est[1] = 0xffae;	/* P_adp_noise_cnt -0.01 */
11228c2ecf20Sopenharmony_ci		est[2] = 0x0333;	/* P_adp_regul_ext 0.1 */
11238c2ecf20Sopenharmony_ci		est[3] = 0xfff8;	/* P_adp_noise_ext -0.002 */
11248c2ecf20Sopenharmony_ci		break;
11258c2ecf20Sopenharmony_ci	}
11268c2ecf20Sopenharmony_ci	for (value = 0; value < 4; value++)
11278c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 187 + value, est[value]);
11288c2ecf20Sopenharmony_ci}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_cistatic int dib7000p_autosearch_start(struct dvb_frontend *demod)
11318c2ecf20Sopenharmony_ci{
11328c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
11338c2ecf20Sopenharmony_ci	struct dib7000p_state *state = demod->demodulator_priv;
11348c2ecf20Sopenharmony_ci	struct dtv_frontend_properties schan;
11358c2ecf20Sopenharmony_ci	u32 value, factor;
11368c2ecf20Sopenharmony_ci	u32 internal = dib7000p_get_internal_freq(state);
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	schan = *ch;
11398c2ecf20Sopenharmony_ci	schan.modulation = QAM_64;
11408c2ecf20Sopenharmony_ci	schan.guard_interval = GUARD_INTERVAL_1_32;
11418c2ecf20Sopenharmony_ci	schan.transmission_mode = TRANSMISSION_MODE_8K;
11428c2ecf20Sopenharmony_ci	schan.code_rate_HP = FEC_2_3;
11438c2ecf20Sopenharmony_ci	schan.code_rate_LP = FEC_3_4;
11448c2ecf20Sopenharmony_ci	schan.hierarchy = 0;
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	dib7000p_set_channel(state, &schan, 7);
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	factor = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
11498c2ecf20Sopenharmony_ci	if (factor >= 5000) {
11508c2ecf20Sopenharmony_ci		if (state->version == SOC7090)
11518c2ecf20Sopenharmony_ci			factor = 2;
11528c2ecf20Sopenharmony_ci		else
11538c2ecf20Sopenharmony_ci			factor = 1;
11548c2ecf20Sopenharmony_ci	} else
11558c2ecf20Sopenharmony_ci		factor = 6;
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	value = 30 * internal * factor;
11588c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
11598c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 7, (u16) (value & 0xffff));
11608c2ecf20Sopenharmony_ci	value = 100 * internal * factor;
11618c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
11628c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 9, (u16) (value & 0xffff));
11638c2ecf20Sopenharmony_ci	value = 500 * internal * factor;
11648c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
11658c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 11, (u16) (value & 0xffff));
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	value = dib7000p_read_word(state, 0);
11688c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
11698c2ecf20Sopenharmony_ci	dib7000p_read_word(state, 1284);
11708c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 0, (u16) value);
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci	return 0;
11738c2ecf20Sopenharmony_ci}
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_cistatic int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
11768c2ecf20Sopenharmony_ci{
11778c2ecf20Sopenharmony_ci	struct dib7000p_state *state = demod->demodulator_priv;
11788c2ecf20Sopenharmony_ci	u16 irq_pending = dib7000p_read_word(state, 1284);
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	if (irq_pending & 0x1)
11818c2ecf20Sopenharmony_ci		return 1;
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	if (irq_pending & 0x2)
11848c2ecf20Sopenharmony_ci		return 2;
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	return 0;
11878c2ecf20Sopenharmony_ci}
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_cistatic void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
11908c2ecf20Sopenharmony_ci{
11918c2ecf20Sopenharmony_ci	static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
11928c2ecf20Sopenharmony_ci	static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
11938c2ecf20Sopenharmony_ci		24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
11948c2ecf20Sopenharmony_ci		53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
11958c2ecf20Sopenharmony_ci		82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
11968c2ecf20Sopenharmony_ci		107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
11978c2ecf20Sopenharmony_ci		128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
11988c2ecf20Sopenharmony_ci		147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
11998c2ecf20Sopenharmony_ci		166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
12008c2ecf20Sopenharmony_ci		183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
12018c2ecf20Sopenharmony_ci		199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
12028c2ecf20Sopenharmony_ci		213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
12038c2ecf20Sopenharmony_ci		225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
12048c2ecf20Sopenharmony_ci		235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
12058c2ecf20Sopenharmony_ci		244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
12068c2ecf20Sopenharmony_ci		250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
12078c2ecf20Sopenharmony_ci		254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
12088c2ecf20Sopenharmony_ci		255, 255, 255, 255, 255, 255
12098c2ecf20Sopenharmony_ci	};
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	u32 xtal = state->cfg.bw->xtal_hz / 1000;
12128c2ecf20Sopenharmony_ci	int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
12138c2ecf20Sopenharmony_ci	int k;
12148c2ecf20Sopenharmony_ci	int coef_re[8], coef_im[8];
12158c2ecf20Sopenharmony_ci	int bw_khz = bw;
12168c2ecf20Sopenharmony_ci	u32 pha;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)\n", f_rel, rf_khz, xtal);
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
12218c2ecf20Sopenharmony_ci		return;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	bw_khz /= 100;
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 142, 0x0610);
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	for (k = 0; k < 8; k++) {
12288c2ecf20Sopenharmony_ci		pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci		if (pha == 0) {
12318c2ecf20Sopenharmony_ci			coef_re[k] = 256;
12328c2ecf20Sopenharmony_ci			coef_im[k] = 0;
12338c2ecf20Sopenharmony_ci		} else if (pha < 256) {
12348c2ecf20Sopenharmony_ci			coef_re[k] = sine[256 - (pha & 0xff)];
12358c2ecf20Sopenharmony_ci			coef_im[k] = sine[pha & 0xff];
12368c2ecf20Sopenharmony_ci		} else if (pha == 256) {
12378c2ecf20Sopenharmony_ci			coef_re[k] = 0;
12388c2ecf20Sopenharmony_ci			coef_im[k] = 256;
12398c2ecf20Sopenharmony_ci		} else if (pha < 512) {
12408c2ecf20Sopenharmony_ci			coef_re[k] = -sine[pha & 0xff];
12418c2ecf20Sopenharmony_ci			coef_im[k] = sine[256 - (pha & 0xff)];
12428c2ecf20Sopenharmony_ci		} else if (pha == 512) {
12438c2ecf20Sopenharmony_ci			coef_re[k] = -256;
12448c2ecf20Sopenharmony_ci			coef_im[k] = 0;
12458c2ecf20Sopenharmony_ci		} else if (pha < 768) {
12468c2ecf20Sopenharmony_ci			coef_re[k] = -sine[256 - (pha & 0xff)];
12478c2ecf20Sopenharmony_ci			coef_im[k] = -sine[pha & 0xff];
12488c2ecf20Sopenharmony_ci		} else if (pha == 768) {
12498c2ecf20Sopenharmony_ci			coef_re[k] = 0;
12508c2ecf20Sopenharmony_ci			coef_im[k] = -256;
12518c2ecf20Sopenharmony_ci		} else {
12528c2ecf20Sopenharmony_ci			coef_re[k] = sine[pha & 0xff];
12538c2ecf20Sopenharmony_ci			coef_im[k] = -sine[256 - (pha & 0xff)];
12548c2ecf20Sopenharmony_ci		}
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci		coef_re[k] *= notch[k];
12578c2ecf20Sopenharmony_ci		coef_re[k] += (1 << 14);
12588c2ecf20Sopenharmony_ci		if (coef_re[k] >= (1 << 24))
12598c2ecf20Sopenharmony_ci			coef_re[k] = (1 << 24) - 1;
12608c2ecf20Sopenharmony_ci		coef_re[k] /= (1 << 15);
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci		coef_im[k] *= notch[k];
12638c2ecf20Sopenharmony_ci		coef_im[k] += (1 << 14);
12648c2ecf20Sopenharmony_ci		if (coef_im[k] >= (1 << 24))
12658c2ecf20Sopenharmony_ci			coef_im[k] = (1 << 24) - 1;
12668c2ecf20Sopenharmony_ci		coef_im[k] /= (1 << 15);
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci		dprintk("PALF COEF: %d re: %d im: %d\n", k, coef_re[k], coef_im[k]);
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
12718c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
12728c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
12738c2ecf20Sopenharmony_ci	}
12748c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 143, 0);
12758c2ecf20Sopenharmony_ci}
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_cistatic int dib7000p_tune(struct dvb_frontend *demod)
12788c2ecf20Sopenharmony_ci{
12798c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
12808c2ecf20Sopenharmony_ci	struct dib7000p_state *state = demod->demodulator_priv;
12818c2ecf20Sopenharmony_ci	u16 tmp = 0;
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	if (ch != NULL)
12848c2ecf20Sopenharmony_ci		dib7000p_set_channel(state, ch, 0);
12858c2ecf20Sopenharmony_ci	else
12868c2ecf20Sopenharmony_ci		return -EINVAL;
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	// restart demod
12898c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 770, 0x4000);
12908c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 770, 0x0000);
12918c2ecf20Sopenharmony_ci	msleep(45);
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
12948c2ecf20Sopenharmony_ci	tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
12958c2ecf20Sopenharmony_ci	if (state->sfn_workaround_active) {
12968c2ecf20Sopenharmony_ci		dprintk("SFN workaround is active\n");
12978c2ecf20Sopenharmony_ci		tmp |= (1 << 9);
12988c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 166, 0x4000);
12998c2ecf20Sopenharmony_ci	} else {
13008c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 166, 0x0000);
13018c2ecf20Sopenharmony_ci	}
13028c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 29, tmp);
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	// never achieved a lock with that bandwidth so far - wait for osc-freq to update
13058c2ecf20Sopenharmony_ci	if (state->timf == 0)
13068c2ecf20Sopenharmony_ci		msleep(200);
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	/* offset loop parameters */
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
13118c2ecf20Sopenharmony_ci	tmp = (6 << 8) | 0x80;
13128c2ecf20Sopenharmony_ci	switch (ch->transmission_mode) {
13138c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_2K:
13148c2ecf20Sopenharmony_ci		tmp |= (2 << 12);
13158c2ecf20Sopenharmony_ci		break;
13168c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_4K:
13178c2ecf20Sopenharmony_ci		tmp |= (3 << 12);
13188c2ecf20Sopenharmony_ci		break;
13198c2ecf20Sopenharmony_ci	default:
13208c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_8K:
13218c2ecf20Sopenharmony_ci		tmp |= (4 << 12);
13228c2ecf20Sopenharmony_ci		break;
13238c2ecf20Sopenharmony_ci	}
13248c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 26, tmp);	/* timf_a(6xxx) */
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
13278c2ecf20Sopenharmony_ci	tmp = (0 << 4);
13288c2ecf20Sopenharmony_ci	switch (ch->transmission_mode) {
13298c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_2K:
13308c2ecf20Sopenharmony_ci		tmp |= 0x6;
13318c2ecf20Sopenharmony_ci		break;
13328c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_4K:
13338c2ecf20Sopenharmony_ci		tmp |= 0x7;
13348c2ecf20Sopenharmony_ci		break;
13358c2ecf20Sopenharmony_ci	default:
13368c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_8K:
13378c2ecf20Sopenharmony_ci		tmp |= 0x8;
13388c2ecf20Sopenharmony_ci		break;
13398c2ecf20Sopenharmony_ci	}
13408c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 32, tmp);
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
13438c2ecf20Sopenharmony_ci	tmp = (0 << 4);
13448c2ecf20Sopenharmony_ci	switch (ch->transmission_mode) {
13458c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_2K:
13468c2ecf20Sopenharmony_ci		tmp |= 0x6;
13478c2ecf20Sopenharmony_ci		break;
13488c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_4K:
13498c2ecf20Sopenharmony_ci		tmp |= 0x7;
13508c2ecf20Sopenharmony_ci		break;
13518c2ecf20Sopenharmony_ci	default:
13528c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_8K:
13538c2ecf20Sopenharmony_ci		tmp |= 0x8;
13548c2ecf20Sopenharmony_ci		break;
13558c2ecf20Sopenharmony_ci	}
13568c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 33, tmp);
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	tmp = dib7000p_read_word(state, 509);
13598c2ecf20Sopenharmony_ci	if (!((tmp >> 6) & 0x1)) {
13608c2ecf20Sopenharmony_ci		/* restart the fec */
13618c2ecf20Sopenharmony_ci		tmp = dib7000p_read_word(state, 771);
13628c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 771, tmp | (1 << 1));
13638c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 771, tmp);
13648c2ecf20Sopenharmony_ci		msleep(40);
13658c2ecf20Sopenharmony_ci		tmp = dib7000p_read_word(state, 509);
13668c2ecf20Sopenharmony_ci	}
13678c2ecf20Sopenharmony_ci	// we achieved a lock - it's time to update the osc freq
13688c2ecf20Sopenharmony_ci	if ((tmp >> 6) & 0x1) {
13698c2ecf20Sopenharmony_ci		dib7000p_update_timf(state);
13708c2ecf20Sopenharmony_ci		/* P_timf_alpha += 2 */
13718c2ecf20Sopenharmony_ci		tmp = dib7000p_read_word(state, 26);
13728c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
13738c2ecf20Sopenharmony_ci	}
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	if (state->cfg.spur_protect)
13768c2ecf20Sopenharmony_ci		dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci	dib7000p_reset_stats(demod);
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	return 0;
13838c2ecf20Sopenharmony_ci}
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_cistatic int dib7000p_wakeup(struct dvb_frontend *demod)
13868c2ecf20Sopenharmony_ci{
13878c2ecf20Sopenharmony_ci	struct dib7000p_state *state = demod->demodulator_priv;
13888c2ecf20Sopenharmony_ci	dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
13898c2ecf20Sopenharmony_ci	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
13908c2ecf20Sopenharmony_ci	if (state->version == SOC7090)
13918c2ecf20Sopenharmony_ci		dib7000p_sad_calib(state);
13928c2ecf20Sopenharmony_ci	return 0;
13938c2ecf20Sopenharmony_ci}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_cistatic int dib7000p_sleep(struct dvb_frontend *demod)
13968c2ecf20Sopenharmony_ci{
13978c2ecf20Sopenharmony_ci	struct dib7000p_state *state = demod->demodulator_priv;
13988c2ecf20Sopenharmony_ci	if (state->version == SOC7090)
13998c2ecf20Sopenharmony_ci		return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
14008c2ecf20Sopenharmony_ci	return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
14018c2ecf20Sopenharmony_ci}
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_cistatic int dib7000p_identify(struct dib7000p_state *st)
14048c2ecf20Sopenharmony_ci{
14058c2ecf20Sopenharmony_ci	u16 value;
14068c2ecf20Sopenharmony_ci	dprintk("checking demod on I2C address: %d (%x)\n", st->i2c_addr, st->i2c_addr);
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
14098c2ecf20Sopenharmony_ci		dprintk("wrong Vendor ID (read=0x%x)\n", value);
14108c2ecf20Sopenharmony_ci		return -EREMOTEIO;
14118c2ecf20Sopenharmony_ci	}
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
14148c2ecf20Sopenharmony_ci		dprintk("wrong Device ID (%x)\n", value);
14158c2ecf20Sopenharmony_ci		return -EREMOTEIO;
14168c2ecf20Sopenharmony_ci	}
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	return 0;
14198c2ecf20Sopenharmony_ci}
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_cistatic int dib7000p_get_frontend(struct dvb_frontend *fe,
14228c2ecf20Sopenharmony_ci				 struct dtv_frontend_properties *fep)
14238c2ecf20Sopenharmony_ci{
14248c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
14258c2ecf20Sopenharmony_ci	u16 tps = dib7000p_read_word(state, 463);
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	fep->inversion = INVERSION_AUTO;
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	switch ((tps >> 8) & 0x3) {
14328c2ecf20Sopenharmony_ci	case 0:
14338c2ecf20Sopenharmony_ci		fep->transmission_mode = TRANSMISSION_MODE_2K;
14348c2ecf20Sopenharmony_ci		break;
14358c2ecf20Sopenharmony_ci	case 1:
14368c2ecf20Sopenharmony_ci		fep->transmission_mode = TRANSMISSION_MODE_8K;
14378c2ecf20Sopenharmony_ci		break;
14388c2ecf20Sopenharmony_ci	/* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
14398c2ecf20Sopenharmony_ci	}
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	switch (tps & 0x3) {
14428c2ecf20Sopenharmony_ci	case 0:
14438c2ecf20Sopenharmony_ci		fep->guard_interval = GUARD_INTERVAL_1_32;
14448c2ecf20Sopenharmony_ci		break;
14458c2ecf20Sopenharmony_ci	case 1:
14468c2ecf20Sopenharmony_ci		fep->guard_interval = GUARD_INTERVAL_1_16;
14478c2ecf20Sopenharmony_ci		break;
14488c2ecf20Sopenharmony_ci	case 2:
14498c2ecf20Sopenharmony_ci		fep->guard_interval = GUARD_INTERVAL_1_8;
14508c2ecf20Sopenharmony_ci		break;
14518c2ecf20Sopenharmony_ci	case 3:
14528c2ecf20Sopenharmony_ci		fep->guard_interval = GUARD_INTERVAL_1_4;
14538c2ecf20Sopenharmony_ci		break;
14548c2ecf20Sopenharmony_ci	}
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	switch ((tps >> 14) & 0x3) {
14578c2ecf20Sopenharmony_ci	case 0:
14588c2ecf20Sopenharmony_ci		fep->modulation = QPSK;
14598c2ecf20Sopenharmony_ci		break;
14608c2ecf20Sopenharmony_ci	case 1:
14618c2ecf20Sopenharmony_ci		fep->modulation = QAM_16;
14628c2ecf20Sopenharmony_ci		break;
14638c2ecf20Sopenharmony_ci	case 2:
14648c2ecf20Sopenharmony_ci	default:
14658c2ecf20Sopenharmony_ci		fep->modulation = QAM_64;
14668c2ecf20Sopenharmony_ci		break;
14678c2ecf20Sopenharmony_ci	}
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci	/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
14708c2ecf20Sopenharmony_ci	/* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	fep->hierarchy = HIERARCHY_NONE;
14738c2ecf20Sopenharmony_ci	switch ((tps >> 5) & 0x7) {
14748c2ecf20Sopenharmony_ci	case 1:
14758c2ecf20Sopenharmony_ci		fep->code_rate_HP = FEC_1_2;
14768c2ecf20Sopenharmony_ci		break;
14778c2ecf20Sopenharmony_ci	case 2:
14788c2ecf20Sopenharmony_ci		fep->code_rate_HP = FEC_2_3;
14798c2ecf20Sopenharmony_ci		break;
14808c2ecf20Sopenharmony_ci	case 3:
14818c2ecf20Sopenharmony_ci		fep->code_rate_HP = FEC_3_4;
14828c2ecf20Sopenharmony_ci		break;
14838c2ecf20Sopenharmony_ci	case 5:
14848c2ecf20Sopenharmony_ci		fep->code_rate_HP = FEC_5_6;
14858c2ecf20Sopenharmony_ci		break;
14868c2ecf20Sopenharmony_ci	case 7:
14878c2ecf20Sopenharmony_ci	default:
14888c2ecf20Sopenharmony_ci		fep->code_rate_HP = FEC_7_8;
14898c2ecf20Sopenharmony_ci		break;
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	}
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci	switch ((tps >> 2) & 0x7) {
14948c2ecf20Sopenharmony_ci	case 1:
14958c2ecf20Sopenharmony_ci		fep->code_rate_LP = FEC_1_2;
14968c2ecf20Sopenharmony_ci		break;
14978c2ecf20Sopenharmony_ci	case 2:
14988c2ecf20Sopenharmony_ci		fep->code_rate_LP = FEC_2_3;
14998c2ecf20Sopenharmony_ci		break;
15008c2ecf20Sopenharmony_ci	case 3:
15018c2ecf20Sopenharmony_ci		fep->code_rate_LP = FEC_3_4;
15028c2ecf20Sopenharmony_ci		break;
15038c2ecf20Sopenharmony_ci	case 5:
15048c2ecf20Sopenharmony_ci		fep->code_rate_LP = FEC_5_6;
15058c2ecf20Sopenharmony_ci		break;
15068c2ecf20Sopenharmony_ci	case 7:
15078c2ecf20Sopenharmony_ci	default:
15088c2ecf20Sopenharmony_ci		fep->code_rate_LP = FEC_7_8;
15098c2ecf20Sopenharmony_ci		break;
15108c2ecf20Sopenharmony_ci	}
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	/* native interleaver: (dib7000p_read_word(state, 464) >>  5) & 0x1 */
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci	return 0;
15158c2ecf20Sopenharmony_ci}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_cistatic int dib7000p_set_frontend(struct dvb_frontend *fe)
15188c2ecf20Sopenharmony_ci{
15198c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
15208c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
15218c2ecf20Sopenharmony_ci	int time, ret;
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	if (state->version == SOC7090)
15248c2ecf20Sopenharmony_ci		dib7090_set_diversity_in(fe, 0);
15258c2ecf20Sopenharmony_ci	else
15268c2ecf20Sopenharmony_ci		dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	/* maybe the parameter has been changed */
15298c2ecf20Sopenharmony_ci	state->sfn_workaround_active = buggy_sfn_workaround;
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	if (fe->ops.tuner_ops.set_params)
15328c2ecf20Sopenharmony_ci		fe->ops.tuner_ops.set_params(fe);
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	/* start up the AGC */
15358c2ecf20Sopenharmony_ci	state->agc_state = 0;
15368c2ecf20Sopenharmony_ci	do {
15378c2ecf20Sopenharmony_ci		time = dib7000p_agc_startup(fe);
15388c2ecf20Sopenharmony_ci		if (time != -1)
15398c2ecf20Sopenharmony_ci			msleep(time);
15408c2ecf20Sopenharmony_ci	} while (time != -1);
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
15438c2ecf20Sopenharmony_ci		fep->guard_interval == GUARD_INTERVAL_AUTO || fep->modulation == QAM_AUTO || fep->code_rate_HP == FEC_AUTO) {
15448c2ecf20Sopenharmony_ci		int i = 800, found;
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci		dib7000p_autosearch_start(fe);
15478c2ecf20Sopenharmony_ci		do {
15488c2ecf20Sopenharmony_ci			msleep(1);
15498c2ecf20Sopenharmony_ci			found = dib7000p_autosearch_is_irq(fe);
15508c2ecf20Sopenharmony_ci		} while (found == 0 && i--);
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci		dprintk("autosearch returns: %d\n", found);
15538c2ecf20Sopenharmony_ci		if (found == 0 || found == 1)
15548c2ecf20Sopenharmony_ci			return 0;
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci		dib7000p_get_frontend(fe, fep);
15578c2ecf20Sopenharmony_ci	}
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci	ret = dib7000p_tune(fe);
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	/* make this a config parameter */
15628c2ecf20Sopenharmony_ci	if (state->version == SOC7090) {
15638c2ecf20Sopenharmony_ci		dib7090_set_output_mode(fe, state->cfg.output_mode);
15648c2ecf20Sopenharmony_ci		if (state->cfg.enMpegOutput == 0) {
15658c2ecf20Sopenharmony_ci			dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
15668c2ecf20Sopenharmony_ci			dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
15678c2ecf20Sopenharmony_ci		}
15688c2ecf20Sopenharmony_ci	} else
15698c2ecf20Sopenharmony_ci		dib7000p_set_output_mode(state, state->cfg.output_mode);
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	return ret;
15728c2ecf20Sopenharmony_ci}
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_cistatic int dib7000p_get_stats(struct dvb_frontend *fe, enum fe_status stat);
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_cistatic int dib7000p_read_status(struct dvb_frontend *fe, enum fe_status *stat)
15778c2ecf20Sopenharmony_ci{
15788c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
15798c2ecf20Sopenharmony_ci	u16 lock = dib7000p_read_word(state, 509);
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	*stat = 0;
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	if (lock & 0x8000)
15848c2ecf20Sopenharmony_ci		*stat |= FE_HAS_SIGNAL;
15858c2ecf20Sopenharmony_ci	if (lock & 0x3000)
15868c2ecf20Sopenharmony_ci		*stat |= FE_HAS_CARRIER;
15878c2ecf20Sopenharmony_ci	if (lock & 0x0100)
15888c2ecf20Sopenharmony_ci		*stat |= FE_HAS_VITERBI;
15898c2ecf20Sopenharmony_ci	if (lock & 0x0010)
15908c2ecf20Sopenharmony_ci		*stat |= FE_HAS_SYNC;
15918c2ecf20Sopenharmony_ci	if ((lock & 0x0038) == 0x38)
15928c2ecf20Sopenharmony_ci		*stat |= FE_HAS_LOCK;
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci	dib7000p_get_stats(fe, *stat);
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci	return 0;
15978c2ecf20Sopenharmony_ci}
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_cistatic int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
16008c2ecf20Sopenharmony_ci{
16018c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
16028c2ecf20Sopenharmony_ci	*ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
16038c2ecf20Sopenharmony_ci	return 0;
16048c2ecf20Sopenharmony_ci}
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_cistatic int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
16078c2ecf20Sopenharmony_ci{
16088c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
16098c2ecf20Sopenharmony_ci	*unc = dib7000p_read_word(state, 506);
16108c2ecf20Sopenharmony_ci	return 0;
16118c2ecf20Sopenharmony_ci}
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_cistatic int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
16148c2ecf20Sopenharmony_ci{
16158c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
16168c2ecf20Sopenharmony_ci	u16 val = dib7000p_read_word(state, 394);
16178c2ecf20Sopenharmony_ci	*strength = 65535 - val;
16188c2ecf20Sopenharmony_ci	return 0;
16198c2ecf20Sopenharmony_ci}
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_cistatic u32 dib7000p_get_snr(struct dvb_frontend *fe)
16228c2ecf20Sopenharmony_ci{
16238c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
16248c2ecf20Sopenharmony_ci	u16 val;
16258c2ecf20Sopenharmony_ci	s32 signal_mant, signal_exp, noise_mant, noise_exp;
16268c2ecf20Sopenharmony_ci	u32 result = 0;
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	val = dib7000p_read_word(state, 479);
16298c2ecf20Sopenharmony_ci	noise_mant = (val >> 4) & 0xff;
16308c2ecf20Sopenharmony_ci	noise_exp = ((val & 0xf) << 2);
16318c2ecf20Sopenharmony_ci	val = dib7000p_read_word(state, 480);
16328c2ecf20Sopenharmony_ci	noise_exp += ((val >> 14) & 0x3);
16338c2ecf20Sopenharmony_ci	if ((noise_exp & 0x20) != 0)
16348c2ecf20Sopenharmony_ci		noise_exp -= 0x40;
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	signal_mant = (val >> 6) & 0xFF;
16378c2ecf20Sopenharmony_ci	signal_exp = (val & 0x3F);
16388c2ecf20Sopenharmony_ci	if ((signal_exp & 0x20) != 0)
16398c2ecf20Sopenharmony_ci		signal_exp -= 0x40;
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	if (signal_mant != 0)
16428c2ecf20Sopenharmony_ci		result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
16438c2ecf20Sopenharmony_ci	else
16448c2ecf20Sopenharmony_ci		result = intlog10(2) * 10 * signal_exp - 100;
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	if (noise_mant != 0)
16478c2ecf20Sopenharmony_ci		result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
16488c2ecf20Sopenharmony_ci	else
16498c2ecf20Sopenharmony_ci		result -= intlog10(2) * 10 * noise_exp - 100;
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	return result;
16528c2ecf20Sopenharmony_ci}
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_cistatic int dib7000p_read_snr(struct dvb_frontend *fe, u16 *snr)
16558c2ecf20Sopenharmony_ci{
16568c2ecf20Sopenharmony_ci	u32 result;
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci	result = dib7000p_get_snr(fe);
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	*snr = result / ((1 << 24) / 10);
16618c2ecf20Sopenharmony_ci	return 0;
16628c2ecf20Sopenharmony_ci}
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_cistatic void dib7000p_reset_stats(struct dvb_frontend *demod)
16658c2ecf20Sopenharmony_ci{
16668c2ecf20Sopenharmony_ci	struct dib7000p_state *state = demod->demodulator_priv;
16678c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *c = &demod->dtv_property_cache;
16688c2ecf20Sopenharmony_ci	u32 ucb;
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci	memset(&c->strength, 0, sizeof(c->strength));
16718c2ecf20Sopenharmony_ci	memset(&c->cnr, 0, sizeof(c->cnr));
16728c2ecf20Sopenharmony_ci	memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
16738c2ecf20Sopenharmony_ci	memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
16748c2ecf20Sopenharmony_ci	memset(&c->block_error, 0, sizeof(c->block_error));
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	c->strength.len = 1;
16778c2ecf20Sopenharmony_ci	c->cnr.len = 1;
16788c2ecf20Sopenharmony_ci	c->block_error.len = 1;
16798c2ecf20Sopenharmony_ci	c->block_count.len = 1;
16808c2ecf20Sopenharmony_ci	c->post_bit_error.len = 1;
16818c2ecf20Sopenharmony_ci	c->post_bit_count.len = 1;
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	c->strength.stat[0].scale = FE_SCALE_DECIBEL;
16848c2ecf20Sopenharmony_ci	c->strength.stat[0].uvalue = 0;
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
16878c2ecf20Sopenharmony_ci	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
16888c2ecf20Sopenharmony_ci	c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
16898c2ecf20Sopenharmony_ci	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
16908c2ecf20Sopenharmony_ci	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ci	dib7000p_read_unc_blocks(demod, &ucb);
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	state->old_ucb = ucb;
16958c2ecf20Sopenharmony_ci	state->ber_jiffies_stats = 0;
16968c2ecf20Sopenharmony_ci	state->per_jiffies_stats = 0;
16978c2ecf20Sopenharmony_ci}
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_cistruct linear_segments {
17008c2ecf20Sopenharmony_ci	unsigned x;
17018c2ecf20Sopenharmony_ci	signed y;
17028c2ecf20Sopenharmony_ci};
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci/*
17058c2ecf20Sopenharmony_ci * Table to estimate signal strength in dBm.
17068c2ecf20Sopenharmony_ci * This table should be empirically determinated by measuring the signal
17078c2ecf20Sopenharmony_ci * strength generated by a RF generator directly connected into
17088c2ecf20Sopenharmony_ci * a device.
17098c2ecf20Sopenharmony_ci * This table was determinated by measuring the signal strength generated
17108c2ecf20Sopenharmony_ci * by a DTA-2111 RF generator directly connected into a dib7000p device
17118c2ecf20Sopenharmony_ci * (a Hauppauge Nova-TD stick), using a good quality 3 meters length
17128c2ecf20Sopenharmony_ci * RC6 cable and good RC6 connectors, connected directly to antenna 1.
17138c2ecf20Sopenharmony_ci * As the minimum output power of DTA-2111 is -31dBm, a 16 dBm attenuator
17148c2ecf20Sopenharmony_ci * were used, for the lower power values.
17158c2ecf20Sopenharmony_ci * The real value can actually be on other devices, or even at the
17168c2ecf20Sopenharmony_ci * second antena input, depending on several factors, like if LNA
17178c2ecf20Sopenharmony_ci * is enabled or not, if diversity is enabled, type of connectors, etc.
17188c2ecf20Sopenharmony_ci * Yet, it is better to use this measure in dB than a random non-linear
17198c2ecf20Sopenharmony_ci * percentage value, especially for antenna adjustments.
17208c2ecf20Sopenharmony_ci * On my tests, the precision of the measure using this table is about
17218c2ecf20Sopenharmony_ci * 0.5 dB, with sounds reasonable enough to adjust antennas.
17228c2ecf20Sopenharmony_ci */
17238c2ecf20Sopenharmony_ci#define DB_OFFSET 131000
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_cistatic struct linear_segments strength_to_db_table[] = {
17268c2ecf20Sopenharmony_ci	{ 63630, DB_OFFSET - 20500},
17278c2ecf20Sopenharmony_ci	{ 62273, DB_OFFSET - 21000},
17288c2ecf20Sopenharmony_ci	{ 60162, DB_OFFSET - 22000},
17298c2ecf20Sopenharmony_ci	{ 58730, DB_OFFSET - 23000},
17308c2ecf20Sopenharmony_ci	{ 58294, DB_OFFSET - 24000},
17318c2ecf20Sopenharmony_ci	{ 57778, DB_OFFSET - 25000},
17328c2ecf20Sopenharmony_ci	{ 57320, DB_OFFSET - 26000},
17338c2ecf20Sopenharmony_ci	{ 56779, DB_OFFSET - 27000},
17348c2ecf20Sopenharmony_ci	{ 56293, DB_OFFSET - 28000},
17358c2ecf20Sopenharmony_ci	{ 55724, DB_OFFSET - 29000},
17368c2ecf20Sopenharmony_ci	{ 55145, DB_OFFSET - 30000},
17378c2ecf20Sopenharmony_ci	{ 54680, DB_OFFSET - 31000},
17388c2ecf20Sopenharmony_ci	{ 54293, DB_OFFSET - 32000},
17398c2ecf20Sopenharmony_ci	{ 53813, DB_OFFSET - 33000},
17408c2ecf20Sopenharmony_ci	{ 53427, DB_OFFSET - 34000},
17418c2ecf20Sopenharmony_ci	{ 52981, DB_OFFSET - 35000},
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	{ 52636, DB_OFFSET - 36000},
17448c2ecf20Sopenharmony_ci	{ 52014, DB_OFFSET - 37000},
17458c2ecf20Sopenharmony_ci	{ 51674, DB_OFFSET - 38000},
17468c2ecf20Sopenharmony_ci	{ 50692, DB_OFFSET - 39000},
17478c2ecf20Sopenharmony_ci	{ 49824, DB_OFFSET - 40000},
17488c2ecf20Sopenharmony_ci	{ 49052, DB_OFFSET - 41000},
17498c2ecf20Sopenharmony_ci	{ 48436, DB_OFFSET - 42000},
17508c2ecf20Sopenharmony_ci	{ 47836, DB_OFFSET - 43000},
17518c2ecf20Sopenharmony_ci	{ 47368, DB_OFFSET - 44000},
17528c2ecf20Sopenharmony_ci	{ 46468, DB_OFFSET - 45000},
17538c2ecf20Sopenharmony_ci	{ 45597, DB_OFFSET - 46000},
17548c2ecf20Sopenharmony_ci	{ 44586, DB_OFFSET - 47000},
17558c2ecf20Sopenharmony_ci	{ 43667, DB_OFFSET - 48000},
17568c2ecf20Sopenharmony_ci	{ 42673, DB_OFFSET - 49000},
17578c2ecf20Sopenharmony_ci	{ 41816, DB_OFFSET - 50000},
17588c2ecf20Sopenharmony_ci	{ 40876, DB_OFFSET - 51000},
17598c2ecf20Sopenharmony_ci	{     0,      0},
17608c2ecf20Sopenharmony_ci};
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_cistatic u32 interpolate_value(u32 value, struct linear_segments *segments,
17638c2ecf20Sopenharmony_ci			     unsigned len)
17648c2ecf20Sopenharmony_ci{
17658c2ecf20Sopenharmony_ci	u64 tmp64;
17668c2ecf20Sopenharmony_ci	u32 dx;
17678c2ecf20Sopenharmony_ci	s32 dy;
17688c2ecf20Sopenharmony_ci	int i, ret;
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci	if (value >= segments[0].x)
17718c2ecf20Sopenharmony_ci		return segments[0].y;
17728c2ecf20Sopenharmony_ci	if (value < segments[len-1].x)
17738c2ecf20Sopenharmony_ci		return segments[len-1].y;
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci	for (i = 1; i < len - 1; i++) {
17768c2ecf20Sopenharmony_ci		/* If value is identical, no need to interpolate */
17778c2ecf20Sopenharmony_ci		if (value == segments[i].x)
17788c2ecf20Sopenharmony_ci			return segments[i].y;
17798c2ecf20Sopenharmony_ci		if (value > segments[i].x)
17808c2ecf20Sopenharmony_ci			break;
17818c2ecf20Sopenharmony_ci	}
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci	/* Linear interpolation between the two (x,y) points */
17848c2ecf20Sopenharmony_ci	dy = segments[i - 1].y - segments[i].y;
17858c2ecf20Sopenharmony_ci	dx = segments[i - 1].x - segments[i].x;
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	tmp64 = value - segments[i].x;
17888c2ecf20Sopenharmony_ci	tmp64 *= dy;
17898c2ecf20Sopenharmony_ci	do_div(tmp64, dx);
17908c2ecf20Sopenharmony_ci	ret = segments[i].y + tmp64;
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci	return ret;
17938c2ecf20Sopenharmony_ci}
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci/* FIXME: may require changes - this one was borrowed from dib8000 */
17968c2ecf20Sopenharmony_cistatic u32 dib7000p_get_time_us(struct dvb_frontend *demod)
17978c2ecf20Sopenharmony_ci{
17988c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *c = &demod->dtv_property_cache;
17998c2ecf20Sopenharmony_ci	u64 time_us, tmp64;
18008c2ecf20Sopenharmony_ci	u32 tmp, denom;
18018c2ecf20Sopenharmony_ci	int guard, rate_num, rate_denum = 1, bits_per_symbol;
18028c2ecf20Sopenharmony_ci	int interleaving = 0, fft_div;
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci	switch (c->guard_interval) {
18058c2ecf20Sopenharmony_ci	case GUARD_INTERVAL_1_4:
18068c2ecf20Sopenharmony_ci		guard = 4;
18078c2ecf20Sopenharmony_ci		break;
18088c2ecf20Sopenharmony_ci	case GUARD_INTERVAL_1_8:
18098c2ecf20Sopenharmony_ci		guard = 8;
18108c2ecf20Sopenharmony_ci		break;
18118c2ecf20Sopenharmony_ci	case GUARD_INTERVAL_1_16:
18128c2ecf20Sopenharmony_ci		guard = 16;
18138c2ecf20Sopenharmony_ci		break;
18148c2ecf20Sopenharmony_ci	default:
18158c2ecf20Sopenharmony_ci	case GUARD_INTERVAL_1_32:
18168c2ecf20Sopenharmony_ci		guard = 32;
18178c2ecf20Sopenharmony_ci		break;
18188c2ecf20Sopenharmony_ci	}
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_ci	switch (c->transmission_mode) {
18218c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_2K:
18228c2ecf20Sopenharmony_ci		fft_div = 4;
18238c2ecf20Sopenharmony_ci		break;
18248c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_4K:
18258c2ecf20Sopenharmony_ci		fft_div = 2;
18268c2ecf20Sopenharmony_ci		break;
18278c2ecf20Sopenharmony_ci	default:
18288c2ecf20Sopenharmony_ci	case TRANSMISSION_MODE_8K:
18298c2ecf20Sopenharmony_ci		fft_div = 1;
18308c2ecf20Sopenharmony_ci		break;
18318c2ecf20Sopenharmony_ci	}
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	switch (c->modulation) {
18348c2ecf20Sopenharmony_ci	case DQPSK:
18358c2ecf20Sopenharmony_ci	case QPSK:
18368c2ecf20Sopenharmony_ci		bits_per_symbol = 2;
18378c2ecf20Sopenharmony_ci		break;
18388c2ecf20Sopenharmony_ci	case QAM_16:
18398c2ecf20Sopenharmony_ci		bits_per_symbol = 4;
18408c2ecf20Sopenharmony_ci		break;
18418c2ecf20Sopenharmony_ci	default:
18428c2ecf20Sopenharmony_ci	case QAM_64:
18438c2ecf20Sopenharmony_ci		bits_per_symbol = 6;
18448c2ecf20Sopenharmony_ci		break;
18458c2ecf20Sopenharmony_ci	}
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	switch ((c->hierarchy == 0 || 1 == 1) ? c->code_rate_HP : c->code_rate_LP) {
18488c2ecf20Sopenharmony_ci	case FEC_1_2:
18498c2ecf20Sopenharmony_ci		rate_num = 1;
18508c2ecf20Sopenharmony_ci		rate_denum = 2;
18518c2ecf20Sopenharmony_ci		break;
18528c2ecf20Sopenharmony_ci	case FEC_2_3:
18538c2ecf20Sopenharmony_ci		rate_num = 2;
18548c2ecf20Sopenharmony_ci		rate_denum = 3;
18558c2ecf20Sopenharmony_ci		break;
18568c2ecf20Sopenharmony_ci	case FEC_3_4:
18578c2ecf20Sopenharmony_ci		rate_num = 3;
18588c2ecf20Sopenharmony_ci		rate_denum = 4;
18598c2ecf20Sopenharmony_ci		break;
18608c2ecf20Sopenharmony_ci	case FEC_5_6:
18618c2ecf20Sopenharmony_ci		rate_num = 5;
18628c2ecf20Sopenharmony_ci		rate_denum = 6;
18638c2ecf20Sopenharmony_ci		break;
18648c2ecf20Sopenharmony_ci	default:
18658c2ecf20Sopenharmony_ci	case FEC_7_8:
18668c2ecf20Sopenharmony_ci		rate_num = 7;
18678c2ecf20Sopenharmony_ci		rate_denum = 8;
18688c2ecf20Sopenharmony_ci		break;
18698c2ecf20Sopenharmony_ci	}
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci	denom = bits_per_symbol * rate_num * fft_div * 384;
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	/*
18748c2ecf20Sopenharmony_ci	 * FIXME: check if the math makes sense. If so, fill the
18758c2ecf20Sopenharmony_ci	 * interleaving var.
18768c2ecf20Sopenharmony_ci	 */
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci	/* If calculus gets wrong, wait for 1s for the next stats */
18798c2ecf20Sopenharmony_ci	if (!denom)
18808c2ecf20Sopenharmony_ci		return 0;
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci	/* Estimate the period for the total bit rate */
18838c2ecf20Sopenharmony_ci	time_us = rate_denum * (1008 * 1562500L);
18848c2ecf20Sopenharmony_ci	tmp64 = time_us;
18858c2ecf20Sopenharmony_ci	do_div(tmp64, guard);
18868c2ecf20Sopenharmony_ci	time_us = time_us + tmp64;
18878c2ecf20Sopenharmony_ci	time_us += denom / 2;
18888c2ecf20Sopenharmony_ci	do_div(time_us, denom);
18898c2ecf20Sopenharmony_ci
18908c2ecf20Sopenharmony_ci	tmp = 1008 * 96 * interleaving;
18918c2ecf20Sopenharmony_ci	time_us += tmp + tmp / guard;
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci	return time_us;
18948c2ecf20Sopenharmony_ci}
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_cistatic int dib7000p_get_stats(struct dvb_frontend *demod, enum fe_status stat)
18978c2ecf20Sopenharmony_ci{
18988c2ecf20Sopenharmony_ci	struct dib7000p_state *state = demod->demodulator_priv;
18998c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *c = &demod->dtv_property_cache;
19008c2ecf20Sopenharmony_ci	int show_per_stats = 0;
19018c2ecf20Sopenharmony_ci	u32 time_us = 0, val, snr;
19028c2ecf20Sopenharmony_ci	u64 blocks, ucb;
19038c2ecf20Sopenharmony_ci	s32 db;
19048c2ecf20Sopenharmony_ci	u16 strength;
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ci	/* Get Signal strength */
19078c2ecf20Sopenharmony_ci	dib7000p_read_signal_strength(demod, &strength);
19088c2ecf20Sopenharmony_ci	val = strength;
19098c2ecf20Sopenharmony_ci	db = interpolate_value(val,
19108c2ecf20Sopenharmony_ci			       strength_to_db_table,
19118c2ecf20Sopenharmony_ci			       ARRAY_SIZE(strength_to_db_table)) - DB_OFFSET;
19128c2ecf20Sopenharmony_ci	c->strength.stat[0].svalue = db;
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	/* UCB/BER/CNR measures require lock */
19158c2ecf20Sopenharmony_ci	if (!(stat & FE_HAS_LOCK)) {
19168c2ecf20Sopenharmony_ci		c->cnr.len = 1;
19178c2ecf20Sopenharmony_ci		c->block_count.len = 1;
19188c2ecf20Sopenharmony_ci		c->block_error.len = 1;
19198c2ecf20Sopenharmony_ci		c->post_bit_error.len = 1;
19208c2ecf20Sopenharmony_ci		c->post_bit_count.len = 1;
19218c2ecf20Sopenharmony_ci		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
19228c2ecf20Sopenharmony_ci		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
19238c2ecf20Sopenharmony_ci		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
19248c2ecf20Sopenharmony_ci		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
19258c2ecf20Sopenharmony_ci		c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
19268c2ecf20Sopenharmony_ci		return 0;
19278c2ecf20Sopenharmony_ci	}
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	/* Check if time for stats was elapsed */
19308c2ecf20Sopenharmony_ci	if (time_after(jiffies, state->per_jiffies_stats)) {
19318c2ecf20Sopenharmony_ci		state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci		/* Get SNR */
19348c2ecf20Sopenharmony_ci		snr = dib7000p_get_snr(demod);
19358c2ecf20Sopenharmony_ci		if (snr)
19368c2ecf20Sopenharmony_ci			snr = (1000L * snr) >> 24;
19378c2ecf20Sopenharmony_ci		else
19388c2ecf20Sopenharmony_ci			snr = 0;
19398c2ecf20Sopenharmony_ci		c->cnr.stat[0].svalue = snr;
19408c2ecf20Sopenharmony_ci		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci		/* Get UCB measures */
19438c2ecf20Sopenharmony_ci		dib7000p_read_unc_blocks(demod, &val);
19448c2ecf20Sopenharmony_ci		ucb = val - state->old_ucb;
19458c2ecf20Sopenharmony_ci		if (val < state->old_ucb)
19468c2ecf20Sopenharmony_ci			ucb += 0x100000000LL;
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
19498c2ecf20Sopenharmony_ci		c->block_error.stat[0].uvalue = ucb;
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_ci		/* Estimate the number of packets based on bitrate */
19528c2ecf20Sopenharmony_ci		if (!time_us)
19538c2ecf20Sopenharmony_ci			time_us = dib7000p_get_time_us(demod);
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci		if (time_us) {
19568c2ecf20Sopenharmony_ci			blocks = 1250000ULL * 1000000ULL;
19578c2ecf20Sopenharmony_ci			do_div(blocks, time_us * 8 * 204);
19588c2ecf20Sopenharmony_ci			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
19598c2ecf20Sopenharmony_ci			c->block_count.stat[0].uvalue += blocks;
19608c2ecf20Sopenharmony_ci		}
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_ci		show_per_stats = 1;
19638c2ecf20Sopenharmony_ci	}
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	/* Get post-BER measures */
19668c2ecf20Sopenharmony_ci	if (time_after(jiffies, state->ber_jiffies_stats)) {
19678c2ecf20Sopenharmony_ci		time_us = dib7000p_get_time_us(demod);
19688c2ecf20Sopenharmony_ci		state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_ci		dprintk("Next all layers stats available in %u us.\n", time_us);
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci		dib7000p_read_ber(demod, &val);
19738c2ecf20Sopenharmony_ci		c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
19748c2ecf20Sopenharmony_ci		c->post_bit_error.stat[0].uvalue += val;
19758c2ecf20Sopenharmony_ci
19768c2ecf20Sopenharmony_ci		c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
19778c2ecf20Sopenharmony_ci		c->post_bit_count.stat[0].uvalue += 100000000;
19788c2ecf20Sopenharmony_ci	}
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_ci	/* Get PER measures */
19818c2ecf20Sopenharmony_ci	if (show_per_stats) {
19828c2ecf20Sopenharmony_ci		dib7000p_read_unc_blocks(demod, &val);
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
19858c2ecf20Sopenharmony_ci		c->block_error.stat[0].uvalue += val;
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci		time_us = dib7000p_get_time_us(demod);
19888c2ecf20Sopenharmony_ci		if (time_us) {
19898c2ecf20Sopenharmony_ci			blocks = 1250000ULL * 1000000ULL;
19908c2ecf20Sopenharmony_ci			do_div(blocks, time_us * 8 * 204);
19918c2ecf20Sopenharmony_ci			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
19928c2ecf20Sopenharmony_ci			c->block_count.stat[0].uvalue += blocks;
19938c2ecf20Sopenharmony_ci		}
19948c2ecf20Sopenharmony_ci	}
19958c2ecf20Sopenharmony_ci	return 0;
19968c2ecf20Sopenharmony_ci}
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_cistatic int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
19998c2ecf20Sopenharmony_ci{
20008c2ecf20Sopenharmony_ci	tune->min_delay_ms = 1000;
20018c2ecf20Sopenharmony_ci	return 0;
20028c2ecf20Sopenharmony_ci}
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_cistatic void dib7000p_release(struct dvb_frontend *demod)
20058c2ecf20Sopenharmony_ci{
20068c2ecf20Sopenharmony_ci	struct dib7000p_state *st = demod->demodulator_priv;
20078c2ecf20Sopenharmony_ci	dibx000_exit_i2c_master(&st->i2c_master);
20088c2ecf20Sopenharmony_ci	i2c_del_adapter(&st->dib7090_tuner_adap);
20098c2ecf20Sopenharmony_ci	kfree(st);
20108c2ecf20Sopenharmony_ci}
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_cistatic int dib7000pc_detection(struct i2c_adapter *i2c_adap)
20138c2ecf20Sopenharmony_ci{
20148c2ecf20Sopenharmony_ci	u8 *tx, *rx;
20158c2ecf20Sopenharmony_ci	struct i2c_msg msg[2] = {
20168c2ecf20Sopenharmony_ci		{.addr = 18 >> 1, .flags = 0, .len = 2},
20178c2ecf20Sopenharmony_ci		{.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
20188c2ecf20Sopenharmony_ci	};
20198c2ecf20Sopenharmony_ci	int ret = 0;
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	tx = kzalloc(2, GFP_KERNEL);
20228c2ecf20Sopenharmony_ci	if (!tx)
20238c2ecf20Sopenharmony_ci		return -ENOMEM;
20248c2ecf20Sopenharmony_ci	rx = kzalloc(2, GFP_KERNEL);
20258c2ecf20Sopenharmony_ci	if (!rx) {
20268c2ecf20Sopenharmony_ci		ret = -ENOMEM;
20278c2ecf20Sopenharmony_ci		goto rx_memory_error;
20288c2ecf20Sopenharmony_ci	}
20298c2ecf20Sopenharmony_ci
20308c2ecf20Sopenharmony_ci	msg[0].buf = tx;
20318c2ecf20Sopenharmony_ci	msg[1].buf = rx;
20328c2ecf20Sopenharmony_ci
20338c2ecf20Sopenharmony_ci	tx[0] = 0x03;
20348c2ecf20Sopenharmony_ci	tx[1] = 0x00;
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci	if (i2c_transfer(i2c_adap, msg, 2) == 2)
20378c2ecf20Sopenharmony_ci		if (rx[0] == 0x01 && rx[1] == 0xb3) {
20388c2ecf20Sopenharmony_ci			dprintk("-D-  DiB7000PC detected\n");
20398c2ecf20Sopenharmony_ci			ret = 1;
20408c2ecf20Sopenharmony_ci			goto out;
20418c2ecf20Sopenharmony_ci		}
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci	msg[0].addr = msg[1].addr = 0x40;
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_ci	if (i2c_transfer(i2c_adap, msg, 2) == 2)
20468c2ecf20Sopenharmony_ci		if (rx[0] == 0x01 && rx[1] == 0xb3) {
20478c2ecf20Sopenharmony_ci			dprintk("-D-  DiB7000PC detected\n");
20488c2ecf20Sopenharmony_ci			ret = 1;
20498c2ecf20Sopenharmony_ci			goto out;
20508c2ecf20Sopenharmony_ci		}
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci	dprintk("-D-  DiB7000PC not detected\n");
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ciout:
20558c2ecf20Sopenharmony_ci	kfree(rx);
20568c2ecf20Sopenharmony_cirx_memory_error:
20578c2ecf20Sopenharmony_ci	kfree(tx);
20588c2ecf20Sopenharmony_ci	return ret;
20598c2ecf20Sopenharmony_ci}
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_cistatic struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
20628c2ecf20Sopenharmony_ci{
20638c2ecf20Sopenharmony_ci	struct dib7000p_state *st = demod->demodulator_priv;
20648c2ecf20Sopenharmony_ci	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
20658c2ecf20Sopenharmony_ci}
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_cistatic int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
20688c2ecf20Sopenharmony_ci{
20698c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
20708c2ecf20Sopenharmony_ci	u16 val = dib7000p_read_word(state, 235) & 0xffef;
20718c2ecf20Sopenharmony_ci	val |= (onoff & 0x1) << 4;
20728c2ecf20Sopenharmony_ci	dprintk("PID filter enabled %d\n", onoff);
20738c2ecf20Sopenharmony_ci	return dib7000p_write_word(state, 235, val);
20748c2ecf20Sopenharmony_ci}
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_cistatic int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
20778c2ecf20Sopenharmony_ci{
20788c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
20798c2ecf20Sopenharmony_ci	dprintk("PID filter: index %x, PID %d, OnOff %d\n", id, pid, onoff);
20808c2ecf20Sopenharmony_ci	return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
20818c2ecf20Sopenharmony_ci}
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_cistatic int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
20848c2ecf20Sopenharmony_ci{
20858c2ecf20Sopenharmony_ci	struct dib7000p_state *dpst;
20868c2ecf20Sopenharmony_ci	int k = 0;
20878c2ecf20Sopenharmony_ci	u8 new_addr = 0;
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci	dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
20908c2ecf20Sopenharmony_ci	if (!dpst)
20918c2ecf20Sopenharmony_ci		return -ENOMEM;
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci	dpst->i2c_adap = i2c;
20948c2ecf20Sopenharmony_ci	mutex_init(&dpst->i2c_buffer_lock);
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	for (k = no_of_demods - 1; k >= 0; k--) {
20978c2ecf20Sopenharmony_ci		dpst->cfg = cfg[k];
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ci		/* designated i2c address */
21008c2ecf20Sopenharmony_ci		if (cfg[k].default_i2c_addr != 0)
21018c2ecf20Sopenharmony_ci			new_addr = cfg[k].default_i2c_addr + (k << 1);
21028c2ecf20Sopenharmony_ci		else
21038c2ecf20Sopenharmony_ci			new_addr = (0x40 + k) << 1;
21048c2ecf20Sopenharmony_ci		dpst->i2c_addr = new_addr;
21058c2ecf20Sopenharmony_ci		dib7000p_write_word(dpst, 1287, 0x0003);	/* sram lead in, rdy */
21068c2ecf20Sopenharmony_ci		if (dib7000p_identify(dpst) != 0) {
21078c2ecf20Sopenharmony_ci			dpst->i2c_addr = default_addr;
21088c2ecf20Sopenharmony_ci			dib7000p_write_word(dpst, 1287, 0x0003);	/* sram lead in, rdy */
21098c2ecf20Sopenharmony_ci			if (dib7000p_identify(dpst) != 0) {
21108c2ecf20Sopenharmony_ci				dprintk("DiB7000P #%d: not identified\n", k);
21118c2ecf20Sopenharmony_ci				kfree(dpst);
21128c2ecf20Sopenharmony_ci				return -EIO;
21138c2ecf20Sopenharmony_ci			}
21148c2ecf20Sopenharmony_ci		}
21158c2ecf20Sopenharmony_ci
21168c2ecf20Sopenharmony_ci		/* start diversity to pull_down div_str - just for i2c-enumeration */
21178c2ecf20Sopenharmony_ci		dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci		/* set new i2c address and force divstart */
21208c2ecf20Sopenharmony_ci		dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci		dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
21238c2ecf20Sopenharmony_ci	}
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci	for (k = 0; k < no_of_demods; k++) {
21268c2ecf20Sopenharmony_ci		dpst->cfg = cfg[k];
21278c2ecf20Sopenharmony_ci		if (cfg[k].default_i2c_addr != 0)
21288c2ecf20Sopenharmony_ci			dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
21298c2ecf20Sopenharmony_ci		else
21308c2ecf20Sopenharmony_ci			dpst->i2c_addr = (0x40 + k) << 1;
21318c2ecf20Sopenharmony_ci
21328c2ecf20Sopenharmony_ci		// unforce divstr
21338c2ecf20Sopenharmony_ci		dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_ci		/* deactivate div - it was just for i2c-enumeration */
21368c2ecf20Sopenharmony_ci		dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
21378c2ecf20Sopenharmony_ci	}
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_ci	kfree(dpst);
21408c2ecf20Sopenharmony_ci	return 0;
21418c2ecf20Sopenharmony_ci}
21428c2ecf20Sopenharmony_ci
21438c2ecf20Sopenharmony_cistatic const s32 lut_1000ln_mant[] = {
21448c2ecf20Sopenharmony_ci	6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
21458c2ecf20Sopenharmony_ci};
21468c2ecf20Sopenharmony_ci
21478c2ecf20Sopenharmony_cistatic s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
21488c2ecf20Sopenharmony_ci{
21498c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
21508c2ecf20Sopenharmony_ci	u32 tmp_val = 0, exp = 0, mant = 0;
21518c2ecf20Sopenharmony_ci	s32 pow_i;
21528c2ecf20Sopenharmony_ci	u16 buf[2];
21538c2ecf20Sopenharmony_ci	u8 ix = 0;
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	buf[0] = dib7000p_read_word(state, 0x184);
21568c2ecf20Sopenharmony_ci	buf[1] = dib7000p_read_word(state, 0x185);
21578c2ecf20Sopenharmony_ci	pow_i = (buf[0] << 16) | buf[1];
21588c2ecf20Sopenharmony_ci	dprintk("raw pow_i = %d\n", pow_i);
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci	tmp_val = pow_i;
21618c2ecf20Sopenharmony_ci	while (tmp_val >>= 1)
21628c2ecf20Sopenharmony_ci		exp++;
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci	mant = (pow_i * 1000 / (1 << exp));
21658c2ecf20Sopenharmony_ci	dprintk(" mant = %d exp = %d\n", mant / 1000, exp);
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci	ix = (u8) ((mant - 1000) / 100);	/* index of the LUT */
21688c2ecf20Sopenharmony_ci	dprintk(" ix = %d\n", ix);
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_ci	pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
21718c2ecf20Sopenharmony_ci	pow_i = (pow_i << 8) / 1000;
21728c2ecf20Sopenharmony_ci	dprintk(" pow_i = %d\n", pow_i);
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci	return pow_i;
21758c2ecf20Sopenharmony_ci}
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_cistatic int map_addr_to_serpar_number(struct i2c_msg *msg)
21788c2ecf20Sopenharmony_ci{
21798c2ecf20Sopenharmony_ci	if ((msg->buf[0] <= 15))
21808c2ecf20Sopenharmony_ci		msg->buf[0] -= 1;
21818c2ecf20Sopenharmony_ci	else if (msg->buf[0] == 17)
21828c2ecf20Sopenharmony_ci		msg->buf[0] = 15;
21838c2ecf20Sopenharmony_ci	else if (msg->buf[0] == 16)
21848c2ecf20Sopenharmony_ci		msg->buf[0] = 17;
21858c2ecf20Sopenharmony_ci	else if (msg->buf[0] == 19)
21868c2ecf20Sopenharmony_ci		msg->buf[0] = 16;
21878c2ecf20Sopenharmony_ci	else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
21888c2ecf20Sopenharmony_ci		msg->buf[0] -= 3;
21898c2ecf20Sopenharmony_ci	else if (msg->buf[0] == 28)
21908c2ecf20Sopenharmony_ci		msg->buf[0] = 23;
21918c2ecf20Sopenharmony_ci	else
21928c2ecf20Sopenharmony_ci		return -EINVAL;
21938c2ecf20Sopenharmony_ci	return 0;
21948c2ecf20Sopenharmony_ci}
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_cistatic int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
21978c2ecf20Sopenharmony_ci{
21988c2ecf20Sopenharmony_ci	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
21998c2ecf20Sopenharmony_ci	u8 n_overflow = 1;
22008c2ecf20Sopenharmony_ci	u16 i = 1000;
22018c2ecf20Sopenharmony_ci	u16 serpar_num = msg[0].buf[0];
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci	while (n_overflow == 1 && i) {
22048c2ecf20Sopenharmony_ci		n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
22058c2ecf20Sopenharmony_ci		i--;
22068c2ecf20Sopenharmony_ci		if (i == 0)
22078c2ecf20Sopenharmony_ci			dprintk("Tuner ITF: write busy (overflow)\n");
22088c2ecf20Sopenharmony_ci	}
22098c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
22108c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
22118c2ecf20Sopenharmony_ci
22128c2ecf20Sopenharmony_ci	return num;
22138c2ecf20Sopenharmony_ci}
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_cistatic int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
22168c2ecf20Sopenharmony_ci{
22178c2ecf20Sopenharmony_ci	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
22188c2ecf20Sopenharmony_ci	u8 n_overflow = 1, n_empty = 1;
22198c2ecf20Sopenharmony_ci	u16 i = 1000;
22208c2ecf20Sopenharmony_ci	u16 serpar_num = msg[0].buf[0];
22218c2ecf20Sopenharmony_ci	u16 read_word;
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	while (n_overflow == 1 && i) {
22248c2ecf20Sopenharmony_ci		n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
22258c2ecf20Sopenharmony_ci		i--;
22268c2ecf20Sopenharmony_ci		if (i == 0)
22278c2ecf20Sopenharmony_ci			dprintk("TunerITF: read busy (overflow)\n");
22288c2ecf20Sopenharmony_ci	}
22298c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
22308c2ecf20Sopenharmony_ci
22318c2ecf20Sopenharmony_ci	i = 1000;
22328c2ecf20Sopenharmony_ci	while (n_empty == 1 && i) {
22338c2ecf20Sopenharmony_ci		n_empty = dib7000p_read_word(state, 1984) & 0x1;
22348c2ecf20Sopenharmony_ci		i--;
22358c2ecf20Sopenharmony_ci		if (i == 0)
22368c2ecf20Sopenharmony_ci			dprintk("TunerITF: read busy (empty)\n");
22378c2ecf20Sopenharmony_ci	}
22388c2ecf20Sopenharmony_ci	read_word = dib7000p_read_word(state, 1987);
22398c2ecf20Sopenharmony_ci	msg[1].buf[0] = (read_word >> 8) & 0xff;
22408c2ecf20Sopenharmony_ci	msg[1].buf[1] = (read_word) & 0xff;
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci	return num;
22438c2ecf20Sopenharmony_ci}
22448c2ecf20Sopenharmony_ci
22458c2ecf20Sopenharmony_cistatic int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
22468c2ecf20Sopenharmony_ci{
22478c2ecf20Sopenharmony_ci	if (map_addr_to_serpar_number(&msg[0]) == 0) {	/* else = Tuner regs to ignore : DIG_CFG, CTRL_RF_LT, PLL_CFG, PWM1_REG, ADCCLK, DIG_CFG_3; SLEEP_EN... */
22488c2ecf20Sopenharmony_ci		if (num == 1) {	/* write */
22498c2ecf20Sopenharmony_ci			return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
22508c2ecf20Sopenharmony_ci		} else {	/* read */
22518c2ecf20Sopenharmony_ci			return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
22528c2ecf20Sopenharmony_ci		}
22538c2ecf20Sopenharmony_ci	}
22548c2ecf20Sopenharmony_ci	return num;
22558c2ecf20Sopenharmony_ci}
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_cistatic int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
22588c2ecf20Sopenharmony_ci		struct i2c_msg msg[], int num, u16 apb_address)
22598c2ecf20Sopenharmony_ci{
22608c2ecf20Sopenharmony_ci	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
22618c2ecf20Sopenharmony_ci	u16 word;
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_ci	if (num == 1) {		/* write */
22648c2ecf20Sopenharmony_ci		dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
22658c2ecf20Sopenharmony_ci	} else {
22668c2ecf20Sopenharmony_ci		word = dib7000p_read_word(state, apb_address);
22678c2ecf20Sopenharmony_ci		msg[1].buf[0] = (word >> 8) & 0xff;
22688c2ecf20Sopenharmony_ci		msg[1].buf[1] = (word) & 0xff;
22698c2ecf20Sopenharmony_ci	}
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_ci	return num;
22728c2ecf20Sopenharmony_ci}
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_cistatic int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
22758c2ecf20Sopenharmony_ci{
22768c2ecf20Sopenharmony_ci	struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
22778c2ecf20Sopenharmony_ci
22788c2ecf20Sopenharmony_ci	u16 apb_address = 0, word;
22798c2ecf20Sopenharmony_ci	int i = 0;
22808c2ecf20Sopenharmony_ci	switch (msg[0].buf[0]) {
22818c2ecf20Sopenharmony_ci	case 0x12:
22828c2ecf20Sopenharmony_ci		apb_address = 1920;
22838c2ecf20Sopenharmony_ci		break;
22848c2ecf20Sopenharmony_ci	case 0x14:
22858c2ecf20Sopenharmony_ci		apb_address = 1921;
22868c2ecf20Sopenharmony_ci		break;
22878c2ecf20Sopenharmony_ci	case 0x24:
22888c2ecf20Sopenharmony_ci		apb_address = 1922;
22898c2ecf20Sopenharmony_ci		break;
22908c2ecf20Sopenharmony_ci	case 0x1a:
22918c2ecf20Sopenharmony_ci		apb_address = 1923;
22928c2ecf20Sopenharmony_ci		break;
22938c2ecf20Sopenharmony_ci	case 0x22:
22948c2ecf20Sopenharmony_ci		apb_address = 1924;
22958c2ecf20Sopenharmony_ci		break;
22968c2ecf20Sopenharmony_ci	case 0x33:
22978c2ecf20Sopenharmony_ci		apb_address = 1926;
22988c2ecf20Sopenharmony_ci		break;
22998c2ecf20Sopenharmony_ci	case 0x34:
23008c2ecf20Sopenharmony_ci		apb_address = 1927;
23018c2ecf20Sopenharmony_ci		break;
23028c2ecf20Sopenharmony_ci	case 0x35:
23038c2ecf20Sopenharmony_ci		apb_address = 1928;
23048c2ecf20Sopenharmony_ci		break;
23058c2ecf20Sopenharmony_ci	case 0x36:
23068c2ecf20Sopenharmony_ci		apb_address = 1929;
23078c2ecf20Sopenharmony_ci		break;
23088c2ecf20Sopenharmony_ci	case 0x37:
23098c2ecf20Sopenharmony_ci		apb_address = 1930;
23108c2ecf20Sopenharmony_ci		break;
23118c2ecf20Sopenharmony_ci	case 0x38:
23128c2ecf20Sopenharmony_ci		apb_address = 1931;
23138c2ecf20Sopenharmony_ci		break;
23148c2ecf20Sopenharmony_ci	case 0x39:
23158c2ecf20Sopenharmony_ci		apb_address = 1932;
23168c2ecf20Sopenharmony_ci		break;
23178c2ecf20Sopenharmony_ci	case 0x2a:
23188c2ecf20Sopenharmony_ci		apb_address = 1935;
23198c2ecf20Sopenharmony_ci		break;
23208c2ecf20Sopenharmony_ci	case 0x2b:
23218c2ecf20Sopenharmony_ci		apb_address = 1936;
23228c2ecf20Sopenharmony_ci		break;
23238c2ecf20Sopenharmony_ci	case 0x2c:
23248c2ecf20Sopenharmony_ci		apb_address = 1937;
23258c2ecf20Sopenharmony_ci		break;
23268c2ecf20Sopenharmony_ci	case 0x2d:
23278c2ecf20Sopenharmony_ci		apb_address = 1938;
23288c2ecf20Sopenharmony_ci		break;
23298c2ecf20Sopenharmony_ci	case 0x2e:
23308c2ecf20Sopenharmony_ci		apb_address = 1939;
23318c2ecf20Sopenharmony_ci		break;
23328c2ecf20Sopenharmony_ci	case 0x2f:
23338c2ecf20Sopenharmony_ci		apb_address = 1940;
23348c2ecf20Sopenharmony_ci		break;
23358c2ecf20Sopenharmony_ci	case 0x30:
23368c2ecf20Sopenharmony_ci		apb_address = 1941;
23378c2ecf20Sopenharmony_ci		break;
23388c2ecf20Sopenharmony_ci	case 0x31:
23398c2ecf20Sopenharmony_ci		apb_address = 1942;
23408c2ecf20Sopenharmony_ci		break;
23418c2ecf20Sopenharmony_ci	case 0x32:
23428c2ecf20Sopenharmony_ci		apb_address = 1943;
23438c2ecf20Sopenharmony_ci		break;
23448c2ecf20Sopenharmony_ci	case 0x3e:
23458c2ecf20Sopenharmony_ci		apb_address = 1944;
23468c2ecf20Sopenharmony_ci		break;
23478c2ecf20Sopenharmony_ci	case 0x3f:
23488c2ecf20Sopenharmony_ci		apb_address = 1945;
23498c2ecf20Sopenharmony_ci		break;
23508c2ecf20Sopenharmony_ci	case 0x40:
23518c2ecf20Sopenharmony_ci		apb_address = 1948;
23528c2ecf20Sopenharmony_ci		break;
23538c2ecf20Sopenharmony_ci	case 0x25:
23548c2ecf20Sopenharmony_ci		apb_address = 914;
23558c2ecf20Sopenharmony_ci		break;
23568c2ecf20Sopenharmony_ci	case 0x26:
23578c2ecf20Sopenharmony_ci		apb_address = 915;
23588c2ecf20Sopenharmony_ci		break;
23598c2ecf20Sopenharmony_ci	case 0x27:
23608c2ecf20Sopenharmony_ci		apb_address = 917;
23618c2ecf20Sopenharmony_ci		break;
23628c2ecf20Sopenharmony_ci	case 0x28:
23638c2ecf20Sopenharmony_ci		apb_address = 916;
23648c2ecf20Sopenharmony_ci		break;
23658c2ecf20Sopenharmony_ci	case 0x1d:
23668c2ecf20Sopenharmony_ci		i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
23678c2ecf20Sopenharmony_ci		word = dib7000p_read_word(state, 384 + i);
23688c2ecf20Sopenharmony_ci		msg[1].buf[0] = (word >> 8) & 0xff;
23698c2ecf20Sopenharmony_ci		msg[1].buf[1] = (word) & 0xff;
23708c2ecf20Sopenharmony_ci		return num;
23718c2ecf20Sopenharmony_ci	case 0x1f:
23728c2ecf20Sopenharmony_ci		if (num == 1) {	/* write */
23738c2ecf20Sopenharmony_ci			word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
23748c2ecf20Sopenharmony_ci			word &= 0x3;
23758c2ecf20Sopenharmony_ci			word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
23768c2ecf20Sopenharmony_ci			dib7000p_write_word(state, 72, word);	/* Set the proper input */
23778c2ecf20Sopenharmony_ci			return num;
23788c2ecf20Sopenharmony_ci		}
23798c2ecf20Sopenharmony_ci	}
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_ci	if (apb_address != 0)	/* R/W access via APB */
23828c2ecf20Sopenharmony_ci		return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
23838c2ecf20Sopenharmony_ci	else			/* R/W access via SERPAR  */
23848c2ecf20Sopenharmony_ci		return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	return 0;
23878c2ecf20Sopenharmony_ci}
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_cistatic u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
23908c2ecf20Sopenharmony_ci{
23918c2ecf20Sopenharmony_ci	return I2C_FUNC_I2C;
23928c2ecf20Sopenharmony_ci}
23938c2ecf20Sopenharmony_ci
23948c2ecf20Sopenharmony_cistatic const struct i2c_algorithm dib7090_tuner_xfer_algo = {
23958c2ecf20Sopenharmony_ci	.master_xfer = dib7090_tuner_xfer,
23968c2ecf20Sopenharmony_ci	.functionality = dib7000p_i2c_func,
23978c2ecf20Sopenharmony_ci};
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_cistatic struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
24008c2ecf20Sopenharmony_ci{
24018c2ecf20Sopenharmony_ci	struct dib7000p_state *st = fe->demodulator_priv;
24028c2ecf20Sopenharmony_ci	return &st->dib7090_tuner_adap;
24038c2ecf20Sopenharmony_ci}
24048c2ecf20Sopenharmony_ci
24058c2ecf20Sopenharmony_cistatic int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
24068c2ecf20Sopenharmony_ci{
24078c2ecf20Sopenharmony_ci	u16 reg;
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_ci	/* drive host bus 2, 3, 4 */
24108c2ecf20Sopenharmony_ci	reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
24118c2ecf20Sopenharmony_ci	reg |= (drive << 12) | (drive << 6) | drive;
24128c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1798, reg);
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_ci	/* drive host bus 5,6 */
24158c2ecf20Sopenharmony_ci	reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
24168c2ecf20Sopenharmony_ci	reg |= (drive << 8) | (drive << 2);
24178c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1799, reg);
24188c2ecf20Sopenharmony_ci
24198c2ecf20Sopenharmony_ci	/* drive host bus 7, 8, 9 */
24208c2ecf20Sopenharmony_ci	reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
24218c2ecf20Sopenharmony_ci	reg |= (drive << 12) | (drive << 6) | drive;
24228c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1800, reg);
24238c2ecf20Sopenharmony_ci
24248c2ecf20Sopenharmony_ci	/* drive host bus 10, 11 */
24258c2ecf20Sopenharmony_ci	reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
24268c2ecf20Sopenharmony_ci	reg |= (drive << 8) | (drive << 2);
24278c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1801, reg);
24288c2ecf20Sopenharmony_ci
24298c2ecf20Sopenharmony_ci	/* drive host bus 12, 13, 14 */
24308c2ecf20Sopenharmony_ci	reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
24318c2ecf20Sopenharmony_ci	reg |= (drive << 12) | (drive << 6) | drive;
24328c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1802, reg);
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci	return 0;
24358c2ecf20Sopenharmony_ci}
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_cistatic u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
24388c2ecf20Sopenharmony_ci{
24398c2ecf20Sopenharmony_ci	u32 quantif = 3;
24408c2ecf20Sopenharmony_ci	u32 nom = (insertExtSynchro * P_Kin + syncSize);
24418c2ecf20Sopenharmony_ci	u32 denom = P_Kout;
24428c2ecf20Sopenharmony_ci	u32 syncFreq = ((nom << quantif) / denom);
24438c2ecf20Sopenharmony_ci
24448c2ecf20Sopenharmony_ci	if ((syncFreq & ((1 << quantif) - 1)) != 0)
24458c2ecf20Sopenharmony_ci		syncFreq = (syncFreq >> quantif) + 1;
24468c2ecf20Sopenharmony_ci	else
24478c2ecf20Sopenharmony_ci		syncFreq = (syncFreq >> quantif);
24488c2ecf20Sopenharmony_ci
24498c2ecf20Sopenharmony_ci	if (syncFreq != 0)
24508c2ecf20Sopenharmony_ci		syncFreq = syncFreq - 1;
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ci	return syncFreq;
24538c2ecf20Sopenharmony_ci}
24548c2ecf20Sopenharmony_ci
24558c2ecf20Sopenharmony_cistatic int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
24568c2ecf20Sopenharmony_ci{
24578c2ecf20Sopenharmony_ci	dprintk("Configure DibStream Tx\n");
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1615, 1);
24608c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1603, P_Kin);
24618c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1605, P_Kout);
24628c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1606, insertExtSynchro);
24638c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1608, synchroMode);
24648c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
24658c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1610, syncWord & 0xffff);
24668c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1612, syncSize);
24678c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1615, 0);
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ci	return 0;
24708c2ecf20Sopenharmony_ci}
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_cistatic int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
24738c2ecf20Sopenharmony_ci		u32 dataOutRate)
24748c2ecf20Sopenharmony_ci{
24758c2ecf20Sopenharmony_ci	u32 syncFreq;
24768c2ecf20Sopenharmony_ci
24778c2ecf20Sopenharmony_ci	dprintk("Configure DibStream Rx\n");
24788c2ecf20Sopenharmony_ci	if ((P_Kin != 0) && (P_Kout != 0)) {
24798c2ecf20Sopenharmony_ci		syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
24808c2ecf20Sopenharmony_ci		dib7000p_write_word(state, 1542, syncFreq);
24818c2ecf20Sopenharmony_ci	}
24828c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1554, 1);
24838c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1536, P_Kin);
24848c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1537, P_Kout);
24858c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1539, synchroMode);
24868c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
24878c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1541, syncWord & 0xffff);
24888c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1543, syncSize);
24898c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1544, dataOutRate);
24908c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1554, 0);
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_ci	return 0;
24938c2ecf20Sopenharmony_ci}
24948c2ecf20Sopenharmony_ci
24958c2ecf20Sopenharmony_cistatic void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
24968c2ecf20Sopenharmony_ci{
24978c2ecf20Sopenharmony_ci	u16 reg_1287 = dib7000p_read_word(state, 1287);
24988c2ecf20Sopenharmony_ci
24998c2ecf20Sopenharmony_ci	switch (onoff) {
25008c2ecf20Sopenharmony_ci	case 1:
25018c2ecf20Sopenharmony_ci			reg_1287 &= ~(1<<7);
25028c2ecf20Sopenharmony_ci			break;
25038c2ecf20Sopenharmony_ci	case 0:
25048c2ecf20Sopenharmony_ci			reg_1287 |= (1<<7);
25058c2ecf20Sopenharmony_ci			break;
25068c2ecf20Sopenharmony_ci	}
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1287, reg_1287);
25098c2ecf20Sopenharmony_ci}
25108c2ecf20Sopenharmony_ci
25118c2ecf20Sopenharmony_cistatic void dib7090_configMpegMux(struct dib7000p_state *state,
25128c2ecf20Sopenharmony_ci		u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
25138c2ecf20Sopenharmony_ci{
25148c2ecf20Sopenharmony_ci	dprintk("Enable Mpeg mux\n");
25158c2ecf20Sopenharmony_ci
25168c2ecf20Sopenharmony_ci	dib7090_enMpegMux(state, 0);
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ci	/* If the input mode is MPEG do not divide the serial clock */
25198c2ecf20Sopenharmony_ci	if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
25208c2ecf20Sopenharmony_ci		enSerialClkDiv2 = 0;
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
25238c2ecf20Sopenharmony_ci			| ((enSerialMode & 0x1) << 1)
25248c2ecf20Sopenharmony_ci			| (enSerialClkDiv2 & 0x1));
25258c2ecf20Sopenharmony_ci
25268c2ecf20Sopenharmony_ci	dib7090_enMpegMux(state, 1);
25278c2ecf20Sopenharmony_ci}
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_cistatic void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
25308c2ecf20Sopenharmony_ci{
25318c2ecf20Sopenharmony_ci	u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
25328c2ecf20Sopenharmony_ci
25338c2ecf20Sopenharmony_ci	switch (mode) {
25348c2ecf20Sopenharmony_ci	case MPEG_ON_DIBTX:
25358c2ecf20Sopenharmony_ci			dprintk("SET MPEG ON DIBSTREAM TX\n");
25368c2ecf20Sopenharmony_ci			dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
25378c2ecf20Sopenharmony_ci			reg_1288 |= (1<<9);
25388c2ecf20Sopenharmony_ci			break;
25398c2ecf20Sopenharmony_ci	case DIV_ON_DIBTX:
25408c2ecf20Sopenharmony_ci			dprintk("SET DIV_OUT ON DIBSTREAM TX\n");
25418c2ecf20Sopenharmony_ci			dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
25428c2ecf20Sopenharmony_ci			reg_1288 |= (1<<8);
25438c2ecf20Sopenharmony_ci			break;
25448c2ecf20Sopenharmony_ci	case ADC_ON_DIBTX:
25458c2ecf20Sopenharmony_ci			dprintk("SET ADC_OUT ON DIBSTREAM TX\n");
25468c2ecf20Sopenharmony_ci			dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
25478c2ecf20Sopenharmony_ci			reg_1288 |= (1<<7);
25488c2ecf20Sopenharmony_ci			break;
25498c2ecf20Sopenharmony_ci	default:
25508c2ecf20Sopenharmony_ci			break;
25518c2ecf20Sopenharmony_ci	}
25528c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1288, reg_1288);
25538c2ecf20Sopenharmony_ci}
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_cistatic void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
25568c2ecf20Sopenharmony_ci{
25578c2ecf20Sopenharmony_ci	u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
25588c2ecf20Sopenharmony_ci
25598c2ecf20Sopenharmony_ci	switch (mode) {
25608c2ecf20Sopenharmony_ci	case DEMOUT_ON_HOSTBUS:
25618c2ecf20Sopenharmony_ci			dprintk("SET DEM OUT OLD INTERF ON HOST BUS\n");
25628c2ecf20Sopenharmony_ci			dib7090_enMpegMux(state, 0);
25638c2ecf20Sopenharmony_ci			reg_1288 |= (1<<6);
25648c2ecf20Sopenharmony_ci			break;
25658c2ecf20Sopenharmony_ci	case DIBTX_ON_HOSTBUS:
25668c2ecf20Sopenharmony_ci			dprintk("SET DIBSTREAM TX ON HOST BUS\n");
25678c2ecf20Sopenharmony_ci			dib7090_enMpegMux(state, 0);
25688c2ecf20Sopenharmony_ci			reg_1288 |= (1<<5);
25698c2ecf20Sopenharmony_ci			break;
25708c2ecf20Sopenharmony_ci	case MPEG_ON_HOSTBUS:
25718c2ecf20Sopenharmony_ci			dprintk("SET MPEG MUX ON HOST BUS\n");
25728c2ecf20Sopenharmony_ci			reg_1288 |= (1<<4);
25738c2ecf20Sopenharmony_ci			break;
25748c2ecf20Sopenharmony_ci	default:
25758c2ecf20Sopenharmony_ci			break;
25768c2ecf20Sopenharmony_ci	}
25778c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1288, reg_1288);
25788c2ecf20Sopenharmony_ci}
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_cistatic int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
25818c2ecf20Sopenharmony_ci{
25828c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
25838c2ecf20Sopenharmony_ci	u16 reg_1287;
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_ci	switch (onoff) {
25868c2ecf20Sopenharmony_ci	case 0: /* only use the internal way - not the diversity input */
25878c2ecf20Sopenharmony_ci			dprintk("%s mode OFF : by default Enable Mpeg INPUT\n", __func__);
25888c2ecf20Sopenharmony_ci			dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_ci			/* Do not divide the serial clock of MPEG MUX */
25918c2ecf20Sopenharmony_ci			/* in SERIAL MODE in case input mode MPEG is used */
25928c2ecf20Sopenharmony_ci			reg_1287 = dib7000p_read_word(state, 1287);
25938c2ecf20Sopenharmony_ci			/* enSerialClkDiv2 == 1 ? */
25948c2ecf20Sopenharmony_ci			if ((reg_1287 & 0x1) == 1) {
25958c2ecf20Sopenharmony_ci				/* force enSerialClkDiv2 = 0 */
25968c2ecf20Sopenharmony_ci				reg_1287 &= ~0x1;
25978c2ecf20Sopenharmony_ci				dib7000p_write_word(state, 1287, reg_1287);
25988c2ecf20Sopenharmony_ci			}
25998c2ecf20Sopenharmony_ci			state->input_mode_mpeg = 1;
26008c2ecf20Sopenharmony_ci			break;
26018c2ecf20Sopenharmony_ci	case 1: /* both ways */
26028c2ecf20Sopenharmony_ci	case 2: /* only the diversity input */
26038c2ecf20Sopenharmony_ci			dprintk("%s ON : Enable diversity INPUT\n", __func__);
26048c2ecf20Sopenharmony_ci			dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
26058c2ecf20Sopenharmony_ci			state->input_mode_mpeg = 0;
26068c2ecf20Sopenharmony_ci			break;
26078c2ecf20Sopenharmony_ci	}
26088c2ecf20Sopenharmony_ci
26098c2ecf20Sopenharmony_ci	dib7000p_set_diversity_in(&state->demod, onoff);
26108c2ecf20Sopenharmony_ci	return 0;
26118c2ecf20Sopenharmony_ci}
26128c2ecf20Sopenharmony_ci
26138c2ecf20Sopenharmony_cistatic int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
26148c2ecf20Sopenharmony_ci{
26158c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
26168c2ecf20Sopenharmony_ci
26178c2ecf20Sopenharmony_ci	u16 outreg, smo_mode, fifo_threshold;
26188c2ecf20Sopenharmony_ci	u8 prefer_mpeg_mux_use = 1;
26198c2ecf20Sopenharmony_ci	int ret = 0;
26208c2ecf20Sopenharmony_ci
26218c2ecf20Sopenharmony_ci	dib7090_host_bus_drive(state, 1);
26228c2ecf20Sopenharmony_ci
26238c2ecf20Sopenharmony_ci	fifo_threshold = 1792;
26248c2ecf20Sopenharmony_ci	smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
26258c2ecf20Sopenharmony_ci	outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	switch (mode) {
26288c2ecf20Sopenharmony_ci	case OUTMODE_HIGH_Z:
26298c2ecf20Sopenharmony_ci		outreg = 0;
26308c2ecf20Sopenharmony_ci		break;
26318c2ecf20Sopenharmony_ci
26328c2ecf20Sopenharmony_ci	case OUTMODE_MPEG2_SERIAL:
26338c2ecf20Sopenharmony_ci		if (prefer_mpeg_mux_use) {
26348c2ecf20Sopenharmony_ci			dprintk("setting output mode TS_SERIAL using Mpeg Mux\n");
26358c2ecf20Sopenharmony_ci			dib7090_configMpegMux(state, 3, 1, 1);
26368c2ecf20Sopenharmony_ci			dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
26378c2ecf20Sopenharmony_ci		} else {/* Use Smooth block */
26388c2ecf20Sopenharmony_ci			dprintk("setting output mode TS_SERIAL using Smooth bloc\n");
26398c2ecf20Sopenharmony_ci			dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
26408c2ecf20Sopenharmony_ci			outreg |= (2<<6) | (0 << 1);
26418c2ecf20Sopenharmony_ci		}
26428c2ecf20Sopenharmony_ci		break;
26438c2ecf20Sopenharmony_ci
26448c2ecf20Sopenharmony_ci	case OUTMODE_MPEG2_PAR_GATED_CLK:
26458c2ecf20Sopenharmony_ci		if (prefer_mpeg_mux_use) {
26468c2ecf20Sopenharmony_ci			dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux\n");
26478c2ecf20Sopenharmony_ci			dib7090_configMpegMux(state, 2, 0, 0);
26488c2ecf20Sopenharmony_ci			dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
26498c2ecf20Sopenharmony_ci		} else { /* Use Smooth block */
26508c2ecf20Sopenharmony_ci			dprintk("setting output mode TS_PARALLEL_GATED using Smooth block\n");
26518c2ecf20Sopenharmony_ci			dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
26528c2ecf20Sopenharmony_ci			outreg |= (0<<6);
26538c2ecf20Sopenharmony_ci		}
26548c2ecf20Sopenharmony_ci		break;
26558c2ecf20Sopenharmony_ci
26568c2ecf20Sopenharmony_ci	case OUTMODE_MPEG2_PAR_CONT_CLK:	/* Using Smooth block only */
26578c2ecf20Sopenharmony_ci		dprintk("setting output mode TS_PARALLEL_CONT using Smooth block\n");
26588c2ecf20Sopenharmony_ci		dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
26598c2ecf20Sopenharmony_ci		outreg |= (1<<6);
26608c2ecf20Sopenharmony_ci		break;
26618c2ecf20Sopenharmony_ci
26628c2ecf20Sopenharmony_ci	case OUTMODE_MPEG2_FIFO:	/* Using Smooth block because not supported by new Mpeg Mux bloc */
26638c2ecf20Sopenharmony_ci		dprintk("setting output mode TS_FIFO using Smooth block\n");
26648c2ecf20Sopenharmony_ci		dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
26658c2ecf20Sopenharmony_ci		outreg |= (5<<6);
26668c2ecf20Sopenharmony_ci		smo_mode |= (3 << 1);
26678c2ecf20Sopenharmony_ci		fifo_threshold = 512;
26688c2ecf20Sopenharmony_ci		break;
26698c2ecf20Sopenharmony_ci
26708c2ecf20Sopenharmony_ci	case OUTMODE_DIVERSITY:
26718c2ecf20Sopenharmony_ci		dprintk("setting output mode MODE_DIVERSITY\n");
26728c2ecf20Sopenharmony_ci		dib7090_setDibTxMux(state, DIV_ON_DIBTX);
26738c2ecf20Sopenharmony_ci		dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
26748c2ecf20Sopenharmony_ci		break;
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_ci	case OUTMODE_ANALOG_ADC:
26778c2ecf20Sopenharmony_ci		dprintk("setting output mode MODE_ANALOG_ADC\n");
26788c2ecf20Sopenharmony_ci		dib7090_setDibTxMux(state, ADC_ON_DIBTX);
26798c2ecf20Sopenharmony_ci		dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
26808c2ecf20Sopenharmony_ci		break;
26818c2ecf20Sopenharmony_ci	}
26828c2ecf20Sopenharmony_ci	if (mode != OUTMODE_HIGH_Z)
26838c2ecf20Sopenharmony_ci		outreg |= (1 << 10);
26848c2ecf20Sopenharmony_ci
26858c2ecf20Sopenharmony_ci	if (state->cfg.output_mpeg2_in_188_bytes)
26868c2ecf20Sopenharmony_ci		smo_mode |= (1 << 5);
26878c2ecf20Sopenharmony_ci
26888c2ecf20Sopenharmony_ci	ret |= dib7000p_write_word(state, 235, smo_mode);
26898c2ecf20Sopenharmony_ci	ret |= dib7000p_write_word(state, 236, fifo_threshold);	/* synchronous fread */
26908c2ecf20Sopenharmony_ci	ret |= dib7000p_write_word(state, 1286, outreg);
26918c2ecf20Sopenharmony_ci
26928c2ecf20Sopenharmony_ci	return ret;
26938c2ecf20Sopenharmony_ci}
26948c2ecf20Sopenharmony_ci
26958c2ecf20Sopenharmony_cistatic int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
26968c2ecf20Sopenharmony_ci{
26978c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
26988c2ecf20Sopenharmony_ci	u16 en_cur_state;
26998c2ecf20Sopenharmony_ci
27008c2ecf20Sopenharmony_ci	dprintk("sleep dib7090: %d\n", onoff);
27018c2ecf20Sopenharmony_ci
27028c2ecf20Sopenharmony_ci	en_cur_state = dib7000p_read_word(state, 1922);
27038c2ecf20Sopenharmony_ci
27048c2ecf20Sopenharmony_ci	if (en_cur_state > 0xff)
27058c2ecf20Sopenharmony_ci		state->tuner_enable = en_cur_state;
27068c2ecf20Sopenharmony_ci
27078c2ecf20Sopenharmony_ci	if (onoff)
27088c2ecf20Sopenharmony_ci		en_cur_state &= 0x00ff;
27098c2ecf20Sopenharmony_ci	else {
27108c2ecf20Sopenharmony_ci		if (state->tuner_enable != 0)
27118c2ecf20Sopenharmony_ci			en_cur_state = state->tuner_enable;
27128c2ecf20Sopenharmony_ci	}
27138c2ecf20Sopenharmony_ci
27148c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1922, en_cur_state);
27158c2ecf20Sopenharmony_ci
27168c2ecf20Sopenharmony_ci	return 0;
27178c2ecf20Sopenharmony_ci}
27188c2ecf20Sopenharmony_ci
27198c2ecf20Sopenharmony_cistatic int dib7090_get_adc_power(struct dvb_frontend *fe)
27208c2ecf20Sopenharmony_ci{
27218c2ecf20Sopenharmony_ci	return dib7000p_get_adc_power(fe);
27228c2ecf20Sopenharmony_ci}
27238c2ecf20Sopenharmony_ci
27248c2ecf20Sopenharmony_cistatic int dib7090_slave_reset(struct dvb_frontend *fe)
27258c2ecf20Sopenharmony_ci{
27268c2ecf20Sopenharmony_ci	struct dib7000p_state *state = fe->demodulator_priv;
27278c2ecf20Sopenharmony_ci	u16 reg;
27288c2ecf20Sopenharmony_ci
27298c2ecf20Sopenharmony_ci	reg = dib7000p_read_word(state, 1794);
27308c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1794, reg | (4 << 12));
27318c2ecf20Sopenharmony_ci
27328c2ecf20Sopenharmony_ci	dib7000p_write_word(state, 1032, 0xffff);
27338c2ecf20Sopenharmony_ci	return 0;
27348c2ecf20Sopenharmony_ci}
27358c2ecf20Sopenharmony_ci
27368c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dib7000p_ops;
27378c2ecf20Sopenharmony_cistatic struct dvb_frontend *dib7000p_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
27388c2ecf20Sopenharmony_ci{
27398c2ecf20Sopenharmony_ci	struct dvb_frontend *demod;
27408c2ecf20Sopenharmony_ci	struct dib7000p_state *st;
27418c2ecf20Sopenharmony_ci	st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
27428c2ecf20Sopenharmony_ci	if (st == NULL)
27438c2ecf20Sopenharmony_ci		return NULL;
27448c2ecf20Sopenharmony_ci
27458c2ecf20Sopenharmony_ci	memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
27468c2ecf20Sopenharmony_ci	st->i2c_adap = i2c_adap;
27478c2ecf20Sopenharmony_ci	st->i2c_addr = i2c_addr;
27488c2ecf20Sopenharmony_ci	st->gpio_val = cfg->gpio_val;
27498c2ecf20Sopenharmony_ci	st->gpio_dir = cfg->gpio_dir;
27508c2ecf20Sopenharmony_ci
27518c2ecf20Sopenharmony_ci	/* Ensure the output mode remains at the previous default if it's
27528c2ecf20Sopenharmony_ci	 * not specifically set by the caller.
27538c2ecf20Sopenharmony_ci	 */
27548c2ecf20Sopenharmony_ci	if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
27558c2ecf20Sopenharmony_ci		st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
27568c2ecf20Sopenharmony_ci
27578c2ecf20Sopenharmony_ci	demod = &st->demod;
27588c2ecf20Sopenharmony_ci	demod->demodulator_priv = st;
27598c2ecf20Sopenharmony_ci	memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
27608c2ecf20Sopenharmony_ci	mutex_init(&st->i2c_buffer_lock);
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_ci	dib7000p_write_word(st, 1287, 0x0003);	/* sram lead in, rdy */
27638c2ecf20Sopenharmony_ci
27648c2ecf20Sopenharmony_ci	if (dib7000p_identify(st) != 0)
27658c2ecf20Sopenharmony_ci		goto error;
27668c2ecf20Sopenharmony_ci
27678c2ecf20Sopenharmony_ci	st->version = dib7000p_read_word(st, 897);
27688c2ecf20Sopenharmony_ci
27698c2ecf20Sopenharmony_ci	/* FIXME: make sure the dev.parent field is initialized, or else
27708c2ecf20Sopenharmony_ci	   request_firmware() will hit an OOPS (this should be moved somewhere
27718c2ecf20Sopenharmony_ci	   more common) */
27728c2ecf20Sopenharmony_ci	st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
27738c2ecf20Sopenharmony_ci
27748c2ecf20Sopenharmony_ci	dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_ci	/* init 7090 tuner adapter */
27778c2ecf20Sopenharmony_ci	strscpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface",
27788c2ecf20Sopenharmony_ci		sizeof(st->dib7090_tuner_adap.name));
27798c2ecf20Sopenharmony_ci	st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
27808c2ecf20Sopenharmony_ci	st->dib7090_tuner_adap.algo_data = NULL;
27818c2ecf20Sopenharmony_ci	st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
27828c2ecf20Sopenharmony_ci	i2c_set_adapdata(&st->dib7090_tuner_adap, st);
27838c2ecf20Sopenharmony_ci	i2c_add_adapter(&st->dib7090_tuner_adap);
27848c2ecf20Sopenharmony_ci
27858c2ecf20Sopenharmony_ci	dib7000p_demod_reset(st);
27868c2ecf20Sopenharmony_ci
27878c2ecf20Sopenharmony_ci	dib7000p_reset_stats(demod);
27888c2ecf20Sopenharmony_ci
27898c2ecf20Sopenharmony_ci	if (st->version == SOC7090) {
27908c2ecf20Sopenharmony_ci		dib7090_set_output_mode(demod, st->cfg.output_mode);
27918c2ecf20Sopenharmony_ci		dib7090_set_diversity_in(demod, 0);
27928c2ecf20Sopenharmony_ci	}
27938c2ecf20Sopenharmony_ci
27948c2ecf20Sopenharmony_ci	return demod;
27958c2ecf20Sopenharmony_ci
27968c2ecf20Sopenharmony_cierror:
27978c2ecf20Sopenharmony_ci	kfree(st);
27988c2ecf20Sopenharmony_ci	return NULL;
27998c2ecf20Sopenharmony_ci}
28008c2ecf20Sopenharmony_ci
28018c2ecf20Sopenharmony_civoid *dib7000p_attach(struct dib7000p_ops *ops)
28028c2ecf20Sopenharmony_ci{
28038c2ecf20Sopenharmony_ci	if (!ops)
28048c2ecf20Sopenharmony_ci		return NULL;
28058c2ecf20Sopenharmony_ci
28068c2ecf20Sopenharmony_ci	ops->slave_reset = dib7090_slave_reset;
28078c2ecf20Sopenharmony_ci	ops->get_adc_power = dib7090_get_adc_power;
28088c2ecf20Sopenharmony_ci	ops->dib7000pc_detection = dib7000pc_detection;
28098c2ecf20Sopenharmony_ci	ops->get_i2c_tuner = dib7090_get_i2c_tuner;
28108c2ecf20Sopenharmony_ci	ops->tuner_sleep = dib7090_tuner_sleep;
28118c2ecf20Sopenharmony_ci	ops->init = dib7000p_init;
28128c2ecf20Sopenharmony_ci	ops->set_agc1_min = dib7000p_set_agc1_min;
28138c2ecf20Sopenharmony_ci	ops->set_gpio = dib7000p_set_gpio;
28148c2ecf20Sopenharmony_ci	ops->i2c_enumeration = dib7000p_i2c_enumeration;
28158c2ecf20Sopenharmony_ci	ops->pid_filter = dib7000p_pid_filter;
28168c2ecf20Sopenharmony_ci	ops->pid_filter_ctrl = dib7000p_pid_filter_ctrl;
28178c2ecf20Sopenharmony_ci	ops->get_i2c_master = dib7000p_get_i2c_master;
28188c2ecf20Sopenharmony_ci	ops->update_pll = dib7000p_update_pll;
28198c2ecf20Sopenharmony_ci	ops->ctrl_timf = dib7000p_ctrl_timf;
28208c2ecf20Sopenharmony_ci	ops->get_agc_values = dib7000p_get_agc_values;
28218c2ecf20Sopenharmony_ci	ops->set_wbd_ref = dib7000p_set_wbd_ref;
28228c2ecf20Sopenharmony_ci
28238c2ecf20Sopenharmony_ci	return ops;
28248c2ecf20Sopenharmony_ci}
28258c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dib7000p_attach);
28268c2ecf20Sopenharmony_ci
28278c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dib7000p_ops = {
28288c2ecf20Sopenharmony_ci	.delsys = { SYS_DVBT },
28298c2ecf20Sopenharmony_ci	.info = {
28308c2ecf20Sopenharmony_ci		 .name = "DiBcom 7000PC",
28318c2ecf20Sopenharmony_ci		 .frequency_min_hz =  44250 * kHz,
28328c2ecf20Sopenharmony_ci		 .frequency_max_hz = 867250 * kHz,
28338c2ecf20Sopenharmony_ci		 .frequency_stepsize_hz = 62500,
28348c2ecf20Sopenharmony_ci		 .caps = FE_CAN_INVERSION_AUTO |
28358c2ecf20Sopenharmony_ci		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
28368c2ecf20Sopenharmony_ci		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
28378c2ecf20Sopenharmony_ci		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
28388c2ecf20Sopenharmony_ci		 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
28398c2ecf20Sopenharmony_ci		 },
28408c2ecf20Sopenharmony_ci
28418c2ecf20Sopenharmony_ci	.release = dib7000p_release,
28428c2ecf20Sopenharmony_ci
28438c2ecf20Sopenharmony_ci	.init = dib7000p_wakeup,
28448c2ecf20Sopenharmony_ci	.sleep = dib7000p_sleep,
28458c2ecf20Sopenharmony_ci
28468c2ecf20Sopenharmony_ci	.set_frontend = dib7000p_set_frontend,
28478c2ecf20Sopenharmony_ci	.get_tune_settings = dib7000p_fe_get_tune_settings,
28488c2ecf20Sopenharmony_ci	.get_frontend = dib7000p_get_frontend,
28498c2ecf20Sopenharmony_ci
28508c2ecf20Sopenharmony_ci	.read_status = dib7000p_read_status,
28518c2ecf20Sopenharmony_ci	.read_ber = dib7000p_read_ber,
28528c2ecf20Sopenharmony_ci	.read_signal_strength = dib7000p_read_signal_strength,
28538c2ecf20Sopenharmony_ci	.read_snr = dib7000p_read_snr,
28548c2ecf20Sopenharmony_ci	.read_ucblocks = dib7000p_read_unc_blocks,
28558c2ecf20Sopenharmony_ci};
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_ciMODULE_AUTHOR("Olivier Grenie <olivie.grenie@parrot.com>");
28588c2ecf20Sopenharmony_ciMODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
28598c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
28608c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
2861