18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci    Driver for ST STV0299 demodulator
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
68c2ecf20Sopenharmony_ci	<ralph@convergence.de>,
78c2ecf20Sopenharmony_ci	<holger@convergence.de>,
88c2ecf20Sopenharmony_ci	<js@convergence.de>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci    Philips SU1278/SH
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci    Copyright (C) 2002 by Peter Schildmann <peter.schildmann@web.de>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci    LG TDQF-S001F
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci    Copyright (C) 2002 Felix Domke <tmbinc@elitedvb.net>
198c2ecf20Sopenharmony_ci		     & Andreas Oberritter <obi@linuxtv.org>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci    Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci    Copyright (C) 2003 Vadim Catana <skystar@moldova.cc>:
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci    Support for Philips SU1278 on Technotrend hardware
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci    Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci*/
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include <linux/init.h>
348c2ecf20Sopenharmony_ci#include <linux/kernel.h>
358c2ecf20Sopenharmony_ci#include <linux/ktime.h>
368c2ecf20Sopenharmony_ci#include <linux/module.h>
378c2ecf20Sopenharmony_ci#include <linux/string.h>
388c2ecf20Sopenharmony_ci#include <linux/slab.h>
398c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
408c2ecf20Sopenharmony_ci#include <asm/div64.h>
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h>
438c2ecf20Sopenharmony_ci#include "stv0299.h"
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistruct stv0299_state {
468c2ecf20Sopenharmony_ci	struct i2c_adapter* i2c;
478c2ecf20Sopenharmony_ci	const struct stv0299_config* config;
488c2ecf20Sopenharmony_ci	struct dvb_frontend frontend;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	u8 initialised:1;
518c2ecf20Sopenharmony_ci	u32 tuner_frequency;
528c2ecf20Sopenharmony_ci	u32 symbol_rate;
538c2ecf20Sopenharmony_ci	enum fe_code_rate fec_inner;
548c2ecf20Sopenharmony_ci	int errmode;
558c2ecf20Sopenharmony_ci	u32 ucblocks;
568c2ecf20Sopenharmony_ci	u8 mcr_reg;
578c2ecf20Sopenharmony_ci};
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#define STATUS_BER 0
608c2ecf20Sopenharmony_ci#define STATUS_UCBLOCKS 1
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic int debug;
638c2ecf20Sopenharmony_cistatic int debug_legacy_dish_switch;
648c2ecf20Sopenharmony_ci#define dprintk(args...) \
658c2ecf20Sopenharmony_ci	do { \
668c2ecf20Sopenharmony_ci		if (debug) printk(KERN_DEBUG "stv0299: " args); \
678c2ecf20Sopenharmony_ci	} while (0)
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	int ret;
738c2ecf20Sopenharmony_ci	u8 buf [] = { reg, data };
748c2ecf20Sopenharmony_ci	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	ret = i2c_transfer (state->i2c, &msg, 1);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (ret != 1)
798c2ecf20Sopenharmony_ci		dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
808c2ecf20Sopenharmony_ci			__func__, reg, data, ret);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	return (ret != 1) ? -EREMOTEIO : 0;
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic int stv0299_write(struct dvb_frontend* fe, const u8 buf[], int len)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	if (len != 2)
908c2ecf20Sopenharmony_ci		return -EINVAL;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	return stv0299_writeregI(state, buf[0], buf[1]);
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic u8 stv0299_readreg (struct stv0299_state* state, u8 reg)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	int ret;
988c2ecf20Sopenharmony_ci	u8 b0 [] = { reg };
998c2ecf20Sopenharmony_ci	u8 b1 [] = { 0 };
1008c2ecf20Sopenharmony_ci	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
1018c2ecf20Sopenharmony_ci			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	ret = i2c_transfer (state->i2c, msg, 2);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	if (ret != 2)
1068c2ecf20Sopenharmony_ci		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
1078c2ecf20Sopenharmony_ci				__func__, reg, ret);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	return b1[0];
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	int ret;
1158c2ecf20Sopenharmony_ci	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = &reg1, .len = 1 },
1168c2ecf20Sopenharmony_ci			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } };
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	ret = i2c_transfer (state->i2c, msg, 2);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (ret != 2)
1218c2ecf20Sopenharmony_ci		dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	return ret == 2 ? 0 : ret;
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic int stv0299_set_FEC(struct stv0299_state *state, enum fe_code_rate fec)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	dprintk ("%s\n", __func__);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	switch (fec) {
1318c2ecf20Sopenharmony_ci	case FEC_AUTO:
1328c2ecf20Sopenharmony_ci	{
1338c2ecf20Sopenharmony_ci		return stv0299_writeregI (state, 0x31, 0x1f);
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci	case FEC_1_2:
1368c2ecf20Sopenharmony_ci	{
1378c2ecf20Sopenharmony_ci		return stv0299_writeregI (state, 0x31, 0x01);
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci	case FEC_2_3:
1408c2ecf20Sopenharmony_ci	{
1418c2ecf20Sopenharmony_ci		return stv0299_writeregI (state, 0x31, 0x02);
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci	case FEC_3_4:
1448c2ecf20Sopenharmony_ci	{
1458c2ecf20Sopenharmony_ci		return stv0299_writeregI (state, 0x31, 0x04);
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci	case FEC_5_6:
1488c2ecf20Sopenharmony_ci	{
1498c2ecf20Sopenharmony_ci		return stv0299_writeregI (state, 0x31, 0x08);
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci	case FEC_7_8:
1528c2ecf20Sopenharmony_ci	{
1538c2ecf20Sopenharmony_ci		return stv0299_writeregI (state, 0x31, 0x10);
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci	default:
1568c2ecf20Sopenharmony_ci	{
1578c2ecf20Sopenharmony_ci		return -EINVAL;
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci    }
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic enum fe_code_rate stv0299_get_fec(struct stv0299_state *state)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	static enum fe_code_rate fec_tab[] = { FEC_2_3, FEC_3_4, FEC_5_6,
1658c2ecf20Sopenharmony_ci					       FEC_7_8, FEC_1_2 };
1668c2ecf20Sopenharmony_ci	u8 index;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	dprintk ("%s\n", __func__);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	index = stv0299_readreg (state, 0x1b);
1718c2ecf20Sopenharmony_ci	index &= 0x7;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	if (index > 4)
1748c2ecf20Sopenharmony_ci		return FEC_AUTO;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	return fec_tab [index];
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	unsigned long start = jiffies;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	dprintk ("%s\n", __func__);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	while (stv0299_readreg(state, 0x0a) & 1) {
1868c2ecf20Sopenharmony_ci		if (jiffies - start > timeout) {
1878c2ecf20Sopenharmony_ci			dprintk ("%s: timeout!!\n", __func__);
1888c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
1898c2ecf20Sopenharmony_ci		}
1908c2ecf20Sopenharmony_ci		msleep(10);
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	return 0;
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	unsigned long start = jiffies;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	dprintk ("%s\n", __func__);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	while ((stv0299_readreg(state, 0x0a) & 3) != 2 ) {
2038c2ecf20Sopenharmony_ci		if (jiffies - start > timeout) {
2048c2ecf20Sopenharmony_ci			dprintk ("%s: timeout!!\n", __func__);
2058c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
2068c2ecf20Sopenharmony_ci		}
2078c2ecf20Sopenharmony_ci		msleep(10);
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	return 0;
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
2168c2ecf20Sopenharmony_ci	u64 big = srate;
2178c2ecf20Sopenharmony_ci	u32 ratio;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	// check rate is within limits
2208c2ecf20Sopenharmony_ci	if ((srate < 1000000) || (srate > 45000000)) return -EINVAL;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	// calculate value to program
2238c2ecf20Sopenharmony_ci	big = big << 20;
2248c2ecf20Sopenharmony_ci	big += (state->config->mclk-1); // round correctly
2258c2ecf20Sopenharmony_ci	do_div(big, state->config->mclk);
2268c2ecf20Sopenharmony_ci	ratio = big << 4;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	return state->config->set_symbol_rate(fe, srate, ratio);
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic int stv0299_get_symbolrate (struct stv0299_state* state)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	u32 Mclk = state->config->mclk / 4096L;
2348c2ecf20Sopenharmony_ci	u32 srate;
2358c2ecf20Sopenharmony_ci	s32 offset;
2368c2ecf20Sopenharmony_ci	u8 sfr[3];
2378c2ecf20Sopenharmony_ci	s8 rtf;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	dprintk ("%s\n", __func__);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	stv0299_readregs (state, 0x1f, sfr, 3);
2428c2ecf20Sopenharmony_ci	stv0299_readregs (state, 0x1a, (u8 *)&rtf, 1);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	srate = (sfr[0] << 8) | sfr[1];
2458c2ecf20Sopenharmony_ci	srate *= Mclk;
2468c2ecf20Sopenharmony_ci	srate /= 16;
2478c2ecf20Sopenharmony_ci	srate += (sfr[2] >> 4) * Mclk / 256;
2488c2ecf20Sopenharmony_ci	offset = (s32) rtf * (srate / 4096L);
2498c2ecf20Sopenharmony_ci	offset /= 128;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	dprintk ("%s : srate = %i\n", __func__, srate);
2528c2ecf20Sopenharmony_ci	dprintk ("%s : ofset = %i\n", __func__, offset);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	srate += offset;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	srate += 1000;
2578c2ecf20Sopenharmony_ci	srate /= 2000;
2588c2ecf20Sopenharmony_ci	srate *= 2000;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	return srate;
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic int stv0299_send_diseqc_msg (struct dvb_frontend* fe,
2648c2ecf20Sopenharmony_ci				    struct dvb_diseqc_master_cmd *m)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
2678c2ecf20Sopenharmony_ci	u8 val;
2688c2ecf20Sopenharmony_ci	int i;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	dprintk ("%s\n", __func__);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (stv0299_wait_diseqc_idle (state, 100) < 0)
2738c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	val = stv0299_readreg (state, 0x08);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x6))  /* DiSEqC mode */
2788c2ecf20Sopenharmony_ci		return -EREMOTEIO;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	for (i=0; i<m->msg_len; i++) {
2818c2ecf20Sopenharmony_ci		if (stv0299_wait_diseqc_fifo (state, 100) < 0)
2828c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci		if (stv0299_writeregI (state, 0x09, m->msg[i]))
2858c2ecf20Sopenharmony_ci			return -EREMOTEIO;
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (stv0299_wait_diseqc_idle (state, 100) < 0)
2898c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	return 0;
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic int stv0299_send_diseqc_burst(struct dvb_frontend *fe,
2958c2ecf20Sopenharmony_ci				     enum fe_sec_mini_cmd burst)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
2988c2ecf20Sopenharmony_ci	u8 val;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	dprintk ("%s\n", __func__);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	if (stv0299_wait_diseqc_idle (state, 100) < 0)
3038c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	val = stv0299_readreg (state, 0x08);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x2))	/* burst mode */
3088c2ecf20Sopenharmony_ci		return -EREMOTEIO;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	if (stv0299_writeregI (state, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff))
3118c2ecf20Sopenharmony_ci		return -EREMOTEIO;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	if (stv0299_wait_diseqc_idle (state, 100) < 0)
3148c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	if (stv0299_writeregI (state, 0x08, val))
3178c2ecf20Sopenharmony_ci		return -EREMOTEIO;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	return 0;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic int stv0299_set_tone(struct dvb_frontend *fe,
3238c2ecf20Sopenharmony_ci			    enum fe_sec_tone_mode tone)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
3268c2ecf20Sopenharmony_ci	u8 val;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (stv0299_wait_diseqc_idle (state, 100) < 0)
3298c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	val = stv0299_readreg (state, 0x08);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	switch (tone) {
3348c2ecf20Sopenharmony_ci	case SEC_TONE_ON:
3358c2ecf20Sopenharmony_ci		return stv0299_writeregI (state, 0x08, val | 0x3);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	case SEC_TONE_OFF:
3388c2ecf20Sopenharmony_ci		return stv0299_writeregI (state, 0x08, (val & ~0x3) | 0x02);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	default:
3418c2ecf20Sopenharmony_ci		return -EINVAL;
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic int stv0299_set_voltage(struct dvb_frontend *fe,
3468c2ecf20Sopenharmony_ci			       enum fe_sec_voltage voltage)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
3498c2ecf20Sopenharmony_ci	u8 reg0x08;
3508c2ecf20Sopenharmony_ci	u8 reg0x0c;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	dprintk("%s: %s\n", __func__,
3538c2ecf20Sopenharmony_ci		voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
3548c2ecf20Sopenharmony_ci		voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	reg0x08 = stv0299_readreg (state, 0x08);
3578c2ecf20Sopenharmony_ci	reg0x0c = stv0299_readreg (state, 0x0c);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	/*
3608c2ecf20Sopenharmony_ci	 *  H/V switching over OP0, OP1 and OP2 are LNB power enable bits
3618c2ecf20Sopenharmony_ci	 */
3628c2ecf20Sopenharmony_ci	reg0x0c &= 0x0f;
3638c2ecf20Sopenharmony_ci	reg0x08 = (reg0x08 & 0x3f) | (state->config->lock_output << 6);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	switch (voltage) {
3668c2ecf20Sopenharmony_ci	case SEC_VOLTAGE_13:
3678c2ecf20Sopenharmony_ci		if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0)
3688c2ecf20Sopenharmony_ci			reg0x0c |= 0x10; /* OP1 off, OP0 on */
3698c2ecf20Sopenharmony_ci		else
3708c2ecf20Sopenharmony_ci			reg0x0c |= 0x40; /* OP1 on, OP0 off */
3718c2ecf20Sopenharmony_ci		break;
3728c2ecf20Sopenharmony_ci	case SEC_VOLTAGE_18:
3738c2ecf20Sopenharmony_ci		reg0x0c |= 0x50; /* OP1 on, OP0 on */
3748c2ecf20Sopenharmony_ci		break;
3758c2ecf20Sopenharmony_ci	case SEC_VOLTAGE_OFF:
3768c2ecf20Sopenharmony_ci		/* LNB power off! */
3778c2ecf20Sopenharmony_ci		reg0x08 = 0x00;
3788c2ecf20Sopenharmony_ci		reg0x0c = 0x00;
3798c2ecf20Sopenharmony_ci		break;
3808c2ecf20Sopenharmony_ci	default:
3818c2ecf20Sopenharmony_ci		return -EINVAL;
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (state->config->op0_off)
3858c2ecf20Sopenharmony_ci		reg0x0c &= ~0x10;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	stv0299_writeregI(state, 0x08, reg0x08);
3888c2ecf20Sopenharmony_ci	return stv0299_writeregI(state, 0x0c, reg0x0c);
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long cmd)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
3948c2ecf20Sopenharmony_ci	u8 reg0x08;
3958c2ecf20Sopenharmony_ci	u8 reg0x0c;
3968c2ecf20Sopenharmony_ci	u8 lv_mask = 0x40;
3978c2ecf20Sopenharmony_ci	u8 last = 1;
3988c2ecf20Sopenharmony_ci	int i;
3998c2ecf20Sopenharmony_ci	ktime_t nexttime;
4008c2ecf20Sopenharmony_ci	ktime_t tv[10];
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	reg0x08 = stv0299_readreg (state, 0x08);
4038c2ecf20Sopenharmony_ci	reg0x0c = stv0299_readreg (state, 0x0c);
4048c2ecf20Sopenharmony_ci	reg0x0c &= 0x0f;
4058c2ecf20Sopenharmony_ci	stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6));
4068c2ecf20Sopenharmony_ci	if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0)
4078c2ecf20Sopenharmony_ci		lv_mask = 0x10;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	cmd = cmd << 1;
4108c2ecf20Sopenharmony_ci	if (debug_legacy_dish_switch)
4118c2ecf20Sopenharmony_ci		printk ("%s switch command: 0x%04lx\n",__func__, cmd);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	nexttime = ktime_get_boottime();
4148c2ecf20Sopenharmony_ci	if (debug_legacy_dish_switch)
4158c2ecf20Sopenharmony_ci		tv[0] = nexttime;
4168c2ecf20Sopenharmony_ci	stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	dvb_frontend_sleep_until(&nexttime, 32000);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	for (i=0; i<9; i++) {
4218c2ecf20Sopenharmony_ci		if (debug_legacy_dish_switch)
4228c2ecf20Sopenharmony_ci			tv[i+1] = ktime_get_boottime();
4238c2ecf20Sopenharmony_ci		if((cmd & 0x01) != last) {
4248c2ecf20Sopenharmony_ci			/* set voltage to (last ? 13V : 18V) */
4258c2ecf20Sopenharmony_ci			stv0299_writeregI (state, 0x0c, reg0x0c | (last ? lv_mask : 0x50));
4268c2ecf20Sopenharmony_ci			last = (last) ? 0 : 1;
4278c2ecf20Sopenharmony_ci		}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci		cmd = cmd >> 1;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci		if (i != 8)
4328c2ecf20Sopenharmony_ci			dvb_frontend_sleep_until(&nexttime, 8000);
4338c2ecf20Sopenharmony_ci	}
4348c2ecf20Sopenharmony_ci	if (debug_legacy_dish_switch) {
4358c2ecf20Sopenharmony_ci		printk ("%s(%d): switch delay (should be 32k followed by all 8k\n",
4368c2ecf20Sopenharmony_ci			__func__, fe->dvb->num);
4378c2ecf20Sopenharmony_ci		for (i = 1; i < 10; i++)
4388c2ecf20Sopenharmony_ci			printk("%d: %d\n", i,
4398c2ecf20Sopenharmony_ci			       (int) ktime_us_delta(tv[i], tv[i-1]));
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	return 0;
4438c2ecf20Sopenharmony_ci}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_cistatic int stv0299_init (struct dvb_frontend* fe)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
4488c2ecf20Sopenharmony_ci	int i;
4498c2ecf20Sopenharmony_ci	u8 reg;
4508c2ecf20Sopenharmony_ci	u8 val;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	dprintk("stv0299: init chip\n");
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	stv0299_writeregI(state, 0x02, 0x30 | state->mcr_reg);
4558c2ecf20Sopenharmony_ci	msleep(50);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	for (i = 0; ; i += 2)  {
4588c2ecf20Sopenharmony_ci		reg = state->config->inittab[i];
4598c2ecf20Sopenharmony_ci		val = state->config->inittab[i+1];
4608c2ecf20Sopenharmony_ci		if (reg == 0xff && val == 0xff)
4618c2ecf20Sopenharmony_ci			break;
4628c2ecf20Sopenharmony_ci		if (reg == 0x0c && state->config->op0_off)
4638c2ecf20Sopenharmony_ci			val &= ~0x10;
4648c2ecf20Sopenharmony_ci		if (reg == 0x2)
4658c2ecf20Sopenharmony_ci			state->mcr_reg = val & 0xf;
4668c2ecf20Sopenharmony_ci		stv0299_writeregI(state, reg, val);
4678c2ecf20Sopenharmony_ci	}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	return 0;
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_cistatic int stv0299_read_status(struct dvb_frontend *fe,
4738c2ecf20Sopenharmony_ci			       enum fe_status *status)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	u8 signal = 0xff - stv0299_readreg (state, 0x18);
4788c2ecf20Sopenharmony_ci	u8 sync = stv0299_readreg (state, 0x1b);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync);
4818c2ecf20Sopenharmony_ci	*status = 0;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	if (signal > 10)
4848c2ecf20Sopenharmony_ci		*status |= FE_HAS_SIGNAL;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	if (sync & 0x80)
4878c2ecf20Sopenharmony_ci		*status |= FE_HAS_CARRIER;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	if (sync & 0x10)
4908c2ecf20Sopenharmony_ci		*status |= FE_HAS_VITERBI;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	if (sync & 0x08)
4938c2ecf20Sopenharmony_ci		*status |= FE_HAS_SYNC;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	if ((sync & 0x98) == 0x98)
4968c2ecf20Sopenharmony_ci		*status |= FE_HAS_LOCK;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	return 0;
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_cistatic int stv0299_read_ber(struct dvb_frontend* fe, u32* ber)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	if (state->errmode != STATUS_BER)
5068c2ecf20Sopenharmony_ci		return -ENOSYS;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	*ber = stv0299_readreg(state, 0x1e) | (stv0299_readreg(state, 0x1d) << 8);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	return 0;
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_cistatic int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength)
5148c2ecf20Sopenharmony_ci{
5158c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	s32 signal =  0xffff - ((stv0299_readreg (state, 0x18) << 8)
5188c2ecf20Sopenharmony_ci			       | stv0299_readreg (state, 0x19));
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __func__,
5218c2ecf20Sopenharmony_ci		 stv0299_readreg (state, 0x18),
5228c2ecf20Sopenharmony_ci		 stv0299_readreg (state, 0x19), (int) signal);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	signal = signal * 5 / 4;
5258c2ecf20Sopenharmony_ci	*strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	return 0;
5288c2ecf20Sopenharmony_ci}
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_cistatic int stv0299_read_snr(struct dvb_frontend* fe, u16* snr)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8)
5358c2ecf20Sopenharmony_ci			   | stv0299_readreg (state, 0x25));
5368c2ecf20Sopenharmony_ci	xsnr = 3 * (xsnr - 0xa100);
5378c2ecf20Sopenharmony_ci	*snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	return 0;
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistatic int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	if (state->errmode != STATUS_UCBLOCKS)
5478c2ecf20Sopenharmony_ci		return -ENOSYS;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	state->ucblocks += stv0299_readreg(state, 0x1e);
5508c2ecf20Sopenharmony_ci	state->ucblocks += (stv0299_readreg(state, 0x1d) << 8);
5518c2ecf20Sopenharmony_ci	*ucblocks = state->ucblocks;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	return 0;
5548c2ecf20Sopenharmony_ci}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_cistatic int stv0299_set_frontend(struct dvb_frontend *fe)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
5598c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
5608c2ecf20Sopenharmony_ci	int invval = 0;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	dprintk ("%s : FE_SET_FRONTEND\n", __func__);
5638c2ecf20Sopenharmony_ci	if (state->config->set_ts_params)
5648c2ecf20Sopenharmony_ci		state->config->set_ts_params(fe, 0);
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	// set the inversion
5678c2ecf20Sopenharmony_ci	if (p->inversion == INVERSION_OFF) invval = 0;
5688c2ecf20Sopenharmony_ci	else if (p->inversion == INVERSION_ON) invval = 1;
5698c2ecf20Sopenharmony_ci	else {
5708c2ecf20Sopenharmony_ci		printk("stv0299 does not support auto-inversion\n");
5718c2ecf20Sopenharmony_ci		return -EINVAL;
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci	if (state->config->invert) invval = (~invval) & 1;
5748c2ecf20Sopenharmony_ci	stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	if (fe->ops.tuner_ops.set_params) {
5778c2ecf20Sopenharmony_ci		fe->ops.tuner_ops.set_params(fe);
5788c2ecf20Sopenharmony_ci		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	stv0299_set_FEC(state, p->fec_inner);
5828c2ecf20Sopenharmony_ci	stv0299_set_symbolrate(fe, p->symbol_rate);
5838c2ecf20Sopenharmony_ci	stv0299_writeregI(state, 0x22, 0x00);
5848c2ecf20Sopenharmony_ci	stv0299_writeregI(state, 0x23, 0x00);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	state->tuner_frequency = p->frequency;
5878c2ecf20Sopenharmony_ci	state->fec_inner = p->fec_inner;
5888c2ecf20Sopenharmony_ci	state->symbol_rate = p->symbol_rate;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	return 0;
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_cistatic int stv0299_get_frontend(struct dvb_frontend *fe,
5948c2ecf20Sopenharmony_ci				struct dtv_frontend_properties *p)
5958c2ecf20Sopenharmony_ci{
5968c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
5978c2ecf20Sopenharmony_ci	s32 derot_freq;
5988c2ecf20Sopenharmony_ci	int invval;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	derot_freq = (s32)(s16) ((stv0299_readreg (state, 0x22) << 8)
6018c2ecf20Sopenharmony_ci				| stv0299_readreg (state, 0x23));
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	derot_freq *= (state->config->mclk >> 16);
6048c2ecf20Sopenharmony_ci	derot_freq += 500;
6058c2ecf20Sopenharmony_ci	derot_freq /= 1000;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	p->frequency += derot_freq;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	invval = stv0299_readreg (state, 0x0c) & 1;
6108c2ecf20Sopenharmony_ci	if (state->config->invert) invval = (~invval) & 1;
6118c2ecf20Sopenharmony_ci	p->inversion = invval ? INVERSION_ON : INVERSION_OFF;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	p->fec_inner = stv0299_get_fec(state);
6148c2ecf20Sopenharmony_ci	p->symbol_rate = stv0299_get_symbolrate(state);
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	return 0;
6178c2ecf20Sopenharmony_ci}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_cistatic int stv0299_sleep(struct dvb_frontend* fe)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	stv0299_writeregI(state, 0x02, 0xb0 | state->mcr_reg);
6248c2ecf20Sopenharmony_ci	state->initialised = 0;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	return 0;
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_cistatic int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
6308c2ecf20Sopenharmony_ci{
6318c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	if (enable) {
6348c2ecf20Sopenharmony_ci		stv0299_writeregI(state, 0x05, 0xb5);
6358c2ecf20Sopenharmony_ci	} else {
6368c2ecf20Sopenharmony_ci		stv0299_writeregI(state, 0x05, 0x35);
6378c2ecf20Sopenharmony_ci	}
6388c2ecf20Sopenharmony_ci	udelay(1);
6398c2ecf20Sopenharmony_ci	return 0;
6408c2ecf20Sopenharmony_ci}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_cistatic int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
6438c2ecf20Sopenharmony_ci{
6448c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
6458c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	fesettings->min_delay_ms = state->config->min_delay_ms;
6488c2ecf20Sopenharmony_ci	if (p->symbol_rate < 10000000) {
6498c2ecf20Sopenharmony_ci		fesettings->step_size = p->symbol_rate / 32000;
6508c2ecf20Sopenharmony_ci		fesettings->max_drift = 5000;
6518c2ecf20Sopenharmony_ci	} else {
6528c2ecf20Sopenharmony_ci		fesettings->step_size = p->symbol_rate / 16000;
6538c2ecf20Sopenharmony_ci		fesettings->max_drift = p->symbol_rate / 2000;
6548c2ecf20Sopenharmony_ci	}
6558c2ecf20Sopenharmony_ci	return 0;
6568c2ecf20Sopenharmony_ci}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_cistatic void stv0299_release(struct dvb_frontend* fe)
6598c2ecf20Sopenharmony_ci{
6608c2ecf20Sopenharmony_ci	struct stv0299_state* state = fe->demodulator_priv;
6618c2ecf20Sopenharmony_ci	kfree(state);
6628c2ecf20Sopenharmony_ci}
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops stv0299_ops;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_cistruct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
6678c2ecf20Sopenharmony_ci				    struct i2c_adapter* i2c)
6688c2ecf20Sopenharmony_ci{
6698c2ecf20Sopenharmony_ci	struct stv0299_state* state = NULL;
6708c2ecf20Sopenharmony_ci	int id;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	/* allocate memory for the internal state */
6738c2ecf20Sopenharmony_ci	state = kzalloc(sizeof(struct stv0299_state), GFP_KERNEL);
6748c2ecf20Sopenharmony_ci	if (state == NULL) goto error;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	/* setup the state */
6778c2ecf20Sopenharmony_ci	state->config = config;
6788c2ecf20Sopenharmony_ci	state->i2c = i2c;
6798c2ecf20Sopenharmony_ci	state->initialised = 0;
6808c2ecf20Sopenharmony_ci	state->tuner_frequency = 0;
6818c2ecf20Sopenharmony_ci	state->symbol_rate = 0;
6828c2ecf20Sopenharmony_ci	state->fec_inner = 0;
6838c2ecf20Sopenharmony_ci	state->errmode = STATUS_BER;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	/* check if the demod is there */
6868c2ecf20Sopenharmony_ci	stv0299_writeregI(state, 0x02, 0x30); /* standby off */
6878c2ecf20Sopenharmony_ci	msleep(200);
6888c2ecf20Sopenharmony_ci	id = stv0299_readreg(state, 0x00);
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	/* register 0x00 contains 0xa1 for STV0299 and STV0299B */
6918c2ecf20Sopenharmony_ci	/* register 0x00 might contain 0x80 when returning from standby */
6928c2ecf20Sopenharmony_ci	if (id != 0xa1 && id != 0x80) goto error;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	/* create dvb_frontend */
6958c2ecf20Sopenharmony_ci	memcpy(&state->frontend.ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
6968c2ecf20Sopenharmony_ci	state->frontend.demodulator_priv = state;
6978c2ecf20Sopenharmony_ci	return &state->frontend;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_cierror:
7008c2ecf20Sopenharmony_ci	kfree(state);
7018c2ecf20Sopenharmony_ci	return NULL;
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops stv0299_ops = {
7058c2ecf20Sopenharmony_ci	.delsys = { SYS_DVBS },
7068c2ecf20Sopenharmony_ci	.info = {
7078c2ecf20Sopenharmony_ci		.name			= "ST STV0299 DVB-S",
7088c2ecf20Sopenharmony_ci		.frequency_min_hz	=  950 * MHz,
7098c2ecf20Sopenharmony_ci		.frequency_max_hz	= 2150 * MHz,
7108c2ecf20Sopenharmony_ci		.frequency_stepsize_hz	=  125 * kHz,
7118c2ecf20Sopenharmony_ci		.symbol_rate_min	= 1000000,
7128c2ecf20Sopenharmony_ci		.symbol_rate_max	= 45000000,
7138c2ecf20Sopenharmony_ci		.symbol_rate_tolerance	= 500,	/* ppm */
7148c2ecf20Sopenharmony_ci		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
7158c2ecf20Sopenharmony_ci		      FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
7168c2ecf20Sopenharmony_ci		      FE_CAN_QPSK |
7178c2ecf20Sopenharmony_ci		      FE_CAN_FEC_AUTO
7188c2ecf20Sopenharmony_ci	},
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	.release = stv0299_release,
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	.init = stv0299_init,
7238c2ecf20Sopenharmony_ci	.sleep = stv0299_sleep,
7248c2ecf20Sopenharmony_ci	.write = stv0299_write,
7258c2ecf20Sopenharmony_ci	.i2c_gate_ctrl = stv0299_i2c_gate_ctrl,
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	.set_frontend = stv0299_set_frontend,
7288c2ecf20Sopenharmony_ci	.get_frontend = stv0299_get_frontend,
7298c2ecf20Sopenharmony_ci	.get_tune_settings = stv0299_get_tune_settings,
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	.read_status = stv0299_read_status,
7328c2ecf20Sopenharmony_ci	.read_ber = stv0299_read_ber,
7338c2ecf20Sopenharmony_ci	.read_signal_strength = stv0299_read_signal_strength,
7348c2ecf20Sopenharmony_ci	.read_snr = stv0299_read_snr,
7358c2ecf20Sopenharmony_ci	.read_ucblocks = stv0299_read_ucblocks,
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	.diseqc_send_master_cmd = stv0299_send_diseqc_msg,
7388c2ecf20Sopenharmony_ci	.diseqc_send_burst = stv0299_send_diseqc_burst,
7398c2ecf20Sopenharmony_ci	.set_tone = stv0299_set_tone,
7408c2ecf20Sopenharmony_ci	.set_voltage = stv0299_set_voltage,
7418c2ecf20Sopenharmony_ci	.dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd,
7428c2ecf20Sopenharmony_ci};
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_cimodule_param(debug_legacy_dish_switch, int, 0444);
7458c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug_legacy_dish_switch, "Enable timing analysis for Dish Network legacy switches");
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_cimodule_param(debug, int, 0644);
7488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver");
7518c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, Andreas Oberritter, Andrew de Quincey, Kenneth Aafly");
7528c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(stv0299_attach);
755