18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci    Driver for VES1893 and VES1993 QPSK Demodulators
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
68c2ecf20Sopenharmony_ci    Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de>
78c2ecf20Sopenharmony_ci    Copyright (C) 2002 Dennis Noermann <dennis.noermann@noernet.de>
88c2ecf20Sopenharmony_ci    Copyright (C) 2002-2003 Andreas Oberritter <obi@linuxtv.org>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci*/
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/init.h>
168c2ecf20Sopenharmony_ci#include <linux/string.h>
178c2ecf20Sopenharmony_ci#include <linux/slab.h>
188c2ecf20Sopenharmony_ci#include <linux/delay.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h>
218c2ecf20Sopenharmony_ci#include "ves1x93.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistruct ves1x93_state {
258c2ecf20Sopenharmony_ci	struct i2c_adapter* i2c;
268c2ecf20Sopenharmony_ci	/* configuration settings */
278c2ecf20Sopenharmony_ci	const struct ves1x93_config* config;
288c2ecf20Sopenharmony_ci	struct dvb_frontend frontend;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	/* previous uncorrected block counter */
318c2ecf20Sopenharmony_ci	enum fe_spectral_inversion inversion;
328c2ecf20Sopenharmony_ci	u8 *init_1x93_tab;
338c2ecf20Sopenharmony_ci	u8 *init_1x93_wtab;
348c2ecf20Sopenharmony_ci	u8 tab_size;
358c2ecf20Sopenharmony_ci	u8 demod_type;
368c2ecf20Sopenharmony_ci	u32 frequency;
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic int debug;
408c2ecf20Sopenharmony_ci#define dprintk	if (debug) printk
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#define DEMOD_VES1893		0
438c2ecf20Sopenharmony_ci#define DEMOD_VES1993		1
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic u8 init_1893_tab [] = {
468c2ecf20Sopenharmony_ci	0x01, 0xa4, 0x35, 0x80, 0x2a, 0x0b, 0x55, 0xc4,
478c2ecf20Sopenharmony_ci	0x09, 0x69, 0x00, 0x86, 0x4c, 0x28, 0x7f, 0x00,
488c2ecf20Sopenharmony_ci	0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
498c2ecf20Sopenharmony_ci	0x80, 0x00, 0x21, 0xb0, 0x14, 0x00, 0xdc, 0x00,
508c2ecf20Sopenharmony_ci	0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
518c2ecf20Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
528c2ecf20Sopenharmony_ci	0x00, 0x55, 0x00, 0x00, 0x7f, 0x00
538c2ecf20Sopenharmony_ci};
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic u8 init_1993_tab [] = {
568c2ecf20Sopenharmony_ci	0x00, 0x9c, 0x35, 0x80, 0x6a, 0x09, 0x72, 0x8c,
578c2ecf20Sopenharmony_ci	0x09, 0x6b, 0x00, 0x00, 0x4c, 0x08, 0x00, 0x00,
588c2ecf20Sopenharmony_ci	0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598c2ecf20Sopenharmony_ci	0x80, 0x40, 0x21, 0xb0, 0x00, 0x00, 0x00, 0x10,
608c2ecf20Sopenharmony_ci	0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
618c2ecf20Sopenharmony_ci	0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
628c2ecf20Sopenharmony_ci	0x00, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03,
638c2ecf20Sopenharmony_ci	0x00, 0x00, 0x0e, 0x80, 0x00
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic u8 init_1893_wtab[] =
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
698c2ecf20Sopenharmony_ci	0,1,0,0,0,0,0,0, 1,0,1,1,0,0,0,1,
708c2ecf20Sopenharmony_ci	1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0,
718c2ecf20Sopenharmony_ci	1,1,1,0,1,1
728c2ecf20Sopenharmony_ci};
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic u8 init_1993_wtab[] =
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
778c2ecf20Sopenharmony_ci	0,1,0,0,0,0,0,0, 1,1,1,1,0,0,0,1,
788c2ecf20Sopenharmony_ci	1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0,
798c2ecf20Sopenharmony_ci	1,1,1,0,1,1,1,1, 1,1,1,1,1
808c2ecf20Sopenharmony_ci};
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic int ves1x93_writereg (struct ves1x93_state* state, u8 reg, u8 data)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	u8 buf [] = { 0x00, reg, data };
858c2ecf20Sopenharmony_ci	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 };
868c2ecf20Sopenharmony_ci	int err;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
898c2ecf20Sopenharmony_ci		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
908c2ecf20Sopenharmony_ci		return -EREMOTEIO;
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	return 0;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic u8 ves1x93_readreg (struct ves1x93_state* state, u8 reg)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	int ret;
998c2ecf20Sopenharmony_ci	u8 b0 [] = { 0x00, reg };
1008c2ecf20Sopenharmony_ci	u8 b1 [] = { 0 };
1018c2ecf20Sopenharmony_ci	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
1028c2ecf20Sopenharmony_ci			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	ret = i2c_transfer (state->i2c, msg, 2);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (ret != 2) return ret;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	return b1[0];
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic int ves1x93_clr_bit (struct ves1x93_state* state)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	msleep(10);
1148c2ecf20Sopenharmony_ci	ves1x93_writereg (state, 0, state->init_1x93_tab[0] & 0xfe);
1158c2ecf20Sopenharmony_ci	ves1x93_writereg (state, 0, state->init_1x93_tab[0]);
1168c2ecf20Sopenharmony_ci	msleep(50);
1178c2ecf20Sopenharmony_ci	return 0;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic int ves1x93_set_inversion(struct ves1x93_state *state,
1218c2ecf20Sopenharmony_ci				 enum fe_spectral_inversion inversion)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	u8 val;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	/*
1268c2ecf20Sopenharmony_ci	 * inversion on/off are interchanged because i and q seem to
1278c2ecf20Sopenharmony_ci	 * be swapped on the hardware
1288c2ecf20Sopenharmony_ci	 */
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	switch (inversion) {
1318c2ecf20Sopenharmony_ci	case INVERSION_OFF:
1328c2ecf20Sopenharmony_ci		val = 0xc0;
1338c2ecf20Sopenharmony_ci		break;
1348c2ecf20Sopenharmony_ci	case INVERSION_ON:
1358c2ecf20Sopenharmony_ci		val = 0x80;
1368c2ecf20Sopenharmony_ci		break;
1378c2ecf20Sopenharmony_ci	case INVERSION_AUTO:
1388c2ecf20Sopenharmony_ci		val = 0x00;
1398c2ecf20Sopenharmony_ci		break;
1408c2ecf20Sopenharmony_ci	default:
1418c2ecf20Sopenharmony_ci		return -EINVAL;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	return ves1x93_writereg (state, 0x0c, (state->init_1x93_tab[0x0c] & 0x3f) | val);
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic int ves1x93_set_fec(struct ves1x93_state *state, enum fe_code_rate fec)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	if (fec == FEC_AUTO)
1508c2ecf20Sopenharmony_ci		return ves1x93_writereg (state, 0x0d, 0x08);
1518c2ecf20Sopenharmony_ci	else if (fec < FEC_1_2 || fec > FEC_8_9)
1528c2ecf20Sopenharmony_ci		return -EINVAL;
1538c2ecf20Sopenharmony_ci	else
1548c2ecf20Sopenharmony_ci		return ves1x93_writereg (state, 0x0d, fec - FEC_1_2);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic enum fe_code_rate ves1x93_get_fec(struct ves1x93_state *state)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	return FEC_1_2 + ((ves1x93_readreg (state, 0x0d) >> 4) & 0x7);
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic int ves1x93_set_symbolrate (struct ves1x93_state* state, u32 srate)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	u32 BDR;
1658c2ecf20Sopenharmony_ci	u32 ratio;
1668c2ecf20Sopenharmony_ci	u8  ADCONF, FCONF, FNR, AGCR;
1678c2ecf20Sopenharmony_ci	u32 BDRI;
1688c2ecf20Sopenharmony_ci	u32 tmp;
1698c2ecf20Sopenharmony_ci	u32 FIN;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	dprintk("%s: srate == %d\n", __func__, (unsigned int) srate);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	if (srate > state->config->xin/2)
1748c2ecf20Sopenharmony_ci		srate = state->config->xin/2;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	if (srate < 500000)
1778c2ecf20Sopenharmony_ci		srate = 500000;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci#define MUL (1UL<<26)
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	FIN = (state->config->xin + 6000) >> 4;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	tmp = srate << 6;
1848c2ecf20Sopenharmony_ci	ratio = tmp / FIN;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	tmp = (tmp % FIN) << 8;
1878c2ecf20Sopenharmony_ci	ratio = (ratio << 8) + tmp / FIN;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	tmp = (tmp % FIN) << 8;
1908c2ecf20Sopenharmony_ci	ratio = (ratio << 8) + tmp / FIN;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	FNR = 0xff;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	if (ratio < MUL/3)	     FNR = 0;
1958c2ecf20Sopenharmony_ci	if (ratio < (MUL*11)/50)     FNR = 1;
1968c2ecf20Sopenharmony_ci	if (ratio < MUL/6)	     FNR = 2;
1978c2ecf20Sopenharmony_ci	if (ratio < MUL/9)	     FNR = 3;
1988c2ecf20Sopenharmony_ci	if (ratio < MUL/12)	     FNR = 4;
1998c2ecf20Sopenharmony_ci	if (ratio < (MUL*11)/200)    FNR = 5;
2008c2ecf20Sopenharmony_ci	if (ratio < MUL/24)	     FNR = 6;
2018c2ecf20Sopenharmony_ci	if (ratio < (MUL*27)/1000)   FNR = 7;
2028c2ecf20Sopenharmony_ci	if (ratio < MUL/48)	     FNR = 8;
2038c2ecf20Sopenharmony_ci	if (ratio < (MUL*137)/10000) FNR = 9;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	if (FNR == 0xff) {
2068c2ecf20Sopenharmony_ci		ADCONF = 0x89;
2078c2ecf20Sopenharmony_ci		FCONF  = 0x80;
2088c2ecf20Sopenharmony_ci		FNR	= 0;
2098c2ecf20Sopenharmony_ci	} else {
2108c2ecf20Sopenharmony_ci		ADCONF = 0x81;
2118c2ecf20Sopenharmony_ci		FCONF  = 0x88 | (FNR >> 1) | ((FNR & 0x01) << 5);
2128c2ecf20Sopenharmony_ci		/*FCONF	 = 0x80 | ((FNR & 0x01) << 5) | (((FNR > 1) & 0x03) << 3) | ((FNR >> 1) & 0x07);*/
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	BDR = (( (ratio << (FNR >> 1)) >> 4) + 1) >> 1;
2168c2ecf20Sopenharmony_ci	BDRI = ( ((FIN << 8) / ((srate << (FNR >> 1)) >> 2)) + 1) >> 1;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	dprintk("FNR= %d\n", FNR);
2198c2ecf20Sopenharmony_ci	dprintk("ratio= %08x\n", (unsigned int) ratio);
2208c2ecf20Sopenharmony_ci	dprintk("BDR= %08x\n", (unsigned int) BDR);
2218c2ecf20Sopenharmony_ci	dprintk("BDRI= %02x\n", (unsigned int) BDRI);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	if (BDRI > 0xff)
2248c2ecf20Sopenharmony_ci		BDRI = 0xff;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	ves1x93_writereg (state, 0x06, 0xff & BDR);
2278c2ecf20Sopenharmony_ci	ves1x93_writereg (state, 0x07, 0xff & (BDR >> 8));
2288c2ecf20Sopenharmony_ci	ves1x93_writereg (state, 0x08, 0x0f & (BDR >> 16));
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	ves1x93_writereg (state, 0x09, BDRI);
2318c2ecf20Sopenharmony_ci	ves1x93_writereg (state, 0x20, ADCONF);
2328c2ecf20Sopenharmony_ci	ves1x93_writereg (state, 0x21, FCONF);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	AGCR = state->init_1x93_tab[0x05];
2358c2ecf20Sopenharmony_ci	if (state->config->invert_pwm)
2368c2ecf20Sopenharmony_ci		AGCR |= 0x20;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	if (srate < 6000000)
2398c2ecf20Sopenharmony_ci		AGCR |= 0x80;
2408c2ecf20Sopenharmony_ci	else
2418c2ecf20Sopenharmony_ci		AGCR &= ~0x80;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	ves1x93_writereg (state, 0x05, AGCR);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	/* ves1993 hates this, will lose lock */
2468c2ecf20Sopenharmony_ci	if (state->demod_type != DEMOD_VES1993)
2478c2ecf20Sopenharmony_ci		ves1x93_clr_bit (state);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	return 0;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic int ves1x93_init (struct dvb_frontend* fe)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	struct ves1x93_state* state = fe->demodulator_priv;
2558c2ecf20Sopenharmony_ci	int i;
2568c2ecf20Sopenharmony_ci	int val;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	dprintk("%s: init chip\n", __func__);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	for (i = 0; i < state->tab_size; i++) {
2618c2ecf20Sopenharmony_ci		if (state->init_1x93_wtab[i]) {
2628c2ecf20Sopenharmony_ci			val = state->init_1x93_tab[i];
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci			if (state->config->invert_pwm && (i == 0x05)) val |= 0x20; /* invert PWM */
2658c2ecf20Sopenharmony_ci			ves1x93_writereg (state, i, val);
2668c2ecf20Sopenharmony_ci		}
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	return 0;
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic int ves1x93_set_voltage(struct dvb_frontend *fe,
2738c2ecf20Sopenharmony_ci			       enum fe_sec_voltage voltage)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	struct ves1x93_state* state = fe->demodulator_priv;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	switch (voltage) {
2788c2ecf20Sopenharmony_ci	case SEC_VOLTAGE_13:
2798c2ecf20Sopenharmony_ci		return ves1x93_writereg (state, 0x1f, 0x20);
2808c2ecf20Sopenharmony_ci	case SEC_VOLTAGE_18:
2818c2ecf20Sopenharmony_ci		return ves1x93_writereg (state, 0x1f, 0x30);
2828c2ecf20Sopenharmony_ci	case SEC_VOLTAGE_OFF:
2838c2ecf20Sopenharmony_ci		return ves1x93_writereg (state, 0x1f, 0x00);
2848c2ecf20Sopenharmony_ci	default:
2858c2ecf20Sopenharmony_ci		return -EINVAL;
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic int ves1x93_read_status(struct dvb_frontend *fe,
2908c2ecf20Sopenharmony_ci			       enum fe_status *status)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct ves1x93_state* state = fe->demodulator_priv;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	u8 sync = ves1x93_readreg (state, 0x0e);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	/*
2978c2ecf20Sopenharmony_ci	 * The ves1893 sometimes returns sync values that make no sense,
2988c2ecf20Sopenharmony_ci	 * because, e.g., the SIGNAL bit is 0, while some of the higher
2998c2ecf20Sopenharmony_ci	 * bits are 1 (and how can there be a CARRIER w/o a SIGNAL?).
3008c2ecf20Sopenharmony_ci	 * Tests showed that the VITERBI and SYNC bits are returned
3018c2ecf20Sopenharmony_ci	 * reliably, while the SIGNAL and CARRIER bits ar sometimes wrong.
3028c2ecf20Sopenharmony_ci	 * If such a case occurs, we read the value again, until we get a
3038c2ecf20Sopenharmony_ci	 * valid value.
3048c2ecf20Sopenharmony_ci	 */
3058c2ecf20Sopenharmony_ci	int maxtry = 10; /* just for safety - let's not get stuck here */
3068c2ecf20Sopenharmony_ci	while ((sync & 0x03) != 0x03 && (sync & 0x0c) && maxtry--) {
3078c2ecf20Sopenharmony_ci		msleep(10);
3088c2ecf20Sopenharmony_ci		sync = ves1x93_readreg (state, 0x0e);
3098c2ecf20Sopenharmony_ci	}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	*status = 0;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	if (sync & 1)
3148c2ecf20Sopenharmony_ci		*status |= FE_HAS_SIGNAL;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	if (sync & 2)
3178c2ecf20Sopenharmony_ci		*status |= FE_HAS_CARRIER;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (sync & 4)
3208c2ecf20Sopenharmony_ci		*status |= FE_HAS_VITERBI;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	if (sync & 8)
3238c2ecf20Sopenharmony_ci		*status |= FE_HAS_SYNC;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	if ((sync & 0x1f) == 0x1f)
3268c2ecf20Sopenharmony_ci		*status |= FE_HAS_LOCK;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	return 0;
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistatic int ves1x93_read_ber(struct dvb_frontend* fe, u32* ber)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct ves1x93_state* state = fe->demodulator_priv;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	*ber = ves1x93_readreg (state, 0x15);
3368c2ecf20Sopenharmony_ci	*ber |= (ves1x93_readreg (state, 0x16) << 8);
3378c2ecf20Sopenharmony_ci	*ber |= ((ves1x93_readreg (state, 0x17) & 0x0F) << 16);
3388c2ecf20Sopenharmony_ci	*ber *= 10;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	return 0;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic int ves1x93_read_signal_strength(struct dvb_frontend* fe, u16* strength)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	struct ves1x93_state* state = fe->demodulator_priv;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	u8 signal = ~ves1x93_readreg (state, 0x0b);
3488c2ecf20Sopenharmony_ci	*strength = (signal << 8) | signal;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	return 0;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic int ves1x93_read_snr(struct dvb_frontend* fe, u16* snr)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	struct ves1x93_state* state = fe->demodulator_priv;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	u8 _snr = ~ves1x93_readreg (state, 0x1c);
3588c2ecf20Sopenharmony_ci	*snr = (_snr << 8) | _snr;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	return 0;
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cistatic int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	struct ves1x93_state* state = fe->demodulator_priv;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	*ucblocks = ves1x93_readreg (state, 0x18) & 0x7f;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	if (*ucblocks == 0x7f)
3708c2ecf20Sopenharmony_ci		*ucblocks = 0xffffffff;   /* counter overflow... */
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	ves1x93_writereg (state, 0x18, 0x00);  /* reset the counter */
3738c2ecf20Sopenharmony_ci	ves1x93_writereg (state, 0x18, 0x80);  /* dto. */
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	return 0;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic int ves1x93_set_frontend(struct dvb_frontend *fe)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
3818c2ecf20Sopenharmony_ci	struct ves1x93_state* state = fe->demodulator_priv;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	if (fe->ops.tuner_ops.set_params) {
3848c2ecf20Sopenharmony_ci		fe->ops.tuner_ops.set_params(fe);
3858c2ecf20Sopenharmony_ci		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci	ves1x93_set_inversion (state, p->inversion);
3888c2ecf20Sopenharmony_ci	ves1x93_set_fec(state, p->fec_inner);
3898c2ecf20Sopenharmony_ci	ves1x93_set_symbolrate(state, p->symbol_rate);
3908c2ecf20Sopenharmony_ci	state->inversion = p->inversion;
3918c2ecf20Sopenharmony_ci	state->frequency = p->frequency;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	return 0;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_cistatic int ves1x93_get_frontend(struct dvb_frontend *fe,
3978c2ecf20Sopenharmony_ci				struct dtv_frontend_properties *p)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	struct ves1x93_state* state = fe->demodulator_priv;
4008c2ecf20Sopenharmony_ci	int afc;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2;
4038c2ecf20Sopenharmony_ci	afc = (afc * (int)(p->symbol_rate/1000/8))/16;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	p->frequency = state->frequency - afc;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	/*
4088c2ecf20Sopenharmony_ci	 * inversion indicator is only valid
4098c2ecf20Sopenharmony_ci	 * if auto inversion was used
4108c2ecf20Sopenharmony_ci	 */
4118c2ecf20Sopenharmony_ci	if (state->inversion == INVERSION_AUTO)
4128c2ecf20Sopenharmony_ci		p->inversion = (ves1x93_readreg (state, 0x0f) & 2) ?
4138c2ecf20Sopenharmony_ci				INVERSION_OFF : INVERSION_ON;
4148c2ecf20Sopenharmony_ci	p->fec_inner = ves1x93_get_fec(state);
4158c2ecf20Sopenharmony_ci	/*  XXX FIXME: timing offset !! */
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	return 0;
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_cistatic int ves1x93_sleep(struct dvb_frontend* fe)
4218c2ecf20Sopenharmony_ci{
4228c2ecf20Sopenharmony_ci	struct ves1x93_state* state = fe->demodulator_priv;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	return ves1x93_writereg (state, 0x00, 0x08);
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic void ves1x93_release(struct dvb_frontend* fe)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	struct ves1x93_state* state = fe->demodulator_priv;
4308c2ecf20Sopenharmony_ci	kfree(state);
4318c2ecf20Sopenharmony_ci}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cistatic int ves1x93_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	struct ves1x93_state* state = fe->demodulator_priv;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	if (enable) {
4388c2ecf20Sopenharmony_ci		return ves1x93_writereg(state, 0x00, 0x11);
4398c2ecf20Sopenharmony_ci	} else {
4408c2ecf20Sopenharmony_ci		return ves1x93_writereg(state, 0x00, 0x01);
4418c2ecf20Sopenharmony_ci	}
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops ves1x93_ops;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_cistruct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
4478c2ecf20Sopenharmony_ci				    struct i2c_adapter* i2c)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	struct ves1x93_state* state = NULL;
4508c2ecf20Sopenharmony_ci	u8 identity;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	/* allocate memory for the internal state */
4538c2ecf20Sopenharmony_ci	state = kzalloc(sizeof(struct ves1x93_state), GFP_KERNEL);
4548c2ecf20Sopenharmony_ci	if (state == NULL) goto error;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	/* setup the state */
4578c2ecf20Sopenharmony_ci	state->config = config;
4588c2ecf20Sopenharmony_ci	state->i2c = i2c;
4598c2ecf20Sopenharmony_ci	state->inversion = INVERSION_OFF;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	/* check if the demod is there + identify it */
4628c2ecf20Sopenharmony_ci	identity = ves1x93_readreg(state, 0x1e);
4638c2ecf20Sopenharmony_ci	switch (identity) {
4648c2ecf20Sopenharmony_ci	case 0xdc: /* VES1893A rev1 */
4658c2ecf20Sopenharmony_ci		printk("ves1x93: Detected ves1893a rev1\n");
4668c2ecf20Sopenharmony_ci		state->demod_type = DEMOD_VES1893;
4678c2ecf20Sopenharmony_ci		state->init_1x93_tab = init_1893_tab;
4688c2ecf20Sopenharmony_ci		state->init_1x93_wtab = init_1893_wtab;
4698c2ecf20Sopenharmony_ci		state->tab_size = sizeof(init_1893_tab);
4708c2ecf20Sopenharmony_ci		break;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	case 0xdd: /* VES1893A rev2 */
4738c2ecf20Sopenharmony_ci		printk("ves1x93: Detected ves1893a rev2\n");
4748c2ecf20Sopenharmony_ci		state->demod_type = DEMOD_VES1893;
4758c2ecf20Sopenharmony_ci		state->init_1x93_tab = init_1893_tab;
4768c2ecf20Sopenharmony_ci		state->init_1x93_wtab = init_1893_wtab;
4778c2ecf20Sopenharmony_ci		state->tab_size = sizeof(init_1893_tab);
4788c2ecf20Sopenharmony_ci		break;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	case 0xde: /* VES1993 */
4818c2ecf20Sopenharmony_ci		printk("ves1x93: Detected ves1993\n");
4828c2ecf20Sopenharmony_ci		state->demod_type = DEMOD_VES1993;
4838c2ecf20Sopenharmony_ci		state->init_1x93_tab = init_1993_tab;
4848c2ecf20Sopenharmony_ci		state->init_1x93_wtab = init_1993_wtab;
4858c2ecf20Sopenharmony_ci		state->tab_size = sizeof(init_1993_tab);
4868c2ecf20Sopenharmony_ci		break;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	default:
4898c2ecf20Sopenharmony_ci		goto error;
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	/* create dvb_frontend */
4938c2ecf20Sopenharmony_ci	memcpy(&state->frontend.ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
4948c2ecf20Sopenharmony_ci	state->frontend.demodulator_priv = state;
4958c2ecf20Sopenharmony_ci	return &state->frontend;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cierror:
4988c2ecf20Sopenharmony_ci	kfree(state);
4998c2ecf20Sopenharmony_ci	return NULL;
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops ves1x93_ops = {
5038c2ecf20Sopenharmony_ci	.delsys = { SYS_DVBS },
5048c2ecf20Sopenharmony_ci	.info = {
5058c2ecf20Sopenharmony_ci		.name			= "VLSI VES1x93 DVB-S",
5068c2ecf20Sopenharmony_ci		.frequency_min_hz	=   950 * MHz,
5078c2ecf20Sopenharmony_ci		.frequency_max_hz	=  2150 * MHz,
5088c2ecf20Sopenharmony_ci		.frequency_stepsize_hz	=   125 * kHz,
5098c2ecf20Sopenharmony_ci		.frequency_tolerance_hz	= 29500 * kHz,
5108c2ecf20Sopenharmony_ci		.symbol_rate_min	= 1000000,
5118c2ecf20Sopenharmony_ci		.symbol_rate_max	= 45000000,
5128c2ecf20Sopenharmony_ci	/*	.symbol_rate_tolerance	=	???,*/
5138c2ecf20Sopenharmony_ci		.caps = FE_CAN_INVERSION_AUTO |
5148c2ecf20Sopenharmony_ci			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
5158c2ecf20Sopenharmony_ci			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
5168c2ecf20Sopenharmony_ci			FE_CAN_QPSK
5178c2ecf20Sopenharmony_ci	},
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	.release = ves1x93_release,
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	.init = ves1x93_init,
5228c2ecf20Sopenharmony_ci	.sleep = ves1x93_sleep,
5238c2ecf20Sopenharmony_ci	.i2c_gate_ctrl = ves1x93_i2c_gate_ctrl,
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	.set_frontend = ves1x93_set_frontend,
5268c2ecf20Sopenharmony_ci	.get_frontend = ves1x93_get_frontend,
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	.read_status = ves1x93_read_status,
5298c2ecf20Sopenharmony_ci	.read_ber = ves1x93_read_ber,
5308c2ecf20Sopenharmony_ci	.read_signal_strength = ves1x93_read_signal_strength,
5318c2ecf20Sopenharmony_ci	.read_snr = ves1x93_read_snr,
5328c2ecf20Sopenharmony_ci	.read_ucblocks = ves1x93_read_ucblocks,
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	.set_voltage = ves1x93_set_voltage,
5358c2ecf20Sopenharmony_ci};
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_cimodule_param(debug, int, 0644);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("VLSI VES1x93 DVB-S Demodulator driver");
5408c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ralph Metzler");
5418c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ves1x93_attach);
544