18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Linux-DVB Driver for DiBcom's DiB7000M and
48c2ecf20Sopenharmony_ci *              first generation DiB7000P-demodulator-family.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/slab.h>
138c2ecf20Sopenharmony_ci#include <linux/i2c.h>
148c2ecf20Sopenharmony_ci#include <linux/mutex.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "dib7000m.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic int debug;
218c2ecf20Sopenharmony_cimodule_param(debug, int, 0644);
228c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define dprintk(fmt, arg...) do {					\
258c2ecf20Sopenharmony_ci	if (debug)							\
268c2ecf20Sopenharmony_ci		printk(KERN_DEBUG pr_fmt("%s: " fmt),			\
278c2ecf20Sopenharmony_ci		       __func__, ##arg);				\
288c2ecf20Sopenharmony_ci} while (0)
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistruct dib7000m_state {
318c2ecf20Sopenharmony_ci	struct dvb_frontend demod;
328c2ecf20Sopenharmony_ci    struct dib7000m_config cfg;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	u8 i2c_addr;
358c2ecf20Sopenharmony_ci	struct i2c_adapter   *i2c_adap;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	struct dibx000_i2c_master i2c_master;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/* offset is 1 in case of the 7000MC */
408c2ecf20Sopenharmony_ci	u8 reg_offs;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	u16 wbd_ref;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	u8 current_band;
458c2ecf20Sopenharmony_ci	u32 current_bandwidth;
468c2ecf20Sopenharmony_ci	struct dibx000_agc_config *current_agc;
478c2ecf20Sopenharmony_ci	u32 timf;
488c2ecf20Sopenharmony_ci	u32 timf_default;
498c2ecf20Sopenharmony_ci	u32 internal_clk;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	u8 div_force_off : 1;
528c2ecf20Sopenharmony_ci	u8 div_state : 1;
538c2ecf20Sopenharmony_ci	u16 div_sync_wait;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	u16 revision;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	u8 agc_state;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	/* for the I2C transfer */
608c2ecf20Sopenharmony_ci	struct i2c_msg msg[2];
618c2ecf20Sopenharmony_ci	u8 i2c_write_buffer[4];
628c2ecf20Sopenharmony_ci	u8 i2c_read_buffer[2];
638c2ecf20Sopenharmony_ci	struct mutex i2c_buffer_lock;
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cienum dib7000m_power_mode {
678c2ecf20Sopenharmony_ci	DIB7000M_POWER_ALL = 0,
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	DIB7000M_POWER_NO,
708c2ecf20Sopenharmony_ci	DIB7000M_POWER_INTERF_ANALOG_AGC,
718c2ecf20Sopenharmony_ci	DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD,
728c2ecf20Sopenharmony_ci	DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD,
738c2ecf20Sopenharmony_ci	DIB7000M_POWER_INTERFACE_ONLY,
748c2ecf20Sopenharmony_ci};
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	u16 ret;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
818c2ecf20Sopenharmony_ci		dprintk("could not acquire lock\n");
828c2ecf20Sopenharmony_ci		return 0;
838c2ecf20Sopenharmony_ci	}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	state->i2c_write_buffer[0] = (reg >> 8) | 0x80;
868c2ecf20Sopenharmony_ci	state->i2c_write_buffer[1] = reg & 0xff;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
898c2ecf20Sopenharmony_ci	state->msg[0].addr = state->i2c_addr >> 1;
908c2ecf20Sopenharmony_ci	state->msg[0].flags = 0;
918c2ecf20Sopenharmony_ci	state->msg[0].buf = state->i2c_write_buffer;
928c2ecf20Sopenharmony_ci	state->msg[0].len = 2;
938c2ecf20Sopenharmony_ci	state->msg[1].addr = state->i2c_addr >> 1;
948c2ecf20Sopenharmony_ci	state->msg[1].flags = I2C_M_RD;
958c2ecf20Sopenharmony_ci	state->msg[1].buf = state->i2c_read_buffer;
968c2ecf20Sopenharmony_ci	state->msg[1].len = 2;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
998c2ecf20Sopenharmony_ci		dprintk("i2c read error on %d\n", reg);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
1028c2ecf20Sopenharmony_ci	mutex_unlock(&state->i2c_buffer_lock);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	return ret;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	int ret;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
1128c2ecf20Sopenharmony_ci		dprintk("could not acquire lock\n");
1138c2ecf20Sopenharmony_ci		return -EINVAL;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
1178c2ecf20Sopenharmony_ci	state->i2c_write_buffer[1] = reg & 0xff;
1188c2ecf20Sopenharmony_ci	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
1198c2ecf20Sopenharmony_ci	state->i2c_write_buffer[3] = val & 0xff;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	memset(&state->msg[0], 0, sizeof(struct i2c_msg));
1228c2ecf20Sopenharmony_ci	state->msg[0].addr = state->i2c_addr >> 1;
1238c2ecf20Sopenharmony_ci	state->msg[0].flags = 0;
1248c2ecf20Sopenharmony_ci	state->msg[0].buf = state->i2c_write_buffer;
1258c2ecf20Sopenharmony_ci	state->msg[0].len = 4;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
1288c2ecf20Sopenharmony_ci			-EREMOTEIO : 0);
1298c2ecf20Sopenharmony_ci	mutex_unlock(&state->i2c_buffer_lock);
1308c2ecf20Sopenharmony_ci	return ret;
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_cistatic void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	u16 l = 0, r, *n;
1358c2ecf20Sopenharmony_ci	n = buf;
1368c2ecf20Sopenharmony_ci	l = *n++;
1378c2ecf20Sopenharmony_ci	while (l) {
1388c2ecf20Sopenharmony_ci		r = *n++;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci		if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC
1418c2ecf20Sopenharmony_ci			r++;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci		do {
1448c2ecf20Sopenharmony_ci			dib7000m_write_word(state, r, *n++);
1458c2ecf20Sopenharmony_ci			r++;
1468c2ecf20Sopenharmony_ci		} while (--l);
1478c2ecf20Sopenharmony_ci		l = *n++;
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	int    ret = 0;
1548c2ecf20Sopenharmony_ci	u16 outreg, fifo_threshold, smo_mode,
1558c2ecf20Sopenharmony_ci		sram = 0x0005; /* by default SRAM output is disabled */
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	outreg = 0;
1588c2ecf20Sopenharmony_ci	fifo_threshold = 1792;
1598c2ecf20Sopenharmony_ci	smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	dprintk("setting output mode for demod %p to %d\n", &state->demod, mode);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	switch (mode) {
1648c2ecf20Sopenharmony_ci		case OUTMODE_MPEG2_PAR_GATED_CLK:   // STBs with parallel gated clock
1658c2ecf20Sopenharmony_ci			outreg = (1 << 10);  /* 0x0400 */
1668c2ecf20Sopenharmony_ci			break;
1678c2ecf20Sopenharmony_ci		case OUTMODE_MPEG2_PAR_CONT_CLK:    // STBs with parallel continues clock
1688c2ecf20Sopenharmony_ci			outreg = (1 << 10) | (1 << 6); /* 0x0440 */
1698c2ecf20Sopenharmony_ci			break;
1708c2ecf20Sopenharmony_ci		case OUTMODE_MPEG2_SERIAL:          // STBs with serial input
1718c2ecf20Sopenharmony_ci			outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
1728c2ecf20Sopenharmony_ci			break;
1738c2ecf20Sopenharmony_ci		case OUTMODE_DIVERSITY:
1748c2ecf20Sopenharmony_ci			if (state->cfg.hostbus_diversity)
1758c2ecf20Sopenharmony_ci				outreg = (1 << 10) | (4 << 6); /* 0x0500 */
1768c2ecf20Sopenharmony_ci			else
1778c2ecf20Sopenharmony_ci				sram   |= 0x0c00;
1788c2ecf20Sopenharmony_ci			break;
1798c2ecf20Sopenharmony_ci		case OUTMODE_MPEG2_FIFO:            // e.g. USB feeding
1808c2ecf20Sopenharmony_ci			smo_mode |= (3 << 1);
1818c2ecf20Sopenharmony_ci			fifo_threshold = 512;
1828c2ecf20Sopenharmony_ci			outreg = (1 << 10) | (5 << 6);
1838c2ecf20Sopenharmony_ci			break;
1848c2ecf20Sopenharmony_ci		case OUTMODE_HIGH_Z:  // disable
1858c2ecf20Sopenharmony_ci			outreg = 0;
1868c2ecf20Sopenharmony_ci			break;
1878c2ecf20Sopenharmony_ci		default:
1888c2ecf20Sopenharmony_ci			dprintk("Unhandled output_mode passed to be set for demod %p\n", &state->demod);
1898c2ecf20Sopenharmony_ci			break;
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if (state->cfg.output_mpeg2_in_188_bytes)
1938c2ecf20Sopenharmony_ci		smo_mode |= (1 << 5) ;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state,  294 + state->reg_offs, smo_mode);
1968c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state,  295 + state->reg_offs, fifo_threshold); /* synchronous fread */
1978c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 1795, outreg);
1988c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 1805, sram);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (state->revision == 0x4003) {
2018c2ecf20Sopenharmony_ci		u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd;
2028c2ecf20Sopenharmony_ci		if (mode == OUTMODE_DIVERSITY)
2038c2ecf20Sopenharmony_ci			clk_cfg1 |= (1 << 1); // P_O_CLK_en
2048c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 909, clk_cfg1);
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci	return ret;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	/* by default everything is going to be powered off */
2128c2ecf20Sopenharmony_ci	u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906  = 0x3fff;
2138c2ecf20Sopenharmony_ci	u8  offset = 0;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	/* now, depending on the requested mode, we power on */
2168c2ecf20Sopenharmony_ci	switch (mode) {
2178c2ecf20Sopenharmony_ci		/* power up everything in the demod */
2188c2ecf20Sopenharmony_ci		case DIB7000M_POWER_ALL:
2198c2ecf20Sopenharmony_ci			reg_903 = 0x0000; reg_904 = 0x0000; reg_905 = 0x0000; reg_906 = 0x0000;
2208c2ecf20Sopenharmony_ci			break;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci		/* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */
2238c2ecf20Sopenharmony_ci		case DIB7000M_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */
2248c2ecf20Sopenharmony_ci			reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2));
2258c2ecf20Sopenharmony_ci			break;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		case DIB7000M_POWER_INTERF_ANALOG_AGC:
2288c2ecf20Sopenharmony_ci			reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10));
2298c2ecf20Sopenharmony_ci			reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2));
2308c2ecf20Sopenharmony_ci			reg_906 &= ~((1 << 0));
2318c2ecf20Sopenharmony_ci			break;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci		case DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD:
2348c2ecf20Sopenharmony_ci			reg_903 = 0x0000; reg_904 = 0x801f; reg_905 = 0x0000; reg_906 = 0x0000;
2358c2ecf20Sopenharmony_ci			break;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		case DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD:
2388c2ecf20Sopenharmony_ci			reg_903 = 0x0000; reg_904 = 0x8000; reg_905 = 0x010b; reg_906 = 0x0000;
2398c2ecf20Sopenharmony_ci			break;
2408c2ecf20Sopenharmony_ci		case DIB7000M_POWER_NO:
2418c2ecf20Sopenharmony_ci			break;
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	/* always power down unused parts */
2458c2ecf20Sopenharmony_ci	if (!state->cfg.mobile_mode)
2468c2ecf20Sopenharmony_ci		reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	/* P_sdio_select_clk = 0 on MC and after*/
2498c2ecf20Sopenharmony_ci	if (state->revision != 0x4000)
2508c2ecf20Sopenharmony_ci		reg_906 <<= 1;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	if (state->revision == 0x4003)
2538c2ecf20Sopenharmony_ci		offset = 1;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 903 + offset, reg_903);
2568c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 904 + offset, reg_904);
2578c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 905 + offset, reg_905);
2588c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 906 + offset, reg_906);
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	int ret = 0;
2648c2ecf20Sopenharmony_ci	u16 reg_913 = dib7000m_read_word(state, 913),
2658c2ecf20Sopenharmony_ci	       reg_914 = dib7000m_read_word(state, 914);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	switch (no) {
2688c2ecf20Sopenharmony_ci		case DIBX000_SLOW_ADC_ON:
2698c2ecf20Sopenharmony_ci			reg_914 |= (1 << 1) | (1 << 0);
2708c2ecf20Sopenharmony_ci			ret |= dib7000m_write_word(state, 914, reg_914);
2718c2ecf20Sopenharmony_ci			reg_914 &= ~(1 << 1);
2728c2ecf20Sopenharmony_ci			break;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci		case DIBX000_SLOW_ADC_OFF:
2758c2ecf20Sopenharmony_ci			reg_914 |=  (1 << 1) | (1 << 0);
2768c2ecf20Sopenharmony_ci			break;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci		case DIBX000_ADC_ON:
2798c2ecf20Sopenharmony_ci			if (state->revision == 0x4000) { // workaround for PA/MA
2808c2ecf20Sopenharmony_ci				// power-up ADC
2818c2ecf20Sopenharmony_ci				dib7000m_write_word(state, 913, 0);
2828c2ecf20Sopenharmony_ci				dib7000m_write_word(state, 914, reg_914 & 0x3);
2838c2ecf20Sopenharmony_ci				// power-down bandgag
2848c2ecf20Sopenharmony_ci				dib7000m_write_word(state, 913, (1 << 15));
2858c2ecf20Sopenharmony_ci				dib7000m_write_word(state, 914, reg_914 & 0x3);
2868c2ecf20Sopenharmony_ci			}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci			reg_913 &= 0x0fff;
2898c2ecf20Sopenharmony_ci			reg_914 &= 0x0003;
2908c2ecf20Sopenharmony_ci			break;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci		case DIBX000_ADC_OFF: // leave the VBG voltage on
2938c2ecf20Sopenharmony_ci			reg_913 |= (1 << 14) | (1 << 13) | (1 << 12);
2948c2ecf20Sopenharmony_ci			reg_914 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
2958c2ecf20Sopenharmony_ci			break;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		case DIBX000_VBG_ENABLE:
2988c2ecf20Sopenharmony_ci			reg_913 &= ~(1 << 15);
2998c2ecf20Sopenharmony_ci			break;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		case DIBX000_VBG_DISABLE:
3028c2ecf20Sopenharmony_ci			reg_913 |= (1 << 15);
3038c2ecf20Sopenharmony_ci			break;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci		default:
3068c2ecf20Sopenharmony_ci			break;
3078c2ecf20Sopenharmony_ci	}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci//	dprintk("913: %x, 914: %x\n", reg_913, reg_914);
3108c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 913, reg_913);
3118c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 914, reg_914);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	return ret;
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	u32 timf;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (!bw)
3218c2ecf20Sopenharmony_ci		bw = 8000;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	// store the current bandwidth for later use
3248c2ecf20Sopenharmony_ci	state->current_bandwidth = bw;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (state->timf == 0) {
3278c2ecf20Sopenharmony_ci		dprintk("using default timf\n");
3288c2ecf20Sopenharmony_ci		timf = state->timf_default;
3298c2ecf20Sopenharmony_ci	} else {
3308c2ecf20Sopenharmony_ci		dprintk("using updated timf\n");
3318c2ecf20Sopenharmony_ci		timf = state->timf;
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	timf = timf * (bw / 50) / 160;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
3378c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 24, (u16) ((timf      ) & 0xffff));
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	return 0;
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	struct dib7000m_state *state = demod->demodulator_priv;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	if (state->div_force_off) {
3478c2ecf20Sopenharmony_ci		dprintk("diversity combination deactivated - forced by COFDM parameters\n");
3488c2ecf20Sopenharmony_ci		onoff = 0;
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci	state->div_state = (u8)onoff;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	if (onoff) {
3538c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 263 + state->reg_offs, 6);
3548c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 264 + state->reg_offs, 6);
3558c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
3568c2ecf20Sopenharmony_ci	} else {
3578c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 263 + state->reg_offs, 1);
3588c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 264 + state->reg_offs, 0);
3598c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 266 + state->reg_offs, 0);
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	return 0;
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic int dib7000m_sad_calib(struct dib7000m_state *state)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci/* internal */
3698c2ecf20Sopenharmony_ci//	dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writing in set_bandwidth
3708c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 929, (0 << 1) | (0 << 0));
3718c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/* do the calibration */
3748c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 929, (1 << 0));
3758c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 929, (0 << 0));
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	msleep(1);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	return 0;
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
3858c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000)        & 0xffff));
3868c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 21, (u16) ( (bw->ifreq          >> 16) & 0xffff));
3878c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 22, (u16) (  bw->ifreq                 & 0xffff));
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 928, bw->sad_cfg);
3908c2ecf20Sopenharmony_ci}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_cistatic void dib7000m_reset_pll(struct dib7000m_state *state)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	const struct dibx000_bandwidth_config *bw = state->cfg.bw;
3958c2ecf20Sopenharmony_ci	u16 reg_907,reg_910;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	/* default */
3988c2ecf20Sopenharmony_ci	reg_907 = (bw->pll_bypass << 15) | (bw->modulo << 7) |
3998c2ecf20Sopenharmony_ci		(bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) |
4008c2ecf20Sopenharmony_ci		(bw->enable_refdiv << 1) | (0 << 0);
4018c2ecf20Sopenharmony_ci	reg_910 = (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	// for this oscillator frequency should be 30 MHz for the Master (default values in the board_parameters give that value)
4048c2ecf20Sopenharmony_ci	// this is only working only for 30 MHz crystals
4058c2ecf20Sopenharmony_ci	if (!state->cfg.quartz_direct) {
4068c2ecf20Sopenharmony_ci		reg_910 |= (1 << 5);  // forcing the predivider to 1
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci		// if the previous front-end is baseband, its output frequency is 15 MHz (prev freq divided by 2)
4098c2ecf20Sopenharmony_ci		if(state->cfg.input_clk_is_div_2)
4108c2ecf20Sopenharmony_ci			reg_907 |= (16 << 9);
4118c2ecf20Sopenharmony_ci		else // otherwise the previous front-end puts out its input (default 30MHz) - no extra division necessary
4128c2ecf20Sopenharmony_ci			reg_907 |= (8 << 9);
4138c2ecf20Sopenharmony_ci	} else {
4148c2ecf20Sopenharmony_ci		reg_907 |= (bw->pll_ratio & 0x3f) << 9;
4158c2ecf20Sopenharmony_ci		reg_910 |= (bw->pll_prediv << 5);
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 910, reg_910); // pll cfg
4198c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 907, reg_907); // clk cfg0
4208c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 908, 0x0006);  // clk_cfg1
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	dib7000m_reset_pll_common(state, bw);
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic void dib7000mc_reset_pll(struct dib7000m_state *state)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	const struct dibx000_bandwidth_config *bw = state->cfg.bw;
4288c2ecf20Sopenharmony_ci	u16 clk_cfg1;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	// clk_cfg0
4318c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0));
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	// clk_cfg1
4348c2ecf20Sopenharmony_ci	//dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) |
4358c2ecf20Sopenharmony_ci	clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) |
4368c2ecf20Sopenharmony_ci			(bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) |
4378c2ecf20Sopenharmony_ci			(1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0);
4388c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 908, clk_cfg1);
4398c2ecf20Sopenharmony_ci	clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3);
4408c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 908, clk_cfg1);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	// smpl_cfg
4438c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7));
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	dib7000m_reset_pll_common(state, bw);
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_cistatic int dib7000m_reset_gpio(struct dib7000m_state *st)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	/* reset the GPIOs */
4518c2ecf20Sopenharmony_ci	dib7000m_write_word(st, 773, st->cfg.gpio_dir);
4528c2ecf20Sopenharmony_ci	dib7000m_write_word(st, 774, st->cfg.gpio_val);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	/* TODO 782 is P_gpio_od */
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	dib7000m_write_word(st, 775, st->cfg.gpio_pwm_pos);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	dib7000m_write_word(st, 780, st->cfg.pwm_freq_div);
4598c2ecf20Sopenharmony_ci	return 0;
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic u16 dib7000m_defaults_common[] =
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	// auto search configuration
4668c2ecf20Sopenharmony_ci	3, 2,
4678c2ecf20Sopenharmony_ci		0x0004,
4688c2ecf20Sopenharmony_ci		0x1000,
4698c2ecf20Sopenharmony_ci		0x0814,
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	12, 6,
4728c2ecf20Sopenharmony_ci		0x001b,
4738c2ecf20Sopenharmony_ci		0x7740,
4748c2ecf20Sopenharmony_ci		0x005b,
4758c2ecf20Sopenharmony_ci		0x8d80,
4768c2ecf20Sopenharmony_ci		0x01c9,
4778c2ecf20Sopenharmony_ci		0xc380,
4788c2ecf20Sopenharmony_ci		0x0000,
4798c2ecf20Sopenharmony_ci		0x0080,
4808c2ecf20Sopenharmony_ci		0x0000,
4818c2ecf20Sopenharmony_ci		0x0090,
4828c2ecf20Sopenharmony_ci		0x0001,
4838c2ecf20Sopenharmony_ci		0xd4c0,
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	1, 26,
4868c2ecf20Sopenharmony_ci		0x6680, // P_corm_thres Lock algorithms configuration
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	1, 170,
4898c2ecf20Sopenharmony_ci		0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	8, 173,
4928c2ecf20Sopenharmony_ci		0,
4938c2ecf20Sopenharmony_ci		0,
4948c2ecf20Sopenharmony_ci		0,
4958c2ecf20Sopenharmony_ci		0,
4968c2ecf20Sopenharmony_ci		0,
4978c2ecf20Sopenharmony_ci		0,
4988c2ecf20Sopenharmony_ci		0,
4998c2ecf20Sopenharmony_ci		0,
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	1, 182,
5028c2ecf20Sopenharmony_ci		8192, // P_fft_nb_to_cut
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	2, 195,
5058c2ecf20Sopenharmony_ci		0x0ccd, // P_pha3_thres
5068c2ecf20Sopenharmony_ci		0,      // P_cti_use_cpe, P_cti_use_prog
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	1, 205,
5098c2ecf20Sopenharmony_ci		0x200f, // P_cspu_regul, P_cspu_win_cut
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	5, 214,
5128c2ecf20Sopenharmony_ci		0x023d, // P_adp_regul_cnt
5138c2ecf20Sopenharmony_ci		0x00a4, // P_adp_noise_cnt
5148c2ecf20Sopenharmony_ci		0x00a4, // P_adp_regul_ext
5158c2ecf20Sopenharmony_ci		0x7ff0, // P_adp_noise_ext
5168c2ecf20Sopenharmony_ci		0x3ccc, // P_adp_fil
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	1, 226,
5198c2ecf20Sopenharmony_ci		0, // P_2d_byp_ti_num
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	1, 255,
5228c2ecf20Sopenharmony_ci		0x800, // P_equal_thres_wgn
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	1, 263,
5258c2ecf20Sopenharmony_ci		0x0001,
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	1, 281,
5288c2ecf20Sopenharmony_ci		0x0010, // P_fec_*
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	1, 294,
5318c2ecf20Sopenharmony_ci		0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	0
5348c2ecf20Sopenharmony_ci};
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_cistatic u16 dib7000m_defaults[] =
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci{
5398c2ecf20Sopenharmony_ci	/* set ADC level to -16 */
5408c2ecf20Sopenharmony_ci	11, 76,
5418c2ecf20Sopenharmony_ci		(1 << 13) - 825 - 117,
5428c2ecf20Sopenharmony_ci		(1 << 13) - 837 - 117,
5438c2ecf20Sopenharmony_ci		(1 << 13) - 811 - 117,
5448c2ecf20Sopenharmony_ci		(1 << 13) - 766 - 117,
5458c2ecf20Sopenharmony_ci		(1 << 13) - 737 - 117,
5468c2ecf20Sopenharmony_ci		(1 << 13) - 693 - 117,
5478c2ecf20Sopenharmony_ci		(1 << 13) - 648 - 117,
5488c2ecf20Sopenharmony_ci		(1 << 13) - 619 - 117,
5498c2ecf20Sopenharmony_ci		(1 << 13) - 575 - 117,
5508c2ecf20Sopenharmony_ci		(1 << 13) - 531 - 117,
5518c2ecf20Sopenharmony_ci		(1 << 13) - 501 - 117,
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	// Tuner IO bank: max drive (14mA)
5548c2ecf20Sopenharmony_ci	1, 912,
5558c2ecf20Sopenharmony_ci		0x2c8a,
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	1, 1817,
5588c2ecf20Sopenharmony_ci		1,
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	0,
5618c2ecf20Sopenharmony_ci};
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_cistatic int dib7000m_demod_reset(struct dib7000m_state *state)
5648c2ecf20Sopenharmony_ci{
5658c2ecf20Sopenharmony_ci	dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
5688c2ecf20Sopenharmony_ci	dib7000m_set_adc_state(state, DIBX000_VBG_ENABLE);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	/* restart all parts */
5718c2ecf20Sopenharmony_ci	dib7000m_write_word(state,  898, 0xffff);
5728c2ecf20Sopenharmony_ci	dib7000m_write_word(state,  899, 0xffff);
5738c2ecf20Sopenharmony_ci	dib7000m_write_word(state,  900, 0xff0f);
5748c2ecf20Sopenharmony_ci	dib7000m_write_word(state,  901, 0xfffc);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	dib7000m_write_word(state,  898, 0);
5778c2ecf20Sopenharmony_ci	dib7000m_write_word(state,  899, 0);
5788c2ecf20Sopenharmony_ci	dib7000m_write_word(state,  900, 0);
5798c2ecf20Sopenharmony_ci	dib7000m_write_word(state,  901, 0);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	if (state->revision == 0x4000)
5828c2ecf20Sopenharmony_ci		dib7000m_reset_pll(state);
5838c2ecf20Sopenharmony_ci	else
5848c2ecf20Sopenharmony_ci		dib7000mc_reset_pll(state);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	if (dib7000m_reset_gpio(state) != 0)
5878c2ecf20Sopenharmony_ci		dprintk("GPIO reset was not successful.\n");
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
5908c2ecf20Sopenharmony_ci		dprintk("OUTPUT_MODE could not be reset.\n");
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	/* unforce divstr regardless whether i2c enumeration was done or not */
5938c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) );
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	dib7000m_set_bandwidth(state, 8000);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON);
5988c2ecf20Sopenharmony_ci	dib7000m_sad_calib(state);
5998c2ecf20Sopenharmony_ci	dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	if (state->cfg.dvbt_mode)
6028c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 1796, 0x0); // select DVB-T output
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	if (state->cfg.mobile_mode)
6058c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 261 + state->reg_offs, 2);
6068c2ecf20Sopenharmony_ci	else
6078c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 224 + state->reg_offs, 1);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
6108c2ecf20Sopenharmony_ci	if(state->cfg.tuner_is_baseband)
6118c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 36, 0x0755);
6128c2ecf20Sopenharmony_ci	else
6138c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 36, 0x1f55);
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	// P_divclksel=3 P_divbitsel=1
6168c2ecf20Sopenharmony_ci	if (state->revision == 0x4000)
6178c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));
6188c2ecf20Sopenharmony_ci	else
6198c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 909, (3 << 4) | 1);
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	dib7000m_write_tab(state, dib7000m_defaults_common);
6228c2ecf20Sopenharmony_ci	dib7000m_write_tab(state, dib7000m_defaults);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	state->internal_clk = state->cfg.bw->internal;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	return 0;
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_cistatic void dib7000m_restart_agc(struct dib7000m_state *state)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	// P_restart_iqc & P_restart_agc
6348c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 898, 0x0c00);
6358c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 898, 0x0000);
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_cistatic int dib7000m_agc_soft_split(struct dib7000m_state *state)
6398c2ecf20Sopenharmony_ci{
6408c2ecf20Sopenharmony_ci	u16 agc,split_offset;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	if(!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
6438c2ecf20Sopenharmony_ci		return 0;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	// n_agc_global
6468c2ecf20Sopenharmony_ci	agc = dib7000m_read_word(state, 390);
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	if (agc > state->current_agc->split.min_thres)
6498c2ecf20Sopenharmony_ci		split_offset = state->current_agc->split.min;
6508c2ecf20Sopenharmony_ci	else if (agc < state->current_agc->split.max_thres)
6518c2ecf20Sopenharmony_ci		split_offset = state->current_agc->split.max;
6528c2ecf20Sopenharmony_ci	else
6538c2ecf20Sopenharmony_ci		split_offset = state->current_agc->split.max *
6548c2ecf20Sopenharmony_ci			(agc - state->current_agc->split.min_thres) /
6558c2ecf20Sopenharmony_ci			(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	dprintk("AGC split_offset: %d\n", split_offset);
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	// P_agc_force_split and P_agc_split_offset
6608c2ecf20Sopenharmony_ci	return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset);
6618c2ecf20Sopenharmony_ci}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_cistatic int dib7000m_update_lna(struct dib7000m_state *state)
6648c2ecf20Sopenharmony_ci{
6658c2ecf20Sopenharmony_ci	u16 dyn_gain;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	if (state->cfg.update_lna) {
6688c2ecf20Sopenharmony_ci		// read dyn_gain here (because it is demod-dependent and not fe)
6698c2ecf20Sopenharmony_ci		dyn_gain = dib7000m_read_word(state, 390);
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci		if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
6728c2ecf20Sopenharmony_ci			dib7000m_restart_agc(state);
6738c2ecf20Sopenharmony_ci			return 1;
6748c2ecf20Sopenharmony_ci		}
6758c2ecf20Sopenharmony_ci	}
6768c2ecf20Sopenharmony_ci	return 0;
6778c2ecf20Sopenharmony_ci}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_cistatic int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	struct dibx000_agc_config *agc = NULL;
6828c2ecf20Sopenharmony_ci	int i;
6838c2ecf20Sopenharmony_ci	if (state->current_band == band && state->current_agc != NULL)
6848c2ecf20Sopenharmony_ci		return 0;
6858c2ecf20Sopenharmony_ci	state->current_band = band;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	for (i = 0; i < state->cfg.agc_config_count; i++)
6888c2ecf20Sopenharmony_ci		if (state->cfg.agc[i].band_caps & band) {
6898c2ecf20Sopenharmony_ci			agc = &state->cfg.agc[i];
6908c2ecf20Sopenharmony_ci			break;
6918c2ecf20Sopenharmony_ci		}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	if (agc == NULL) {
6948c2ecf20Sopenharmony_ci		dprintk("no valid AGC configuration found for band 0x%02x\n", band);
6958c2ecf20Sopenharmony_ci		return -EINVAL;
6968c2ecf20Sopenharmony_ci	}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	state->current_agc = agc;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	/* AGC */
7018c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 72 ,  agc->setup);
7028c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 73 ,  agc->inv_gain);
7038c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 74 ,  agc->time_stabiliz);
7048c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 97 , (agc->alpha_level << 12) | agc->thlock);
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	// Demod AGC loop configuration
7078c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp);
7088c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 99, (agc->beta_mant  << 6) | agc->beta_exp);
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
7118c2ecf20Sopenharmony_ci		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	/* AGC continued */
7148c2ecf20Sopenharmony_ci	if (state->wbd_ref != 0)
7158c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 102, state->wbd_ref);
7168c2ecf20Sopenharmony_ci	else // use default
7178c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 102, agc->wbd_ref);
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 103, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) );
7208c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 104,  agc->agc1_max);
7218c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 105,  agc->agc1_min);
7228c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 106,  agc->agc2_max);
7238c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 107,  agc->agc2_min);
7248c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 108, (agc->agc1_pt1 << 8) | agc->agc1_pt2 );
7258c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 109, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
7268c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 110, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
7278c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 111, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	if (state->revision > 0x4000) { // settings for the MC
7308c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 71,   agc->agc1_pt3);
7318c2ecf20Sopenharmony_ci//		dprintk("929: %x %d %d\n",
7328c2ecf20Sopenharmony_ci//			(dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel);
7338c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
7348c2ecf20Sopenharmony_ci	} else {
7358c2ecf20Sopenharmony_ci		// wrong default values
7368c2ecf20Sopenharmony_ci		u16 b[9] = { 676, 696, 717, 737, 758, 778, 799, 819, 840 };
7378c2ecf20Sopenharmony_ci		for (i = 0; i < 9; i++)
7388c2ecf20Sopenharmony_ci			dib7000m_write_word(state, 88 + i, b[i]);
7398c2ecf20Sopenharmony_ci	}
7408c2ecf20Sopenharmony_ci	return 0;
7418c2ecf20Sopenharmony_ci}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_cistatic void dib7000m_update_timf(struct dib7000m_state *state)
7448c2ecf20Sopenharmony_ci{
7458c2ecf20Sopenharmony_ci	u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437);
7468c2ecf20Sopenharmony_ci	state->timf = timf * 160 / (state->current_bandwidth / 50);
7478c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 23, (u16) (timf >> 16));
7488c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 24, (u16) (timf & 0xffff));
7498c2ecf20Sopenharmony_ci	dprintk("updated timf_frequency: %d (default: %d)\n", state->timf, state->timf_default);
7508c2ecf20Sopenharmony_ci}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_cistatic int dib7000m_agc_startup(struct dvb_frontend *demod)
7538c2ecf20Sopenharmony_ci{
7548c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
7558c2ecf20Sopenharmony_ci	struct dib7000m_state *state = demod->demodulator_priv;
7568c2ecf20Sopenharmony_ci	u16 cfg_72 = dib7000m_read_word(state, 72);
7578c2ecf20Sopenharmony_ci	int ret = -1;
7588c2ecf20Sopenharmony_ci	u8 *agc_state = &state->agc_state;
7598c2ecf20Sopenharmony_ci	u8 agc_split;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	switch (state->agc_state) {
7628c2ecf20Sopenharmony_ci		case 0:
7638c2ecf20Sopenharmony_ci			// set power-up level: interf+analog+AGC
7648c2ecf20Sopenharmony_ci			dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);
7658c2ecf20Sopenharmony_ci			dib7000m_set_adc_state(state, DIBX000_ADC_ON);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci			if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
7688c2ecf20Sopenharmony_ci				return -1;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci			ret = 7; /* ADC power up */
7718c2ecf20Sopenharmony_ci			(*agc_state)++;
7728c2ecf20Sopenharmony_ci			break;
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci		case 1:
7758c2ecf20Sopenharmony_ci			/* AGC initialization */
7768c2ecf20Sopenharmony_ci			if (state->cfg.agc_control)
7778c2ecf20Sopenharmony_ci				state->cfg.agc_control(&state->demod, 1);
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci			dib7000m_write_word(state, 75, 32768);
7808c2ecf20Sopenharmony_ci			if (!state->current_agc->perform_agc_softsplit) {
7818c2ecf20Sopenharmony_ci				/* we are using the wbd - so slow AGC startup */
7828c2ecf20Sopenharmony_ci				dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */
7838c2ecf20Sopenharmony_ci				(*agc_state)++;
7848c2ecf20Sopenharmony_ci				ret = 5;
7858c2ecf20Sopenharmony_ci			} else {
7868c2ecf20Sopenharmony_ci				/* default AGC startup */
7878c2ecf20Sopenharmony_ci				(*agc_state) = 4;
7888c2ecf20Sopenharmony_ci				/* wait AGC rough lock time */
7898c2ecf20Sopenharmony_ci				ret = 7;
7908c2ecf20Sopenharmony_ci			}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci			dib7000m_restart_agc(state);
7938c2ecf20Sopenharmony_ci			break;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci		case 2: /* fast split search path after 5sec */
7968c2ecf20Sopenharmony_ci			dib7000m_write_word(state,  72, cfg_72 | (1 << 4)); /* freeze AGC loop */
7978c2ecf20Sopenharmony_ci			dib7000m_write_word(state, 103, 2 << 9);            /* fast split search 0.25kHz */
7988c2ecf20Sopenharmony_ci			(*agc_state)++;
7998c2ecf20Sopenharmony_ci			ret = 14;
8008c2ecf20Sopenharmony_ci			break;
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	case 3: /* split search ended */
8038c2ecf20Sopenharmony_ci			agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */
8048c2ecf20Sopenharmony_ci			dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci			dib7000m_write_word(state, 72,  cfg_72 & ~(1 << 4));   /* std AGC loop */
8078c2ecf20Sopenharmony_ci			dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci			dib7000m_restart_agc(state);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci			dprintk("SPLIT %p: %u\n", demod, agc_split);
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci			(*agc_state)++;
8148c2ecf20Sopenharmony_ci			ret = 5;
8158c2ecf20Sopenharmony_ci			break;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci		case 4: /* LNA startup */
8188c2ecf20Sopenharmony_ci			/* wait AGC accurate lock time */
8198c2ecf20Sopenharmony_ci			ret = 7;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci			if (dib7000m_update_lna(state))
8228c2ecf20Sopenharmony_ci				// wait only AGC rough lock time
8238c2ecf20Sopenharmony_ci				ret = 5;
8248c2ecf20Sopenharmony_ci			else
8258c2ecf20Sopenharmony_ci				(*agc_state)++;
8268c2ecf20Sopenharmony_ci			break;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci		case 5:
8298c2ecf20Sopenharmony_ci			dib7000m_agc_soft_split(state);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci			if (state->cfg.agc_control)
8328c2ecf20Sopenharmony_ci				state->cfg.agc_control(&state->demod, 0);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci			(*agc_state)++;
8358c2ecf20Sopenharmony_ci			break;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci		default:
8388c2ecf20Sopenharmony_ci			break;
8398c2ecf20Sopenharmony_ci	}
8408c2ecf20Sopenharmony_ci	return ret;
8418c2ecf20Sopenharmony_ci}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_cistatic void dib7000m_set_channel(struct dib7000m_state *state, struct dtv_frontend_properties *ch,
8448c2ecf20Sopenharmony_ci				 u8 seq)
8458c2ecf20Sopenharmony_ci{
8468c2ecf20Sopenharmony_ci	u16 value, est[4];
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	/* nfft, guard, qam, alpha */
8518c2ecf20Sopenharmony_ci	value = 0;
8528c2ecf20Sopenharmony_ci	switch (ch->transmission_mode) {
8538c2ecf20Sopenharmony_ci		case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
8548c2ecf20Sopenharmony_ci		case TRANSMISSION_MODE_4K: value |= (2 << 7); break;
8558c2ecf20Sopenharmony_ci		default:
8568c2ecf20Sopenharmony_ci		case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
8578c2ecf20Sopenharmony_ci	}
8588c2ecf20Sopenharmony_ci	switch (ch->guard_interval) {
8598c2ecf20Sopenharmony_ci		case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
8608c2ecf20Sopenharmony_ci		case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
8618c2ecf20Sopenharmony_ci		case GUARD_INTERVAL_1_4:  value |= (3 << 5); break;
8628c2ecf20Sopenharmony_ci		default:
8638c2ecf20Sopenharmony_ci		case GUARD_INTERVAL_1_8:  value |= (2 << 5); break;
8648c2ecf20Sopenharmony_ci	}
8658c2ecf20Sopenharmony_ci	switch (ch->modulation) {
8668c2ecf20Sopenharmony_ci		case QPSK:  value |= (0 << 3); break;
8678c2ecf20Sopenharmony_ci		case QAM_16: value |= (1 << 3); break;
8688c2ecf20Sopenharmony_ci		default:
8698c2ecf20Sopenharmony_ci		case QAM_64: value |= (2 << 3); break;
8708c2ecf20Sopenharmony_ci	}
8718c2ecf20Sopenharmony_ci	switch (HIERARCHY_1) {
8728c2ecf20Sopenharmony_ci		case HIERARCHY_2: value |= 2; break;
8738c2ecf20Sopenharmony_ci		case HIERARCHY_4: value |= 4; break;
8748c2ecf20Sopenharmony_ci		default:
8758c2ecf20Sopenharmony_ci		case HIERARCHY_1: value |= 1; break;
8768c2ecf20Sopenharmony_ci	}
8778c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 0, value);
8788c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 5, (seq << 4));
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	/* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
8818c2ecf20Sopenharmony_ci	value = 0;
8828c2ecf20Sopenharmony_ci	if (1 != 0)
8838c2ecf20Sopenharmony_ci		value |= (1 << 6);
8848c2ecf20Sopenharmony_ci	if (ch->hierarchy == 1)
8858c2ecf20Sopenharmony_ci		value |= (1 << 4);
8868c2ecf20Sopenharmony_ci	if (1 == 1)
8878c2ecf20Sopenharmony_ci		value |= 1;
8888c2ecf20Sopenharmony_ci	switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
8898c2ecf20Sopenharmony_ci		case FEC_2_3: value |= (2 << 1); break;
8908c2ecf20Sopenharmony_ci		case FEC_3_4: value |= (3 << 1); break;
8918c2ecf20Sopenharmony_ci		case FEC_5_6: value |= (5 << 1); break;
8928c2ecf20Sopenharmony_ci		case FEC_7_8: value |= (7 << 1); break;
8938c2ecf20Sopenharmony_ci		default:
8948c2ecf20Sopenharmony_ci		case FEC_1_2: value |= (1 << 1); break;
8958c2ecf20Sopenharmony_ci	}
8968c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 267 + state->reg_offs, value);
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	/* offset loop parameters */
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	/* P_timf_alpha = 6, P_corm_alpha=6, P_corm_thres=0x80 */
9018c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 26, (6 << 12) | (6 << 8) | 0x80);
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=1, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
9048c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (1 << 9) | (3 << 5) | (1 << 4) | (0x3));
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max=3 */
9078c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 32, (0 << 4) | 0x3);
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step=5 */
9108c2ecf20Sopenharmony_ci	dib7000m_write_word(state, 33, (0 << 4) | 0x5);
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	/* P_dvsy_sync_wait */
9138c2ecf20Sopenharmony_ci	switch (ch->transmission_mode) {
9148c2ecf20Sopenharmony_ci		case TRANSMISSION_MODE_8K: value = 256; break;
9158c2ecf20Sopenharmony_ci		case TRANSMISSION_MODE_4K: value = 128; break;
9168c2ecf20Sopenharmony_ci		case TRANSMISSION_MODE_2K:
9178c2ecf20Sopenharmony_ci		default: value = 64; break;
9188c2ecf20Sopenharmony_ci	}
9198c2ecf20Sopenharmony_ci	switch (ch->guard_interval) {
9208c2ecf20Sopenharmony_ci		case GUARD_INTERVAL_1_16: value *= 2; break;
9218c2ecf20Sopenharmony_ci		case GUARD_INTERVAL_1_8:  value *= 4; break;
9228c2ecf20Sopenharmony_ci		case GUARD_INTERVAL_1_4:  value *= 8; break;
9238c2ecf20Sopenharmony_ci		default:
9248c2ecf20Sopenharmony_ci		case GUARD_INTERVAL_1_32: value *= 1; break;
9258c2ecf20Sopenharmony_ci	}
9268c2ecf20Sopenharmony_ci	state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	/* deactivate the possibility of diversity reception if extended interleave - not for 7000MC */
9298c2ecf20Sopenharmony_ci	/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
9308c2ecf20Sopenharmony_ci	if (1 == 1 || state->revision > 0x4000)
9318c2ecf20Sopenharmony_ci		state->div_force_off = 0;
9328c2ecf20Sopenharmony_ci	else
9338c2ecf20Sopenharmony_ci		state->div_force_off = 1;
9348c2ecf20Sopenharmony_ci	dib7000m_set_diversity_in(&state->demod, state->div_state);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	/* channel estimation fine configuration */
9378c2ecf20Sopenharmony_ci	switch (ch->modulation) {
9388c2ecf20Sopenharmony_ci		case QAM_64:
9398c2ecf20Sopenharmony_ci			est[0] = 0x0148;       /* P_adp_regul_cnt 0.04 */
9408c2ecf20Sopenharmony_ci			est[1] = 0xfff0;       /* P_adp_noise_cnt -0.002 */
9418c2ecf20Sopenharmony_ci			est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
9428c2ecf20Sopenharmony_ci			est[3] = 0xfff8;       /* P_adp_noise_ext -0.001 */
9438c2ecf20Sopenharmony_ci			break;
9448c2ecf20Sopenharmony_ci		case QAM_16:
9458c2ecf20Sopenharmony_ci			est[0] = 0x023d;       /* P_adp_regul_cnt 0.07 */
9468c2ecf20Sopenharmony_ci			est[1] = 0xffdf;       /* P_adp_noise_cnt -0.004 */
9478c2ecf20Sopenharmony_ci			est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
9488c2ecf20Sopenharmony_ci			est[3] = 0xfff0;       /* P_adp_noise_ext -0.002 */
9498c2ecf20Sopenharmony_ci			break;
9508c2ecf20Sopenharmony_ci		default:
9518c2ecf20Sopenharmony_ci			est[0] = 0x099a;       /* P_adp_regul_cnt 0.3 */
9528c2ecf20Sopenharmony_ci			est[1] = 0xffae;       /* P_adp_noise_cnt -0.01 */
9538c2ecf20Sopenharmony_ci			est[2] = 0x0333;       /* P_adp_regul_ext 0.1 */
9548c2ecf20Sopenharmony_ci			est[3] = 0xfff8;       /* P_adp_noise_ext -0.002 */
9558c2ecf20Sopenharmony_ci			break;
9568c2ecf20Sopenharmony_ci	}
9578c2ecf20Sopenharmony_ci	for (value = 0; value < 4; value++)
9588c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]);
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	// set power-up level: autosearch
9618c2ecf20Sopenharmony_ci	dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD);
9628c2ecf20Sopenharmony_ci}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_cistatic int dib7000m_autosearch_start(struct dvb_frontend *demod)
9658c2ecf20Sopenharmony_ci{
9668c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
9678c2ecf20Sopenharmony_ci	struct dib7000m_state *state = demod->demodulator_priv;
9688c2ecf20Sopenharmony_ci	struct dtv_frontend_properties schan;
9698c2ecf20Sopenharmony_ci	int ret = 0;
9708c2ecf20Sopenharmony_ci	u32 value, factor;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	schan = *ch;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	schan.modulation = QAM_64;
9758c2ecf20Sopenharmony_ci	schan.guard_interval        = GUARD_INTERVAL_1_32;
9768c2ecf20Sopenharmony_ci	schan.transmission_mode         = TRANSMISSION_MODE_8K;
9778c2ecf20Sopenharmony_ci	schan.code_rate_HP = FEC_2_3;
9788c2ecf20Sopenharmony_ci	schan.code_rate_LP = FEC_3_4;
9798c2ecf20Sopenharmony_ci	schan.hierarchy    = 0;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	dib7000m_set_channel(state, &schan, 7);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	factor = BANDWIDTH_TO_KHZ(schan.bandwidth_hz);
9848c2ecf20Sopenharmony_ci	if (factor >= 5000)
9858c2ecf20Sopenharmony_ci		factor = 1;
9868c2ecf20Sopenharmony_ci	else
9878c2ecf20Sopenharmony_ci		factor = 6;
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	// always use the setting for 8MHz here lock_time for 7,6 MHz are longer
9908c2ecf20Sopenharmony_ci	value = 30 * state->internal_clk * factor;
9918c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 6,  (u16) ((value >> 16) & 0xffff)); // lock0 wait time
9928c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 7,  (u16)  (value        & 0xffff)); // lock0 wait time
9938c2ecf20Sopenharmony_ci	value = 100 * state->internal_clk * factor;
9948c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 8,  (u16) ((value >> 16) & 0xffff)); // lock1 wait time
9958c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 9,  (u16)  (value        & 0xffff)); // lock1 wait time
9968c2ecf20Sopenharmony_ci	value = 500 * state->internal_clk * factor;
9978c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
9988c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 11, (u16)  (value        & 0xffff)); // lock2 wait time
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	// start search
10018c2ecf20Sopenharmony_ci	value = dib7000m_read_word(state, 0);
10028c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9)));
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	/* clear n_irq_pending */
10058c2ecf20Sopenharmony_ci	if (state->revision == 0x4000)
10068c2ecf20Sopenharmony_ci		dib7000m_write_word(state, 1793, 0);
10078c2ecf20Sopenharmony_ci	else
10088c2ecf20Sopenharmony_ci		dib7000m_read_word(state, 537);
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 0, (u16) value);
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	return ret;
10138c2ecf20Sopenharmony_ci}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_cistatic int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg)
10168c2ecf20Sopenharmony_ci{
10178c2ecf20Sopenharmony_ci	u16 irq_pending = dib7000m_read_word(state, reg);
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	if (irq_pending & 0x1) { // failed
10208c2ecf20Sopenharmony_ci		dprintk("autosearch failed\n");
10218c2ecf20Sopenharmony_ci		return 1;
10228c2ecf20Sopenharmony_ci	}
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	if (irq_pending & 0x2) { // succeeded
10258c2ecf20Sopenharmony_ci		dprintk("autosearch succeeded\n");
10268c2ecf20Sopenharmony_ci		return 2;
10278c2ecf20Sopenharmony_ci	}
10288c2ecf20Sopenharmony_ci	return 0; // still pending
10298c2ecf20Sopenharmony_ci}
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_cistatic int dib7000m_autosearch_is_irq(struct dvb_frontend *demod)
10328c2ecf20Sopenharmony_ci{
10338c2ecf20Sopenharmony_ci	struct dib7000m_state *state = demod->demodulator_priv;
10348c2ecf20Sopenharmony_ci	if (state->revision == 0x4000)
10358c2ecf20Sopenharmony_ci		return dib7000m_autosearch_irq(state, 1793);
10368c2ecf20Sopenharmony_ci	else
10378c2ecf20Sopenharmony_ci		return dib7000m_autosearch_irq(state, 537);
10388c2ecf20Sopenharmony_ci}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_cistatic int dib7000m_tune(struct dvb_frontend *demod)
10418c2ecf20Sopenharmony_ci{
10428c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
10438c2ecf20Sopenharmony_ci	struct dib7000m_state *state = demod->demodulator_priv;
10448c2ecf20Sopenharmony_ci	int ret = 0;
10458c2ecf20Sopenharmony_ci	u16 value;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	// we are already tuned - just resuming from suspend
10488c2ecf20Sopenharmony_ci	dib7000m_set_channel(state, ch, 0);
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	// restart demod
10518c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 898, 0x4000);
10528c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 898, 0x0000);
10538c2ecf20Sopenharmony_ci	msleep(45);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD);
10568c2ecf20Sopenharmony_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 */
10578c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	// never achieved a lock before - wait for timfreq to update
10608c2ecf20Sopenharmony_ci	if (state->timf == 0)
10618c2ecf20Sopenharmony_ci		msleep(200);
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	//dump_reg(state);
10648c2ecf20Sopenharmony_ci	/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
10658c2ecf20Sopenharmony_ci	value = (6 << 8) | 0x80;
10668c2ecf20Sopenharmony_ci	switch (ch->transmission_mode) {
10678c2ecf20Sopenharmony_ci		case TRANSMISSION_MODE_2K: value |= (7 << 12); break;
10688c2ecf20Sopenharmony_ci		case TRANSMISSION_MODE_4K: value |= (8 << 12); break;
10698c2ecf20Sopenharmony_ci		default:
10708c2ecf20Sopenharmony_ci		case TRANSMISSION_MODE_8K: value |= (9 << 12); break;
10718c2ecf20Sopenharmony_ci	}
10728c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 26, value);
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
10758c2ecf20Sopenharmony_ci	value = (0 << 4);
10768c2ecf20Sopenharmony_ci	switch (ch->transmission_mode) {
10778c2ecf20Sopenharmony_ci		case TRANSMISSION_MODE_2K: value |= 0x6; break;
10788c2ecf20Sopenharmony_ci		case TRANSMISSION_MODE_4K: value |= 0x7; break;
10798c2ecf20Sopenharmony_ci		default:
10808c2ecf20Sopenharmony_ci		case TRANSMISSION_MODE_8K: value |= 0x8; break;
10818c2ecf20Sopenharmony_ci	}
10828c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 32, value);
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
10858c2ecf20Sopenharmony_ci	value = (0 << 4);
10868c2ecf20Sopenharmony_ci	switch (ch->transmission_mode) {
10878c2ecf20Sopenharmony_ci		case TRANSMISSION_MODE_2K: value |= 0x6; break;
10888c2ecf20Sopenharmony_ci		case TRANSMISSION_MODE_4K: value |= 0x7; break;
10898c2ecf20Sopenharmony_ci		default:
10908c2ecf20Sopenharmony_ci		case TRANSMISSION_MODE_8K: value |= 0x8; break;
10918c2ecf20Sopenharmony_ci	}
10928c2ecf20Sopenharmony_ci	ret |= dib7000m_write_word(state, 33,  value);
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	// we achieved a lock - it's time to update the timf freq
10958c2ecf20Sopenharmony_ci	if ((dib7000m_read_word(state, 535) >> 6)  & 0x1)
10968c2ecf20Sopenharmony_ci		dib7000m_update_timf(state);
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
10998c2ecf20Sopenharmony_ci	return ret;
11008c2ecf20Sopenharmony_ci}
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_cistatic int dib7000m_wakeup(struct dvb_frontend *demod)
11038c2ecf20Sopenharmony_ci{
11048c2ecf20Sopenharmony_ci	struct dib7000m_state *state = demod->demodulator_priv;
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
11098c2ecf20Sopenharmony_ci		dprintk("could not start Slow ADC\n");
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	return 0;
11128c2ecf20Sopenharmony_ci}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_cistatic int dib7000m_sleep(struct dvb_frontend *demod)
11158c2ecf20Sopenharmony_ci{
11168c2ecf20Sopenharmony_ci	struct dib7000m_state *st = demod->demodulator_priv;
11178c2ecf20Sopenharmony_ci	dib7000m_set_output_mode(st, OUTMODE_HIGH_Z);
11188c2ecf20Sopenharmony_ci	dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY);
11198c2ecf20Sopenharmony_ci	return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) |
11208c2ecf20Sopenharmony_ci		dib7000m_set_adc_state(st, DIBX000_ADC_OFF);
11218c2ecf20Sopenharmony_ci}
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_cistatic int dib7000m_identify(struct dib7000m_state *state)
11248c2ecf20Sopenharmony_ci{
11258c2ecf20Sopenharmony_ci	u16 value;
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	if ((value = dib7000m_read_word(state, 896)) != 0x01b3) {
11288c2ecf20Sopenharmony_ci		dprintk("wrong Vendor ID (0x%x)\n", value);
11298c2ecf20Sopenharmony_ci		return -EREMOTEIO;
11308c2ecf20Sopenharmony_ci	}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	state->revision = dib7000m_read_word(state, 897);
11338c2ecf20Sopenharmony_ci	if (state->revision != 0x4000 &&
11348c2ecf20Sopenharmony_ci		state->revision != 0x4001 &&
11358c2ecf20Sopenharmony_ci		state->revision != 0x4002 &&
11368c2ecf20Sopenharmony_ci		state->revision != 0x4003) {
11378c2ecf20Sopenharmony_ci		dprintk("wrong Device ID (0x%x)\n", value);
11388c2ecf20Sopenharmony_ci		return -EREMOTEIO;
11398c2ecf20Sopenharmony_ci	}
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	/* protect this driver to be used with 7000PC */
11428c2ecf20Sopenharmony_ci	if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) {
11438c2ecf20Sopenharmony_ci		dprintk("this driver does not work with DiB7000PC\n");
11448c2ecf20Sopenharmony_ci		return -EREMOTEIO;
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	switch (state->revision) {
11488c2ecf20Sopenharmony_ci	case 0x4000: dprintk("found DiB7000MA/PA/MB/PB\n"); break;
11498c2ecf20Sopenharmony_ci	case 0x4001: state->reg_offs = 1; dprintk("found DiB7000HC\n"); break;
11508c2ecf20Sopenharmony_ci	case 0x4002: state->reg_offs = 1; dprintk("found DiB7000MC\n"); break;
11518c2ecf20Sopenharmony_ci	case 0x4003: state->reg_offs = 1; dprintk("found DiB9000\n"); break;
11528c2ecf20Sopenharmony_ci	}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	return 0;
11558c2ecf20Sopenharmony_ci}
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_cistatic int dib7000m_get_frontend(struct dvb_frontend* fe,
11598c2ecf20Sopenharmony_ci				 struct dtv_frontend_properties *fep)
11608c2ecf20Sopenharmony_ci{
11618c2ecf20Sopenharmony_ci	struct dib7000m_state *state = fe->demodulator_priv;
11628c2ecf20Sopenharmony_ci	u16 tps = dib7000m_read_word(state,480);
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	fep->inversion = INVERSION_AUTO;
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	switch ((tps >> 8) & 0x3) {
11698c2ecf20Sopenharmony_ci		case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break;
11708c2ecf20Sopenharmony_ci		case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break;
11718c2ecf20Sopenharmony_ci		/* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
11728c2ecf20Sopenharmony_ci	}
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	switch (tps & 0x3) {
11758c2ecf20Sopenharmony_ci		case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break;
11768c2ecf20Sopenharmony_ci		case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break;
11778c2ecf20Sopenharmony_ci		case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break;
11788c2ecf20Sopenharmony_ci		case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break;
11798c2ecf20Sopenharmony_ci	}
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	switch ((tps >> 14) & 0x3) {
11828c2ecf20Sopenharmony_ci		case 0: fep->modulation = QPSK; break;
11838c2ecf20Sopenharmony_ci		case 1: fep->modulation = QAM_16; break;
11848c2ecf20Sopenharmony_ci		case 2:
11858c2ecf20Sopenharmony_ci		default: fep->modulation = QAM_64; break;
11868c2ecf20Sopenharmony_ci	}
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
11898c2ecf20Sopenharmony_ci	/* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	fep->hierarchy = HIERARCHY_NONE;
11928c2ecf20Sopenharmony_ci	switch ((tps >> 5) & 0x7) {
11938c2ecf20Sopenharmony_ci		case 1: fep->code_rate_HP = FEC_1_2; break;
11948c2ecf20Sopenharmony_ci		case 2: fep->code_rate_HP = FEC_2_3; break;
11958c2ecf20Sopenharmony_ci		case 3: fep->code_rate_HP = FEC_3_4; break;
11968c2ecf20Sopenharmony_ci		case 5: fep->code_rate_HP = FEC_5_6; break;
11978c2ecf20Sopenharmony_ci		case 7:
11988c2ecf20Sopenharmony_ci		default: fep->code_rate_HP = FEC_7_8; break;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	}
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	switch ((tps >> 2) & 0x7) {
12038c2ecf20Sopenharmony_ci		case 1: fep->code_rate_LP = FEC_1_2; break;
12048c2ecf20Sopenharmony_ci		case 2: fep->code_rate_LP = FEC_2_3; break;
12058c2ecf20Sopenharmony_ci		case 3: fep->code_rate_LP = FEC_3_4; break;
12068c2ecf20Sopenharmony_ci		case 5: fep->code_rate_LP = FEC_5_6; break;
12078c2ecf20Sopenharmony_ci		case 7:
12088c2ecf20Sopenharmony_ci		default: fep->code_rate_LP = FEC_7_8; break;
12098c2ecf20Sopenharmony_ci	}
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	/* native interleaver: (dib7000m_read_word(state, 481) >>  5) & 0x1 */
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	return 0;
12148c2ecf20Sopenharmony_ci}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_cistatic int dib7000m_set_frontend(struct dvb_frontend *fe)
12178c2ecf20Sopenharmony_ci{
12188c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
12198c2ecf20Sopenharmony_ci	struct dib7000m_state *state = fe->demodulator_priv;
12208c2ecf20Sopenharmony_ci	int time, ret;
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	dib7000m_set_output_mode(state, OUTMODE_HIGH_Z);
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz));
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	if (fe->ops.tuner_ops.set_params)
12278c2ecf20Sopenharmony_ci		fe->ops.tuner_ops.set_params(fe);
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	/* start up the AGC */
12308c2ecf20Sopenharmony_ci	state->agc_state = 0;
12318c2ecf20Sopenharmony_ci	do {
12328c2ecf20Sopenharmony_ci		time = dib7000m_agc_startup(fe);
12338c2ecf20Sopenharmony_ci		if (time != -1)
12348c2ecf20Sopenharmony_ci			msleep(time);
12358c2ecf20Sopenharmony_ci	} while (time != -1);
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
12388c2ecf20Sopenharmony_ci		fep->guard_interval    == GUARD_INTERVAL_AUTO ||
12398c2ecf20Sopenharmony_ci		fep->modulation        == QAM_AUTO ||
12408c2ecf20Sopenharmony_ci		fep->code_rate_HP      == FEC_AUTO) {
12418c2ecf20Sopenharmony_ci		int i = 800, found;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci		dib7000m_autosearch_start(fe);
12448c2ecf20Sopenharmony_ci		do {
12458c2ecf20Sopenharmony_ci			msleep(1);
12468c2ecf20Sopenharmony_ci			found = dib7000m_autosearch_is_irq(fe);
12478c2ecf20Sopenharmony_ci		} while (found == 0 && i--);
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci		dprintk("autosearch returns: %d\n", found);
12508c2ecf20Sopenharmony_ci		if (found == 0 || found == 1)
12518c2ecf20Sopenharmony_ci			return 0; // no channel found
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci		dib7000m_get_frontend(fe, fep);
12548c2ecf20Sopenharmony_ci	}
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	ret = dib7000m_tune(fe);
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	/* make this a config parameter */
12598c2ecf20Sopenharmony_ci	dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
12608c2ecf20Sopenharmony_ci	return ret;
12618c2ecf20Sopenharmony_ci}
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_cistatic int dib7000m_read_status(struct dvb_frontend *fe, enum fe_status *stat)
12648c2ecf20Sopenharmony_ci{
12658c2ecf20Sopenharmony_ci	struct dib7000m_state *state = fe->demodulator_priv;
12668c2ecf20Sopenharmony_ci	u16 lock = dib7000m_read_word(state, 535);
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	*stat = 0;
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	if (lock & 0x8000)
12718c2ecf20Sopenharmony_ci		*stat |= FE_HAS_SIGNAL;
12728c2ecf20Sopenharmony_ci	if (lock & 0x3000)
12738c2ecf20Sopenharmony_ci		*stat |= FE_HAS_CARRIER;
12748c2ecf20Sopenharmony_ci	if (lock & 0x0100)
12758c2ecf20Sopenharmony_ci		*stat |= FE_HAS_VITERBI;
12768c2ecf20Sopenharmony_ci	if (lock & 0x0010)
12778c2ecf20Sopenharmony_ci		*stat |= FE_HAS_SYNC;
12788c2ecf20Sopenharmony_ci	if (lock & 0x0008)
12798c2ecf20Sopenharmony_ci		*stat |= FE_HAS_LOCK;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	return 0;
12828c2ecf20Sopenharmony_ci}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_cistatic int dib7000m_read_ber(struct dvb_frontend *fe, u32 *ber)
12858c2ecf20Sopenharmony_ci{
12868c2ecf20Sopenharmony_ci	struct dib7000m_state *state = fe->demodulator_priv;
12878c2ecf20Sopenharmony_ci	*ber = (dib7000m_read_word(state, 526) << 16) | dib7000m_read_word(state, 527);
12888c2ecf20Sopenharmony_ci	return 0;
12898c2ecf20Sopenharmony_ci}
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_cistatic int dib7000m_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
12928c2ecf20Sopenharmony_ci{
12938c2ecf20Sopenharmony_ci	struct dib7000m_state *state = fe->demodulator_priv;
12948c2ecf20Sopenharmony_ci	*unc = dib7000m_read_word(state, 534);
12958c2ecf20Sopenharmony_ci	return 0;
12968c2ecf20Sopenharmony_ci}
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_cistatic int dib7000m_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
12998c2ecf20Sopenharmony_ci{
13008c2ecf20Sopenharmony_ci	struct dib7000m_state *state = fe->demodulator_priv;
13018c2ecf20Sopenharmony_ci	u16 val = dib7000m_read_word(state, 390);
13028c2ecf20Sopenharmony_ci	*strength = 65535 - val;
13038c2ecf20Sopenharmony_ci	return 0;
13048c2ecf20Sopenharmony_ci}
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_cistatic int dib7000m_read_snr(struct dvb_frontend* fe, u16 *snr)
13078c2ecf20Sopenharmony_ci{
13088c2ecf20Sopenharmony_ci	*snr = 0x0000;
13098c2ecf20Sopenharmony_ci	return 0;
13108c2ecf20Sopenharmony_ci}
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_cistatic int dib7000m_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
13138c2ecf20Sopenharmony_ci{
13148c2ecf20Sopenharmony_ci	tune->min_delay_ms = 1000;
13158c2ecf20Sopenharmony_ci	return 0;
13168c2ecf20Sopenharmony_ci}
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_cistatic void dib7000m_release(struct dvb_frontend *demod)
13198c2ecf20Sopenharmony_ci{
13208c2ecf20Sopenharmony_ci	struct dib7000m_state *st = demod->demodulator_priv;
13218c2ecf20Sopenharmony_ci	dibx000_exit_i2c_master(&st->i2c_master);
13228c2ecf20Sopenharmony_ci	kfree(st);
13238c2ecf20Sopenharmony_ci}
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_cistruct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
13268c2ecf20Sopenharmony_ci{
13278c2ecf20Sopenharmony_ci	struct dib7000m_state *st = demod->demodulator_priv;
13288c2ecf20Sopenharmony_ci	return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
13298c2ecf20Sopenharmony_ci}
13308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib7000m_get_i2c_master);
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ciint dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
13338c2ecf20Sopenharmony_ci{
13348c2ecf20Sopenharmony_ci	struct dib7000m_state *state = fe->demodulator_priv;
13358c2ecf20Sopenharmony_ci	u16 val = dib7000m_read_word(state, 294 + state->reg_offs) & 0xffef;
13368c2ecf20Sopenharmony_ci	val |= (onoff & 0x1) << 4;
13378c2ecf20Sopenharmony_ci	dprintk("PID filter enabled %d\n", onoff);
13388c2ecf20Sopenharmony_ci	return dib7000m_write_word(state, 294 + state->reg_offs, val);
13398c2ecf20Sopenharmony_ci}
13408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib7000m_pid_filter_ctrl);
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ciint dib7000m_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
13438c2ecf20Sopenharmony_ci{
13448c2ecf20Sopenharmony_ci	struct dib7000m_state *state = fe->demodulator_priv;
13458c2ecf20Sopenharmony_ci	dprintk("PID filter: index %x, PID %d, OnOff %d\n", id, pid, onoff);
13468c2ecf20Sopenharmony_ci	return dib7000m_write_word(state, 300 + state->reg_offs + id,
13478c2ecf20Sopenharmony_ci			onoff ? (1 << 13) | pid : 0);
13488c2ecf20Sopenharmony_ci}
13498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib7000m_pid_filter);
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci#if 0
13528c2ecf20Sopenharmony_ci/* used with some prototype boards */
13538c2ecf20Sopenharmony_ciint dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods,
13548c2ecf20Sopenharmony_ci		u8 default_addr, struct dib7000m_config cfg[])
13558c2ecf20Sopenharmony_ci{
13568c2ecf20Sopenharmony_ci	struct dib7000m_state st = { .i2c_adap = i2c };
13578c2ecf20Sopenharmony_ci	int k = 0;
13588c2ecf20Sopenharmony_ci	u8 new_addr = 0;
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	for (k = no_of_demods-1; k >= 0; k--) {
13618c2ecf20Sopenharmony_ci		st.cfg = cfg[k];
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci		/* designated i2c address */
13648c2ecf20Sopenharmony_ci		new_addr          = (0x40 + k) << 1;
13658c2ecf20Sopenharmony_ci		st.i2c_addr = new_addr;
13668c2ecf20Sopenharmony_ci		if (dib7000m_identify(&st) != 0) {
13678c2ecf20Sopenharmony_ci			st.i2c_addr = default_addr;
13688c2ecf20Sopenharmony_ci			if (dib7000m_identify(&st) != 0) {
13698c2ecf20Sopenharmony_ci				dprintk("DiB7000M #%d: not identified\n", k);
13708c2ecf20Sopenharmony_ci				return -EIO;
13718c2ecf20Sopenharmony_ci			}
13728c2ecf20Sopenharmony_ci		}
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci		/* start diversity to pull_down div_str - just for i2c-enumeration */
13758c2ecf20Sopenharmony_ci		dib7000m_set_output_mode(&st, OUTMODE_DIVERSITY);
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci		dib7000m_write_word(&st, 1796, 0x0); // select DVB-T output
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci		/* set new i2c address and force divstart */
13808c2ecf20Sopenharmony_ci		dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2);
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci		dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
13838c2ecf20Sopenharmony_ci	}
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	for (k = 0; k < no_of_demods; k++) {
13868c2ecf20Sopenharmony_ci		st.cfg = cfg[k];
13878c2ecf20Sopenharmony_ci		st.i2c_addr = (0x40 + k) << 1;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci		// unforce divstr
13908c2ecf20Sopenharmony_ci		dib7000m_write_word(&st,1794, st.i2c_addr << 2);
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci		/* deactivate div - it was just for i2c-enumeration */
13938c2ecf20Sopenharmony_ci		dib7000m_set_output_mode(&st, OUTMODE_HIGH_Z);
13948c2ecf20Sopenharmony_ci	}
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci	return 0;
13978c2ecf20Sopenharmony_ci}
13988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib7000m_i2c_enumeration);
13998c2ecf20Sopenharmony_ci#endif
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dib7000m_ops;
14028c2ecf20Sopenharmony_cistruct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg)
14038c2ecf20Sopenharmony_ci{
14048c2ecf20Sopenharmony_ci	struct dvb_frontend *demod;
14058c2ecf20Sopenharmony_ci	struct dib7000m_state *st;
14068c2ecf20Sopenharmony_ci	st = kzalloc(sizeof(struct dib7000m_state), GFP_KERNEL);
14078c2ecf20Sopenharmony_ci	if (st == NULL)
14088c2ecf20Sopenharmony_ci		return NULL;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	memcpy(&st->cfg, cfg, sizeof(struct dib7000m_config));
14118c2ecf20Sopenharmony_ci	st->i2c_adap = i2c_adap;
14128c2ecf20Sopenharmony_ci	st->i2c_addr = i2c_addr;
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci	demod                   = &st->demod;
14158c2ecf20Sopenharmony_ci	demod->demodulator_priv = st;
14168c2ecf20Sopenharmony_ci	memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
14178c2ecf20Sopenharmony_ci	mutex_init(&st->i2c_buffer_lock);
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	st->timf_default = cfg->bw->timf;
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	if (dib7000m_identify(st) != 0)
14228c2ecf20Sopenharmony_ci		goto error;
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	if (st->revision == 0x4000)
14258c2ecf20Sopenharmony_ci		dibx000_init_i2c_master(&st->i2c_master, DIB7000, st->i2c_adap, st->i2c_addr);
14268c2ecf20Sopenharmony_ci	else
14278c2ecf20Sopenharmony_ci		dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c_adap, st->i2c_addr);
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	dib7000m_demod_reset(st);
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	return demod;
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_cierror:
14348c2ecf20Sopenharmony_ci	kfree(st);
14358c2ecf20Sopenharmony_ci	return NULL;
14368c2ecf20Sopenharmony_ci}
14378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dib7000m_attach);
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dib7000m_ops = {
14408c2ecf20Sopenharmony_ci	.delsys = { SYS_DVBT },
14418c2ecf20Sopenharmony_ci	.info = {
14428c2ecf20Sopenharmony_ci		.name = "DiBcom 7000MA/MB/PA/PB/MC",
14438c2ecf20Sopenharmony_ci		.frequency_min_hz      =  44250 * kHz,
14448c2ecf20Sopenharmony_ci		.frequency_max_hz      = 867250 * kHz,
14458c2ecf20Sopenharmony_ci		.frequency_stepsize_hz = 62500,
14468c2ecf20Sopenharmony_ci		.caps = FE_CAN_INVERSION_AUTO |
14478c2ecf20Sopenharmony_ci			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
14488c2ecf20Sopenharmony_ci			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
14498c2ecf20Sopenharmony_ci			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
14508c2ecf20Sopenharmony_ci			FE_CAN_TRANSMISSION_MODE_AUTO |
14518c2ecf20Sopenharmony_ci			FE_CAN_GUARD_INTERVAL_AUTO |
14528c2ecf20Sopenharmony_ci			FE_CAN_RECOVER |
14538c2ecf20Sopenharmony_ci			FE_CAN_HIERARCHY_AUTO,
14548c2ecf20Sopenharmony_ci	},
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	.release              = dib7000m_release,
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	.init                 = dib7000m_wakeup,
14598c2ecf20Sopenharmony_ci	.sleep                = dib7000m_sleep,
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	.set_frontend         = dib7000m_set_frontend,
14628c2ecf20Sopenharmony_ci	.get_tune_settings    = dib7000m_fe_get_tune_settings,
14638c2ecf20Sopenharmony_ci	.get_frontend         = dib7000m_get_frontend,
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	.read_status          = dib7000m_read_status,
14668c2ecf20Sopenharmony_ci	.read_ber             = dib7000m_read_ber,
14678c2ecf20Sopenharmony_ci	.read_signal_strength = dib7000m_read_signal_strength,
14688c2ecf20Sopenharmony_ci	.read_snr             = dib7000m_read_snr,
14698c2ecf20Sopenharmony_ci	.read_ucblocks        = dib7000m_read_unc_blocks,
14708c2ecf20Sopenharmony_ci};
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ciMODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
14738c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for the DiBcom 7000MA/MB/PA/PB/MC COFDM demodulator");
14748c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1475