18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Driver for the ST STV0910 DVB-S/S2 demodulator.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2014-2015 Ralph Metzler <rjkm@metzlerbros.de>
68c2ecf20Sopenharmony_ci *                         Marcus Metzler <mocm@metzlerbros.de>
78c2ecf20Sopenharmony_ci *                         developed for Digital Devices GmbH
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or
108c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License
118c2ecf20Sopenharmony_ci * version 2 only, as published by the Free Software Foundation.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful,
148c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
158c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
168c2ecf20Sopenharmony_ci * GNU General Public License for more details.
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <linux/kernel.h>
208c2ecf20Sopenharmony_ci#include <linux/module.h>
218c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
228c2ecf20Sopenharmony_ci#include <linux/init.h>
238c2ecf20Sopenharmony_ci#include <linux/delay.h>
248c2ecf20Sopenharmony_ci#include <linux/firmware.h>
258c2ecf20Sopenharmony_ci#include <linux/i2c.h>
268c2ecf20Sopenharmony_ci#include <asm/div64.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h>
298c2ecf20Sopenharmony_ci#include "stv0910.h"
308c2ecf20Sopenharmony_ci#include "stv0910_regs.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define EXT_CLOCK    30000000
338c2ecf20Sopenharmony_ci#define TUNING_DELAY 200
348c2ecf20Sopenharmony_ci#define BER_SRC_S    0x20
358c2ecf20Sopenharmony_ci#define BER_SRC_S2   0x20
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic LIST_HEAD(stvlist);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cienum receive_mode { RCVMODE_NONE, RCVMODE_DVBS, RCVMODE_DVBS2, RCVMODE_AUTO };
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cienum dvbs2_fectype { DVBS2_64K, DVBS2_16K };
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cienum dvbs2_mod_cod {
448c2ecf20Sopenharmony_ci	DVBS2_DUMMY_PLF, DVBS2_QPSK_1_4, DVBS2_QPSK_1_3, DVBS2_QPSK_2_5,
458c2ecf20Sopenharmony_ci	DVBS2_QPSK_1_2, DVBS2_QPSK_3_5, DVBS2_QPSK_2_3,	DVBS2_QPSK_3_4,
468c2ecf20Sopenharmony_ci	DVBS2_QPSK_4_5,	DVBS2_QPSK_5_6,	DVBS2_QPSK_8_9,	DVBS2_QPSK_9_10,
478c2ecf20Sopenharmony_ci	DVBS2_8PSK_3_5,	DVBS2_8PSK_2_3,	DVBS2_8PSK_3_4,	DVBS2_8PSK_5_6,
488c2ecf20Sopenharmony_ci	DVBS2_8PSK_8_9,	DVBS2_8PSK_9_10, DVBS2_16APSK_2_3, DVBS2_16APSK_3_4,
498c2ecf20Sopenharmony_ci	DVBS2_16APSK_4_5, DVBS2_16APSK_5_6, DVBS2_16APSK_8_9, DVBS2_16APSK_9_10,
508c2ecf20Sopenharmony_ci	DVBS2_32APSK_3_4, DVBS2_32APSK_4_5, DVBS2_32APSK_5_6, DVBS2_32APSK_8_9,
518c2ecf20Sopenharmony_ci	DVBS2_32APSK_9_10
528c2ecf20Sopenharmony_ci};
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cienum fe_stv0910_mod_cod {
558c2ecf20Sopenharmony_ci	FE_DUMMY_PLF, FE_QPSK_14, FE_QPSK_13, FE_QPSK_25,
568c2ecf20Sopenharmony_ci	FE_QPSK_12, FE_QPSK_35, FE_QPSK_23, FE_QPSK_34,
578c2ecf20Sopenharmony_ci	FE_QPSK_45, FE_QPSK_56, FE_QPSK_89, FE_QPSK_910,
588c2ecf20Sopenharmony_ci	FE_8PSK_35, FE_8PSK_23, FE_8PSK_34, FE_8PSK_56,
598c2ecf20Sopenharmony_ci	FE_8PSK_89, FE_8PSK_910, FE_16APSK_23, FE_16APSK_34,
608c2ecf20Sopenharmony_ci	FE_16APSK_45, FE_16APSK_56, FE_16APSK_89, FE_16APSK_910,
618c2ecf20Sopenharmony_ci	FE_32APSK_34, FE_32APSK_45, FE_32APSK_56, FE_32APSK_89,
628c2ecf20Sopenharmony_ci	FE_32APSK_910
638c2ecf20Sopenharmony_ci};
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cienum fe_stv0910_roll_off { FE_SAT_35, FE_SAT_25, FE_SAT_20, FE_SAT_15 };
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic inline u32 muldiv32(u32 a, u32 b, u32 c)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	u64 tmp64;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	tmp64 = (u64)a * (u64)b;
728c2ecf20Sopenharmony_ci	do_div(tmp64, c);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	return (u32)tmp64;
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistruct stv_base {
788c2ecf20Sopenharmony_ci	struct list_head     stvlist;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	u8                   adr;
818c2ecf20Sopenharmony_ci	struct i2c_adapter  *i2c;
828c2ecf20Sopenharmony_ci	struct mutex         i2c_lock; /* shared I2C access protect */
838c2ecf20Sopenharmony_ci	struct mutex         reg_lock; /* shared register write protect */
848c2ecf20Sopenharmony_ci	int                  count;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	u32                  extclk;
878c2ecf20Sopenharmony_ci	u32                  mclk;
888c2ecf20Sopenharmony_ci};
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistruct stv {
918c2ecf20Sopenharmony_ci	struct stv_base     *base;
928c2ecf20Sopenharmony_ci	struct dvb_frontend  fe;
938c2ecf20Sopenharmony_ci	int                  nr;
948c2ecf20Sopenharmony_ci	u16                  regoff;
958c2ecf20Sopenharmony_ci	u8                   i2crpt;
968c2ecf20Sopenharmony_ci	u8                   tscfgh;
978c2ecf20Sopenharmony_ci	u8                   tsgeneral;
988c2ecf20Sopenharmony_ci	u8                   tsspeed;
998c2ecf20Sopenharmony_ci	u8                   single;
1008c2ecf20Sopenharmony_ci	unsigned long        tune_time;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	s32                  search_range;
1038c2ecf20Sopenharmony_ci	u32                  started;
1048c2ecf20Sopenharmony_ci	u32                  demod_lock_time;
1058c2ecf20Sopenharmony_ci	enum receive_mode    receive_mode;
1068c2ecf20Sopenharmony_ci	u32                  demod_timeout;
1078c2ecf20Sopenharmony_ci	u32                  fec_timeout;
1088c2ecf20Sopenharmony_ci	u32                  first_time_lock;
1098c2ecf20Sopenharmony_ci	u8                   demod_bits;
1108c2ecf20Sopenharmony_ci	u32                  symbol_rate;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	u8                       last_viterbi_rate;
1138c2ecf20Sopenharmony_ci	enum fe_code_rate        puncture_rate;
1148c2ecf20Sopenharmony_ci	enum fe_stv0910_mod_cod  mod_cod;
1158c2ecf20Sopenharmony_ci	enum dvbs2_fectype       fectype;
1168c2ecf20Sopenharmony_ci	u32                      pilots;
1178c2ecf20Sopenharmony_ci	enum fe_stv0910_roll_off feroll_off;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	int   is_standard_broadcast;
1208c2ecf20Sopenharmony_ci	int   is_vcm;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	u32   cur_scrambling_code;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	u32   last_bernumerator;
1258c2ecf20Sopenharmony_ci	u32   last_berdenominator;
1268c2ecf20Sopenharmony_ci	u8    berscale;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	u8    vth[6];
1298c2ecf20Sopenharmony_ci};
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistruct sinit_table {
1328c2ecf20Sopenharmony_ci	u16  address;
1338c2ecf20Sopenharmony_ci	u8   data;
1348c2ecf20Sopenharmony_ci};
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistruct slookup {
1378c2ecf20Sopenharmony_ci	s16  value;
1388c2ecf20Sopenharmony_ci	u32  reg_value;
1398c2ecf20Sopenharmony_ci};
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic int write_reg(struct stv *state, u16 reg, u8 val)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	struct i2c_adapter *adap = state->base->i2c;
1448c2ecf20Sopenharmony_ci	u8 data[3] = {reg >> 8, reg & 0xff, val};
1458c2ecf20Sopenharmony_ci	struct i2c_msg msg = {.addr = state->base->adr, .flags = 0,
1468c2ecf20Sopenharmony_ci			      .buf = data, .len = 3};
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (i2c_transfer(adap, &msg, 1) != 1) {
1498c2ecf20Sopenharmony_ci		dev_warn(&adap->dev, "i2c write error ([%02x] %04x: %02x)\n",
1508c2ecf20Sopenharmony_ci			 state->base->adr, reg, val);
1518c2ecf20Sopenharmony_ci		return -EIO;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci	return 0;
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic inline int i2c_read_regs16(struct i2c_adapter *adapter, u8 adr,
1578c2ecf20Sopenharmony_ci				  u16 reg, u8 *val, int count)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	u8 msg[2] = {reg >> 8, reg & 0xff};
1608c2ecf20Sopenharmony_ci	struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
1618c2ecf20Sopenharmony_ci				   .buf  = msg, .len   = 2},
1628c2ecf20Sopenharmony_ci				  {.addr = adr, .flags = I2C_M_RD,
1638c2ecf20Sopenharmony_ci				   .buf  = val, .len   = count } };
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	if (i2c_transfer(adapter, msgs, 2) != 2) {
1668c2ecf20Sopenharmony_ci		dev_warn(&adapter->dev, "i2c read error ([%02x] %04x)\n",
1678c2ecf20Sopenharmony_ci			 adr, reg);
1688c2ecf20Sopenharmony_ci		return -EIO;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci	return 0;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic int read_reg(struct stv *state, u16 reg, u8 *val)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	return i2c_read_regs16(state->base->i2c, state->base->adr,
1768c2ecf20Sopenharmony_ci			       reg, val, 1);
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic int read_regs(struct stv *state, u16 reg, u8 *val, int len)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	return i2c_read_regs16(state->base->i2c, state->base->adr,
1828c2ecf20Sopenharmony_ci			       reg, val, len);
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic int write_shared_reg(struct stv *state, u16 reg, u8 mask, u8 val)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	int status;
1888c2ecf20Sopenharmony_ci	u8 tmp;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	mutex_lock(&state->base->reg_lock);
1918c2ecf20Sopenharmony_ci	status = read_reg(state, reg, &tmp);
1928c2ecf20Sopenharmony_ci	if (!status)
1938c2ecf20Sopenharmony_ci		status = write_reg(state, reg, (tmp & ~mask) | (val & mask));
1948c2ecf20Sopenharmony_ci	mutex_unlock(&state->base->reg_lock);
1958c2ecf20Sopenharmony_ci	return status;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic int write_field(struct stv *state, u32 field, u8 val)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	int status;
2018c2ecf20Sopenharmony_ci	u8 shift, mask, old, new;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	status = read_reg(state, field >> 16, &old);
2048c2ecf20Sopenharmony_ci	if (status)
2058c2ecf20Sopenharmony_ci		return status;
2068c2ecf20Sopenharmony_ci	mask = field & 0xff;
2078c2ecf20Sopenharmony_ci	shift = (field >> 12) & 0xf;
2088c2ecf20Sopenharmony_ci	new = ((val << shift) & mask) | (old & ~mask);
2098c2ecf20Sopenharmony_ci	if (new == old)
2108c2ecf20Sopenharmony_ci		return 0;
2118c2ecf20Sopenharmony_ci	return write_reg(state, field >> 16, new);
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci#define SET_FIELD(_reg, _val)					\
2158c2ecf20Sopenharmony_ci	write_field(state, state->nr ? FSTV0910_P2_##_reg :	\
2168c2ecf20Sopenharmony_ci		    FSTV0910_P1_##_reg, _val)
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci#define SET_REG(_reg, _val)					\
2198c2ecf20Sopenharmony_ci	write_reg(state, state->nr ? RSTV0910_P2_##_reg :	\
2208c2ecf20Sopenharmony_ci		  RSTV0910_P1_##_reg, _val)
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci#define GET_REG(_reg, _val)					\
2238c2ecf20Sopenharmony_ci	read_reg(state, state->nr ? RSTV0910_P2_##_reg :	\
2248c2ecf20Sopenharmony_ci		 RSTV0910_P1_##_reg, _val)
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic const struct slookup s1_sn_lookup[] = {
2278c2ecf20Sopenharmony_ci	{   0,    9242  }, /* C/N=   0dB */
2288c2ecf20Sopenharmony_ci	{   5,    9105  }, /* C/N= 0.5dB */
2298c2ecf20Sopenharmony_ci	{  10,    8950  }, /* C/N= 1.0dB */
2308c2ecf20Sopenharmony_ci	{  15,    8780  }, /* C/N= 1.5dB */
2318c2ecf20Sopenharmony_ci	{  20,    8566  }, /* C/N= 2.0dB */
2328c2ecf20Sopenharmony_ci	{  25,    8366  }, /* C/N= 2.5dB */
2338c2ecf20Sopenharmony_ci	{  30,    8146  }, /* C/N= 3.0dB */
2348c2ecf20Sopenharmony_ci	{  35,    7908  }, /* C/N= 3.5dB */
2358c2ecf20Sopenharmony_ci	{  40,    7666  }, /* C/N= 4.0dB */
2368c2ecf20Sopenharmony_ci	{  45,    7405  }, /* C/N= 4.5dB */
2378c2ecf20Sopenharmony_ci	{  50,    7136  }, /* C/N= 5.0dB */
2388c2ecf20Sopenharmony_ci	{  55,    6861  }, /* C/N= 5.5dB */
2398c2ecf20Sopenharmony_ci	{  60,    6576  }, /* C/N= 6.0dB */
2408c2ecf20Sopenharmony_ci	{  65,    6330  }, /* C/N= 6.5dB */
2418c2ecf20Sopenharmony_ci	{  70,    6048  }, /* C/N= 7.0dB */
2428c2ecf20Sopenharmony_ci	{  75,    5768  }, /* C/N= 7.5dB */
2438c2ecf20Sopenharmony_ci	{  80,    5492  }, /* C/N= 8.0dB */
2448c2ecf20Sopenharmony_ci	{  85,    5224  }, /* C/N= 8.5dB */
2458c2ecf20Sopenharmony_ci	{  90,    4959  }, /* C/N= 9.0dB */
2468c2ecf20Sopenharmony_ci	{  95,    4709  }, /* C/N= 9.5dB */
2478c2ecf20Sopenharmony_ci	{  100,   4467  }, /* C/N=10.0dB */
2488c2ecf20Sopenharmony_ci	{  105,   4236  }, /* C/N=10.5dB */
2498c2ecf20Sopenharmony_ci	{  110,   4013  }, /* C/N=11.0dB */
2508c2ecf20Sopenharmony_ci	{  115,   3800  }, /* C/N=11.5dB */
2518c2ecf20Sopenharmony_ci	{  120,   3598  }, /* C/N=12.0dB */
2528c2ecf20Sopenharmony_ci	{  125,   3406  }, /* C/N=12.5dB */
2538c2ecf20Sopenharmony_ci	{  130,   3225  }, /* C/N=13.0dB */
2548c2ecf20Sopenharmony_ci	{  135,   3052  }, /* C/N=13.5dB */
2558c2ecf20Sopenharmony_ci	{  140,   2889  }, /* C/N=14.0dB */
2568c2ecf20Sopenharmony_ci	{  145,   2733  }, /* C/N=14.5dB */
2578c2ecf20Sopenharmony_ci	{  150,   2587  }, /* C/N=15.0dB */
2588c2ecf20Sopenharmony_ci	{  160,   2318  }, /* C/N=16.0dB */
2598c2ecf20Sopenharmony_ci	{  170,   2077  }, /* C/N=17.0dB */
2608c2ecf20Sopenharmony_ci	{  180,   1862  }, /* C/N=18.0dB */
2618c2ecf20Sopenharmony_ci	{  190,   1670  }, /* C/N=19.0dB */
2628c2ecf20Sopenharmony_ci	{  200,   1499  }, /* C/N=20.0dB */
2638c2ecf20Sopenharmony_ci	{  210,   1347  }, /* C/N=21.0dB */
2648c2ecf20Sopenharmony_ci	{  220,   1213  }, /* C/N=22.0dB */
2658c2ecf20Sopenharmony_ci	{  230,   1095  }, /* C/N=23.0dB */
2668c2ecf20Sopenharmony_ci	{  240,    992  }, /* C/N=24.0dB */
2678c2ecf20Sopenharmony_ci	{  250,    900  }, /* C/N=25.0dB */
2688c2ecf20Sopenharmony_ci	{  260,    826  }, /* C/N=26.0dB */
2698c2ecf20Sopenharmony_ci	{  270,    758  }, /* C/N=27.0dB */
2708c2ecf20Sopenharmony_ci	{  280,    702  }, /* C/N=28.0dB */
2718c2ecf20Sopenharmony_ci	{  290,    653  }, /* C/N=29.0dB */
2728c2ecf20Sopenharmony_ci	{  300,    613  }, /* C/N=30.0dB */
2738c2ecf20Sopenharmony_ci	{  310,    579  }, /* C/N=31.0dB */
2748c2ecf20Sopenharmony_ci	{  320,    550  }, /* C/N=32.0dB */
2758c2ecf20Sopenharmony_ci	{  330,    526  }, /* C/N=33.0dB */
2768c2ecf20Sopenharmony_ci	{  350,    490  }, /* C/N=33.0dB */
2778c2ecf20Sopenharmony_ci	{  400,    445  }, /* C/N=40.0dB */
2788c2ecf20Sopenharmony_ci	{  450,    430  }, /* C/N=45.0dB */
2798c2ecf20Sopenharmony_ci	{  500,    426  }, /* C/N=50.0dB */
2808c2ecf20Sopenharmony_ci	{  510,    425  }  /* C/N=51.0dB */
2818c2ecf20Sopenharmony_ci};
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic const struct slookup s2_sn_lookup[] = {
2848c2ecf20Sopenharmony_ci	{  -30,  13950  }, /* C/N=-2.5dB */
2858c2ecf20Sopenharmony_ci	{  -25,  13580  }, /* C/N=-2.5dB */
2868c2ecf20Sopenharmony_ci	{  -20,  13150  }, /* C/N=-2.0dB */
2878c2ecf20Sopenharmony_ci	{  -15,  12760  }, /* C/N=-1.5dB */
2888c2ecf20Sopenharmony_ci	{  -10,  12345  }, /* C/N=-1.0dB */
2898c2ecf20Sopenharmony_ci	{   -5,  11900  }, /* C/N=-0.5dB */
2908c2ecf20Sopenharmony_ci	{    0,  11520  }, /* C/N=   0dB */
2918c2ecf20Sopenharmony_ci	{    5,  11080  }, /* C/N= 0.5dB */
2928c2ecf20Sopenharmony_ci	{   10,  10630  }, /* C/N= 1.0dB */
2938c2ecf20Sopenharmony_ci	{   15,  10210  }, /* C/N= 1.5dB */
2948c2ecf20Sopenharmony_ci	{   20,   9790  }, /* C/N= 2.0dB */
2958c2ecf20Sopenharmony_ci	{   25,   9390  }, /* C/N= 2.5dB */
2968c2ecf20Sopenharmony_ci	{   30,   8970  }, /* C/N= 3.0dB */
2978c2ecf20Sopenharmony_ci	{   35,   8575  }, /* C/N= 3.5dB */
2988c2ecf20Sopenharmony_ci	{   40,   8180  }, /* C/N= 4.0dB */
2998c2ecf20Sopenharmony_ci	{   45,   7800  }, /* C/N= 4.5dB */
3008c2ecf20Sopenharmony_ci	{   50,   7430  }, /* C/N= 5.0dB */
3018c2ecf20Sopenharmony_ci	{   55,   7080  }, /* C/N= 5.5dB */
3028c2ecf20Sopenharmony_ci	{   60,   6720  }, /* C/N= 6.0dB */
3038c2ecf20Sopenharmony_ci	{   65,   6320  }, /* C/N= 6.5dB */
3048c2ecf20Sopenharmony_ci	{   70,   6060  }, /* C/N= 7.0dB */
3058c2ecf20Sopenharmony_ci	{   75,   5760  }, /* C/N= 7.5dB */
3068c2ecf20Sopenharmony_ci	{   80,   5480  }, /* C/N= 8.0dB */
3078c2ecf20Sopenharmony_ci	{   85,   5200  }, /* C/N= 8.5dB */
3088c2ecf20Sopenharmony_ci	{   90,   4930  }, /* C/N= 9.0dB */
3098c2ecf20Sopenharmony_ci	{   95,   4680  }, /* C/N= 9.5dB */
3108c2ecf20Sopenharmony_ci	{  100,   4425  }, /* C/N=10.0dB */
3118c2ecf20Sopenharmony_ci	{  105,   4210  }, /* C/N=10.5dB */
3128c2ecf20Sopenharmony_ci	{  110,   3980  }, /* C/N=11.0dB */
3138c2ecf20Sopenharmony_ci	{  115,   3765  }, /* C/N=11.5dB */
3148c2ecf20Sopenharmony_ci	{  120,   3570  }, /* C/N=12.0dB */
3158c2ecf20Sopenharmony_ci	{  125,   3315  }, /* C/N=12.5dB */
3168c2ecf20Sopenharmony_ci	{  130,   3140  }, /* C/N=13.0dB */
3178c2ecf20Sopenharmony_ci	{  135,   2980  }, /* C/N=13.5dB */
3188c2ecf20Sopenharmony_ci	{  140,   2820  }, /* C/N=14.0dB */
3198c2ecf20Sopenharmony_ci	{  145,   2670  }, /* C/N=14.5dB */
3208c2ecf20Sopenharmony_ci	{  150,   2535  }, /* C/N=15.0dB */
3218c2ecf20Sopenharmony_ci	{  160,   2270  }, /* C/N=16.0dB */
3228c2ecf20Sopenharmony_ci	{  170,   2035  }, /* C/N=17.0dB */
3238c2ecf20Sopenharmony_ci	{  180,   1825  }, /* C/N=18.0dB */
3248c2ecf20Sopenharmony_ci	{  190,   1650  }, /* C/N=19.0dB */
3258c2ecf20Sopenharmony_ci	{  200,   1485  }, /* C/N=20.0dB */
3268c2ecf20Sopenharmony_ci	{  210,   1340  }, /* C/N=21.0dB */
3278c2ecf20Sopenharmony_ci	{  220,   1212  }, /* C/N=22.0dB */
3288c2ecf20Sopenharmony_ci	{  230,   1100  }, /* C/N=23.0dB */
3298c2ecf20Sopenharmony_ci	{  240,   1000  }, /* C/N=24.0dB */
3308c2ecf20Sopenharmony_ci	{  250,    910  }, /* C/N=25.0dB */
3318c2ecf20Sopenharmony_ci	{  260,    836  }, /* C/N=26.0dB */
3328c2ecf20Sopenharmony_ci	{  270,    772  }, /* C/N=27.0dB */
3338c2ecf20Sopenharmony_ci	{  280,    718  }, /* C/N=28.0dB */
3348c2ecf20Sopenharmony_ci	{  290,    671  }, /* C/N=29.0dB */
3358c2ecf20Sopenharmony_ci	{  300,    635  }, /* C/N=30.0dB */
3368c2ecf20Sopenharmony_ci	{  310,    602  }, /* C/N=31.0dB */
3378c2ecf20Sopenharmony_ci	{  320,    575  }, /* C/N=32.0dB */
3388c2ecf20Sopenharmony_ci	{  330,    550  }, /* C/N=33.0dB */
3398c2ecf20Sopenharmony_ci	{  350,    517  }, /* C/N=35.0dB */
3408c2ecf20Sopenharmony_ci	{  400,    480  }, /* C/N=40.0dB */
3418c2ecf20Sopenharmony_ci	{  450,    466  }, /* C/N=45.0dB */
3428c2ecf20Sopenharmony_ci	{  500,    464  }, /* C/N=50.0dB */
3438c2ecf20Sopenharmony_ci	{  510,    463  }, /* C/N=51.0dB */
3448c2ecf20Sopenharmony_ci};
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic const struct slookup padc_lookup[] = {
3478c2ecf20Sopenharmony_ci	{    0,  118000 }, /* PADC= +0dBm */
3488c2ecf20Sopenharmony_ci	{ -100,  93600  }, /* PADC= -1dBm */
3498c2ecf20Sopenharmony_ci	{ -200,  74500  }, /* PADC= -2dBm */
3508c2ecf20Sopenharmony_ci	{ -300,  59100  }, /* PADC= -3dBm */
3518c2ecf20Sopenharmony_ci	{ -400,  47000  }, /* PADC= -4dBm */
3528c2ecf20Sopenharmony_ci	{ -500,  37300  }, /* PADC= -5dBm */
3538c2ecf20Sopenharmony_ci	{ -600,  29650  }, /* PADC= -6dBm */
3548c2ecf20Sopenharmony_ci	{ -700,  23520  }, /* PADC= -7dBm */
3558c2ecf20Sopenharmony_ci	{ -900,  14850  }, /* PADC= -9dBm */
3568c2ecf20Sopenharmony_ci	{ -1100, 9380   }, /* PADC=-11dBm */
3578c2ecf20Sopenharmony_ci	{ -1300, 5910   }, /* PADC=-13dBm */
3588c2ecf20Sopenharmony_ci	{ -1500, 3730   }, /* PADC=-15dBm */
3598c2ecf20Sopenharmony_ci	{ -1700, 2354   }, /* PADC=-17dBm */
3608c2ecf20Sopenharmony_ci	{ -1900, 1485   }, /* PADC=-19dBm */
3618c2ecf20Sopenharmony_ci	{ -2000, 1179   }, /* PADC=-20dBm */
3628c2ecf20Sopenharmony_ci	{ -2100, 1000   }, /* PADC=-21dBm */
3638c2ecf20Sopenharmony_ci};
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci/*********************************************************************
3668c2ecf20Sopenharmony_ci * Tracking carrier loop carrier QPSK 1/4 to 8PSK 9/10 long Frame
3678c2ecf20Sopenharmony_ci *********************************************************************/
3688c2ecf20Sopenharmony_cistatic const u8 s2car_loop[] =	{
3698c2ecf20Sopenharmony_ci	/*
3708c2ecf20Sopenharmony_ci	 * Modcod  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff
3718c2ecf20Sopenharmony_ci	 * 20MPon 20MPoff 30MPon 30MPoff
3728c2ecf20Sopenharmony_ci	 */
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	/* FE_QPSK_14  */
3758c2ecf20Sopenharmony_ci	0x0C,  0x3C,  0x0B,  0x3C,  0x2A,  0x2C,  0x2A,  0x1C,  0x3A,  0x3B,
3768c2ecf20Sopenharmony_ci	/* FE_QPSK_13  */
3778c2ecf20Sopenharmony_ci	0x0C,  0x3C,  0x0B,  0x3C,  0x2A,  0x2C,  0x3A,  0x0C,  0x3A,  0x2B,
3788c2ecf20Sopenharmony_ci	/* FE_QPSK_25  */
3798c2ecf20Sopenharmony_ci	0x1C,  0x3C,  0x1B,  0x3C,  0x3A,  0x1C,  0x3A,  0x3B,  0x3A,  0x2B,
3808c2ecf20Sopenharmony_ci	/* FE_QPSK_12  */
3818c2ecf20Sopenharmony_ci	0x0C,  0x1C,  0x2B,  0x1C,  0x0B,  0x2C,  0x0B,  0x0C,  0x2A,  0x2B,
3828c2ecf20Sopenharmony_ci	/* FE_QPSK_35  */
3838c2ecf20Sopenharmony_ci	0x1C,  0x1C,  0x2B,  0x1C,  0x0B,  0x2C,  0x0B,  0x0C,  0x2A,  0x2B,
3848c2ecf20Sopenharmony_ci	/* FE_QPSK_23  */
3858c2ecf20Sopenharmony_ci	0x2C,  0x2C,  0x2B,  0x1C,  0x0B,  0x2C,  0x0B,  0x0C,  0x2A,  0x2B,
3868c2ecf20Sopenharmony_ci	/* FE_QPSK_34  */
3878c2ecf20Sopenharmony_ci	0x3C,  0x2C,  0x3B,  0x2C,  0x1B,  0x1C,  0x1B,  0x3B,  0x3A,  0x1B,
3888c2ecf20Sopenharmony_ci	/* FE_QPSK_45  */
3898c2ecf20Sopenharmony_ci	0x0D,  0x3C,  0x3B,  0x2C,  0x1B,  0x1C,  0x1B,  0x3B,  0x3A,  0x1B,
3908c2ecf20Sopenharmony_ci	/* FE_QPSK_56  */
3918c2ecf20Sopenharmony_ci	0x1D,  0x3C,  0x0C,  0x2C,  0x2B,  0x1C,  0x1B,  0x3B,  0x0B,  0x1B,
3928c2ecf20Sopenharmony_ci	/* FE_QPSK_89  */
3938c2ecf20Sopenharmony_ci	0x3D,  0x0D,  0x0C,  0x2C,  0x2B,  0x0C,  0x2B,  0x2B,  0x0B,  0x0B,
3948c2ecf20Sopenharmony_ci	/* FE_QPSK_910 */
3958c2ecf20Sopenharmony_ci	0x1E,  0x0D,  0x1C,  0x2C,  0x3B,  0x0C,  0x2B,  0x2B,  0x1B,  0x0B,
3968c2ecf20Sopenharmony_ci	/* FE_8PSK_35  */
3978c2ecf20Sopenharmony_ci	0x28,  0x09,  0x28,  0x09,  0x28,  0x09,  0x28,  0x08,  0x28,  0x27,
3988c2ecf20Sopenharmony_ci	/* FE_8PSK_23  */
3998c2ecf20Sopenharmony_ci	0x19,  0x29,  0x19,  0x29,  0x19,  0x29,  0x38,  0x19,  0x28,  0x09,
4008c2ecf20Sopenharmony_ci	/* FE_8PSK_34  */
4018c2ecf20Sopenharmony_ci	0x1A,  0x0B,  0x1A,  0x3A,  0x0A,  0x2A,  0x39,  0x2A,  0x39,  0x1A,
4028c2ecf20Sopenharmony_ci	/* FE_8PSK_56  */
4038c2ecf20Sopenharmony_ci	0x2B,  0x2B,  0x1B,  0x1B,  0x0B,  0x1B,  0x1A,  0x0B,  0x1A,  0x1A,
4048c2ecf20Sopenharmony_ci	/* FE_8PSK_89  */
4058c2ecf20Sopenharmony_ci	0x0C,  0x0C,  0x3B,  0x3B,  0x1B,  0x1B,  0x2A,  0x0B,  0x2A,  0x2A,
4068c2ecf20Sopenharmony_ci	/* FE_8PSK_910 */
4078c2ecf20Sopenharmony_ci	0x0C,  0x1C,  0x0C,  0x3B,  0x2B,  0x1B,  0x3A,  0x0B,  0x2A,  0x2A,
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/**********************************************************************
4108c2ecf20Sopenharmony_ci	 * Tracking carrier loop carrier 16APSK 2/3 to 32APSK 9/10 long Frame
4118c2ecf20Sopenharmony_ci	 **********************************************************************/
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	/*
4148c2ecf20Sopenharmony_ci	 * Modcod 2MPon  2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon
4158c2ecf20Sopenharmony_ci	 * 20MPoff 30MPon 30MPoff
4168c2ecf20Sopenharmony_ci	 */
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	/* FE_16APSK_23  */
4198c2ecf20Sopenharmony_ci	0x0A,  0x0A,  0x0A,  0x0A,  0x1A,  0x0A,  0x39,  0x0A,  0x29,  0x0A,
4208c2ecf20Sopenharmony_ci	/* FE_16APSK_34  */
4218c2ecf20Sopenharmony_ci	0x0A,  0x0A,  0x0A,  0x0A,  0x0B,  0x0A,  0x2A,  0x0A,  0x1A,  0x0A,
4228c2ecf20Sopenharmony_ci	/* FE_16APSK_45  */
4238c2ecf20Sopenharmony_ci	0x0A,  0x0A,  0x0A,  0x0A,  0x1B,  0x0A,  0x3A,  0x0A,  0x2A,  0x0A,
4248c2ecf20Sopenharmony_ci	/* FE_16APSK_56  */
4258c2ecf20Sopenharmony_ci	0x0A,  0x0A,  0x0A,  0x0A,  0x1B,  0x0A,  0x3A,  0x0A,  0x2A,  0x0A,
4268c2ecf20Sopenharmony_ci	/* FE_16APSK_89  */
4278c2ecf20Sopenharmony_ci	0x0A,  0x0A,  0x0A,  0x0A,  0x2B,  0x0A,  0x0B,  0x0A,  0x3A,  0x0A,
4288c2ecf20Sopenharmony_ci	/* FE_16APSK_910 */
4298c2ecf20Sopenharmony_ci	0x0A,  0x0A,  0x0A,  0x0A,  0x2B,  0x0A,  0x0B,  0x0A,  0x3A,  0x0A,
4308c2ecf20Sopenharmony_ci	/* FE_32APSK_34  */
4318c2ecf20Sopenharmony_ci	0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,
4328c2ecf20Sopenharmony_ci	/* FE_32APSK_45  */
4338c2ecf20Sopenharmony_ci	0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,
4348c2ecf20Sopenharmony_ci	/* FE_32APSK_56  */
4358c2ecf20Sopenharmony_ci	0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,
4368c2ecf20Sopenharmony_ci	/* FE_32APSK_89  */
4378c2ecf20Sopenharmony_ci	0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,
4388c2ecf20Sopenharmony_ci	/* FE_32APSK_910 */
4398c2ecf20Sopenharmony_ci	0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,  0x09,
4408c2ecf20Sopenharmony_ci};
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic u8 get_optim_cloop(struct stv *state,
4438c2ecf20Sopenharmony_ci			  enum fe_stv0910_mod_cod mod_cod, u32 pilots)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	int i = 0;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	if (mod_cod >= FE_32APSK_910)
4488c2ecf20Sopenharmony_ci		i = ((int)FE_32APSK_910 - (int)FE_QPSK_14) * 10;
4498c2ecf20Sopenharmony_ci	else if (mod_cod >= FE_QPSK_14)
4508c2ecf20Sopenharmony_ci		i = ((int)mod_cod - (int)FE_QPSK_14) * 10;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	if (state->symbol_rate <= 3000000)
4538c2ecf20Sopenharmony_ci		i += 0;
4548c2ecf20Sopenharmony_ci	else if (state->symbol_rate <=  7000000)
4558c2ecf20Sopenharmony_ci		i += 2;
4568c2ecf20Sopenharmony_ci	else if (state->symbol_rate <= 15000000)
4578c2ecf20Sopenharmony_ci		i += 4;
4588c2ecf20Sopenharmony_ci	else if (state->symbol_rate <= 25000000)
4598c2ecf20Sopenharmony_ci		i += 6;
4608c2ecf20Sopenharmony_ci	else
4618c2ecf20Sopenharmony_ci		i += 8;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	if (!pilots)
4648c2ecf20Sopenharmony_ci		i += 1;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	return s2car_loop[i];
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic int get_cur_symbol_rate(struct stv *state, u32 *p_symbol_rate)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	int status = 0;
4728c2ecf20Sopenharmony_ci	u8 symb_freq0;
4738c2ecf20Sopenharmony_ci	u8 symb_freq1;
4748c2ecf20Sopenharmony_ci	u8 symb_freq2;
4758c2ecf20Sopenharmony_ci	u8 symb_freq3;
4768c2ecf20Sopenharmony_ci	u8 tim_offs0;
4778c2ecf20Sopenharmony_ci	u8 tim_offs1;
4788c2ecf20Sopenharmony_ci	u8 tim_offs2;
4798c2ecf20Sopenharmony_ci	u32 symbol_rate;
4808c2ecf20Sopenharmony_ci	s32 timing_offset;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	*p_symbol_rate = 0;
4838c2ecf20Sopenharmony_ci	if (!state->started)
4848c2ecf20Sopenharmony_ci		return status;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	read_reg(state, RSTV0910_P2_SFR3 + state->regoff, &symb_freq3);
4878c2ecf20Sopenharmony_ci	read_reg(state, RSTV0910_P2_SFR2 + state->regoff, &symb_freq2);
4888c2ecf20Sopenharmony_ci	read_reg(state, RSTV0910_P2_SFR1 + state->regoff, &symb_freq1);
4898c2ecf20Sopenharmony_ci	read_reg(state, RSTV0910_P2_SFR0 + state->regoff, &symb_freq0);
4908c2ecf20Sopenharmony_ci	read_reg(state, RSTV0910_P2_TMGREG2 + state->regoff, &tim_offs2);
4918c2ecf20Sopenharmony_ci	read_reg(state, RSTV0910_P2_TMGREG1 + state->regoff, &tim_offs1);
4928c2ecf20Sopenharmony_ci	read_reg(state, RSTV0910_P2_TMGREG0 + state->regoff, &tim_offs0);
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	symbol_rate = ((u32)symb_freq3 << 24) | ((u32)symb_freq2 << 16) |
4958c2ecf20Sopenharmony_ci		((u32)symb_freq1 << 8) | (u32)symb_freq0;
4968c2ecf20Sopenharmony_ci	timing_offset = ((u32)tim_offs2 << 16) | ((u32)tim_offs1 << 8) |
4978c2ecf20Sopenharmony_ci		(u32)tim_offs0;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if ((timing_offset & (1 << 23)) != 0)
5008c2ecf20Sopenharmony_ci		timing_offset |= 0xFF000000; /* Sign extent */
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	symbol_rate = (u32)(((u64)symbol_rate * state->base->mclk) >> 32);
5038c2ecf20Sopenharmony_ci	timing_offset = (s32)(((s64)symbol_rate * (s64)timing_offset) >> 29);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	*p_symbol_rate = symbol_rate + timing_offset;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	return 0;
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic int get_signal_parameters(struct stv *state)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	u8 tmp;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	if (!state->started)
5158c2ecf20Sopenharmony_ci		return -EINVAL;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	if (state->receive_mode == RCVMODE_DVBS2) {
5188c2ecf20Sopenharmony_ci		read_reg(state, RSTV0910_P2_DMDMODCOD + state->regoff, &tmp);
5198c2ecf20Sopenharmony_ci		state->mod_cod = (enum fe_stv0910_mod_cod)((tmp & 0x7c) >> 2);
5208c2ecf20Sopenharmony_ci		state->pilots = (tmp & 0x01) != 0;
5218c2ecf20Sopenharmony_ci		state->fectype = (enum dvbs2_fectype)((tmp & 0x02) >> 1);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	} else if (state->receive_mode == RCVMODE_DVBS) {
5248c2ecf20Sopenharmony_ci		read_reg(state, RSTV0910_P2_VITCURPUN + state->regoff, &tmp);
5258c2ecf20Sopenharmony_ci		state->puncture_rate = FEC_NONE;
5268c2ecf20Sopenharmony_ci		switch (tmp & 0x1F) {
5278c2ecf20Sopenharmony_ci		case 0x0d:
5288c2ecf20Sopenharmony_ci			state->puncture_rate = FEC_1_2;
5298c2ecf20Sopenharmony_ci			break;
5308c2ecf20Sopenharmony_ci		case 0x12:
5318c2ecf20Sopenharmony_ci			state->puncture_rate = FEC_2_3;
5328c2ecf20Sopenharmony_ci			break;
5338c2ecf20Sopenharmony_ci		case 0x15:
5348c2ecf20Sopenharmony_ci			state->puncture_rate = FEC_3_4;
5358c2ecf20Sopenharmony_ci			break;
5368c2ecf20Sopenharmony_ci		case 0x18:
5378c2ecf20Sopenharmony_ci			state->puncture_rate = FEC_5_6;
5388c2ecf20Sopenharmony_ci			break;
5398c2ecf20Sopenharmony_ci		case 0x1a:
5408c2ecf20Sopenharmony_ci			state->puncture_rate = FEC_7_8;
5418c2ecf20Sopenharmony_ci			break;
5428c2ecf20Sopenharmony_ci		}
5438c2ecf20Sopenharmony_ci		state->is_vcm = 0;
5448c2ecf20Sopenharmony_ci		state->is_standard_broadcast = 1;
5458c2ecf20Sopenharmony_ci		state->feroll_off = FE_SAT_35;
5468c2ecf20Sopenharmony_ci	}
5478c2ecf20Sopenharmony_ci	return 0;
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_cistatic int tracking_optimization(struct stv *state)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci	u8 tmp;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	read_reg(state, RSTV0910_P2_DMDCFGMD + state->regoff, &tmp);
5558c2ecf20Sopenharmony_ci	tmp &= ~0xC0;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	switch (state->receive_mode) {
5588c2ecf20Sopenharmony_ci	case RCVMODE_DVBS:
5598c2ecf20Sopenharmony_ci		tmp |= 0x40;
5608c2ecf20Sopenharmony_ci		break;
5618c2ecf20Sopenharmony_ci	case RCVMODE_DVBS2:
5628c2ecf20Sopenharmony_ci		tmp |= 0x80;
5638c2ecf20Sopenharmony_ci		break;
5648c2ecf20Sopenharmony_ci	default:
5658c2ecf20Sopenharmony_ci		tmp |= 0xC0;
5668c2ecf20Sopenharmony_ci		break;
5678c2ecf20Sopenharmony_ci	}
5688c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_DMDCFGMD + state->regoff, tmp);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	if (state->receive_mode == RCVMODE_DVBS2) {
5718c2ecf20Sopenharmony_ci		/* Disable Reed-Solomon */
5728c2ecf20Sopenharmony_ci		write_shared_reg(state,
5738c2ecf20Sopenharmony_ci				 RSTV0910_TSTTSRS, state->nr ? 0x02 : 0x01,
5748c2ecf20Sopenharmony_ci				 0x03);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci		if (state->fectype == DVBS2_64K) {
5778c2ecf20Sopenharmony_ci			u8 aclc = get_optim_cloop(state, state->mod_cod,
5788c2ecf20Sopenharmony_ci						  state->pilots);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci			if (state->mod_cod <= FE_QPSK_910) {
5818c2ecf20Sopenharmony_ci				write_reg(state, RSTV0910_P2_ACLC2S2Q +
5828c2ecf20Sopenharmony_ci					  state->regoff, aclc);
5838c2ecf20Sopenharmony_ci			} else if (state->mod_cod <= FE_8PSK_910) {
5848c2ecf20Sopenharmony_ci				write_reg(state, RSTV0910_P2_ACLC2S2Q +
5858c2ecf20Sopenharmony_ci					  state->regoff, 0x2a);
5868c2ecf20Sopenharmony_ci				write_reg(state, RSTV0910_P2_ACLC2S28 +
5878c2ecf20Sopenharmony_ci					  state->regoff, aclc);
5888c2ecf20Sopenharmony_ci			} else if (state->mod_cod <= FE_16APSK_910) {
5898c2ecf20Sopenharmony_ci				write_reg(state, RSTV0910_P2_ACLC2S2Q +
5908c2ecf20Sopenharmony_ci					  state->regoff, 0x2a);
5918c2ecf20Sopenharmony_ci				write_reg(state, RSTV0910_P2_ACLC2S216A +
5928c2ecf20Sopenharmony_ci					  state->regoff, aclc);
5938c2ecf20Sopenharmony_ci			} else if (state->mod_cod <= FE_32APSK_910) {
5948c2ecf20Sopenharmony_ci				write_reg(state, RSTV0910_P2_ACLC2S2Q +
5958c2ecf20Sopenharmony_ci					  state->regoff, 0x2a);
5968c2ecf20Sopenharmony_ci				write_reg(state, RSTV0910_P2_ACLC2S232A +
5978c2ecf20Sopenharmony_ci					  state->regoff, aclc);
5988c2ecf20Sopenharmony_ci			}
5998c2ecf20Sopenharmony_ci		}
6008c2ecf20Sopenharmony_ci	}
6018c2ecf20Sopenharmony_ci	return 0;
6028c2ecf20Sopenharmony_ci}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_cistatic s32 table_lookup(const struct slookup *table,
6058c2ecf20Sopenharmony_ci			int table_size, u32 reg_value)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	s32 value;
6088c2ecf20Sopenharmony_ci	int imin = 0;
6098c2ecf20Sopenharmony_ci	int imax = table_size - 1;
6108c2ecf20Sopenharmony_ci	int i;
6118c2ecf20Sopenharmony_ci	s32 reg_diff;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	/* Assumes Table[0].RegValue > Table[imax].RegValue */
6148c2ecf20Sopenharmony_ci	if (reg_value >= table[0].reg_value) {
6158c2ecf20Sopenharmony_ci		value = table[0].value;
6168c2ecf20Sopenharmony_ci	} else if (reg_value <= table[imax].reg_value) {
6178c2ecf20Sopenharmony_ci		value = table[imax].value;
6188c2ecf20Sopenharmony_ci	} else {
6198c2ecf20Sopenharmony_ci		while ((imax - imin) > 1) {
6208c2ecf20Sopenharmony_ci			i = (imax + imin) / 2;
6218c2ecf20Sopenharmony_ci			if ((table[imin].reg_value >= reg_value) &&
6228c2ecf20Sopenharmony_ci			    (reg_value >= table[i].reg_value))
6238c2ecf20Sopenharmony_ci				imax = i;
6248c2ecf20Sopenharmony_ci			else
6258c2ecf20Sopenharmony_ci				imin = i;
6268c2ecf20Sopenharmony_ci		}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci		reg_diff = table[imax].reg_value - table[imin].reg_value;
6298c2ecf20Sopenharmony_ci		value = table[imin].value;
6308c2ecf20Sopenharmony_ci		if (reg_diff != 0)
6318c2ecf20Sopenharmony_ci			value += ((s32)(reg_value - table[imin].reg_value) *
6328c2ecf20Sopenharmony_ci				  (s32)(table[imax].value
6338c2ecf20Sopenharmony_ci					- table[imin].value))
6348c2ecf20Sopenharmony_ci					/ (reg_diff);
6358c2ecf20Sopenharmony_ci	}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	return value;
6388c2ecf20Sopenharmony_ci}
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_cistatic int get_signal_to_noise(struct stv *state, s32 *signal_to_noise)
6418c2ecf20Sopenharmony_ci{
6428c2ecf20Sopenharmony_ci	u8 data0;
6438c2ecf20Sopenharmony_ci	u8 data1;
6448c2ecf20Sopenharmony_ci	u16 data;
6458c2ecf20Sopenharmony_ci	int n_lookup;
6468c2ecf20Sopenharmony_ci	const struct slookup *lookup;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	*signal_to_noise = 0;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	if (!state->started)
6518c2ecf20Sopenharmony_ci		return -EINVAL;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	if (state->receive_mode == RCVMODE_DVBS2) {
6548c2ecf20Sopenharmony_ci		read_reg(state, RSTV0910_P2_NNOSPLHT1 + state->regoff,
6558c2ecf20Sopenharmony_ci			 &data1);
6568c2ecf20Sopenharmony_ci		read_reg(state, RSTV0910_P2_NNOSPLHT0 + state->regoff,
6578c2ecf20Sopenharmony_ci			 &data0);
6588c2ecf20Sopenharmony_ci		n_lookup = ARRAY_SIZE(s2_sn_lookup);
6598c2ecf20Sopenharmony_ci		lookup = s2_sn_lookup;
6608c2ecf20Sopenharmony_ci	} else {
6618c2ecf20Sopenharmony_ci		read_reg(state, RSTV0910_P2_NNOSDATAT1 + state->regoff,
6628c2ecf20Sopenharmony_ci			 &data1);
6638c2ecf20Sopenharmony_ci		read_reg(state, RSTV0910_P2_NNOSDATAT0 + state->regoff,
6648c2ecf20Sopenharmony_ci			 &data0);
6658c2ecf20Sopenharmony_ci		n_lookup = ARRAY_SIZE(s1_sn_lookup);
6668c2ecf20Sopenharmony_ci		lookup = s1_sn_lookup;
6678c2ecf20Sopenharmony_ci	}
6688c2ecf20Sopenharmony_ci	data = (((u16)data1) << 8) | (u16)data0;
6698c2ecf20Sopenharmony_ci	*signal_to_noise = table_lookup(lookup, n_lookup, data);
6708c2ecf20Sopenharmony_ci	return 0;
6718c2ecf20Sopenharmony_ci}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_cistatic int get_bit_error_rate_s(struct stv *state, u32 *bernumerator,
6748c2ecf20Sopenharmony_ci				u32 *berdenominator)
6758c2ecf20Sopenharmony_ci{
6768c2ecf20Sopenharmony_ci	u8 regs[3];
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	int status = read_regs(state,
6798c2ecf20Sopenharmony_ci			       RSTV0910_P2_ERRCNT12 + state->regoff,
6808c2ecf20Sopenharmony_ci			       regs, 3);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	if (status)
6838c2ecf20Sopenharmony_ci		return -EINVAL;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	if ((regs[0] & 0x80) == 0) {
6868c2ecf20Sopenharmony_ci		state->last_berdenominator = 1ULL << ((state->berscale * 2) +
6878c2ecf20Sopenharmony_ci						     10 + 3);
6888c2ecf20Sopenharmony_ci		state->last_bernumerator = ((u32)(regs[0] & 0x7F) << 16) |
6898c2ecf20Sopenharmony_ci			((u32)regs[1] << 8) | regs[2];
6908c2ecf20Sopenharmony_ci		if (state->last_bernumerator < 256 && state->berscale < 6) {
6918c2ecf20Sopenharmony_ci			state->berscale += 1;
6928c2ecf20Sopenharmony_ci			status = write_reg(state, RSTV0910_P2_ERRCTRL1 +
6938c2ecf20Sopenharmony_ci					   state->regoff,
6948c2ecf20Sopenharmony_ci					   0x20 | state->berscale);
6958c2ecf20Sopenharmony_ci		} else if (state->last_bernumerator > 1024 &&
6968c2ecf20Sopenharmony_ci			   state->berscale > 2) {
6978c2ecf20Sopenharmony_ci			state->berscale -= 1;
6988c2ecf20Sopenharmony_ci			status = write_reg(state, RSTV0910_P2_ERRCTRL1 +
6998c2ecf20Sopenharmony_ci					   state->regoff, 0x20 |
7008c2ecf20Sopenharmony_ci					   state->berscale);
7018c2ecf20Sopenharmony_ci		}
7028c2ecf20Sopenharmony_ci	}
7038c2ecf20Sopenharmony_ci	*bernumerator = state->last_bernumerator;
7048c2ecf20Sopenharmony_ci	*berdenominator = state->last_berdenominator;
7058c2ecf20Sopenharmony_ci	return 0;
7068c2ecf20Sopenharmony_ci}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_cistatic u32 dvbs2_nbch(enum dvbs2_mod_cod mod_cod, enum dvbs2_fectype fectype)
7098c2ecf20Sopenharmony_ci{
7108c2ecf20Sopenharmony_ci	static const u32 nbch[][2] = {
7118c2ecf20Sopenharmony_ci		{    0,     0}, /* DUMMY_PLF   */
7128c2ecf20Sopenharmony_ci		{16200,  3240}, /* QPSK_1_4,   */
7138c2ecf20Sopenharmony_ci		{21600,  5400}, /* QPSK_1_3,   */
7148c2ecf20Sopenharmony_ci		{25920,  6480}, /* QPSK_2_5,   */
7158c2ecf20Sopenharmony_ci		{32400,  7200}, /* QPSK_1_2,   */
7168c2ecf20Sopenharmony_ci		{38880,  9720}, /* QPSK_3_5,   */
7178c2ecf20Sopenharmony_ci		{43200, 10800}, /* QPSK_2_3,   */
7188c2ecf20Sopenharmony_ci		{48600, 11880}, /* QPSK_3_4,   */
7198c2ecf20Sopenharmony_ci		{51840, 12600}, /* QPSK_4_5,   */
7208c2ecf20Sopenharmony_ci		{54000, 13320}, /* QPSK_5_6,   */
7218c2ecf20Sopenharmony_ci		{57600, 14400}, /* QPSK_8_9,   */
7228c2ecf20Sopenharmony_ci		{58320, 16000}, /* QPSK_9_10,  */
7238c2ecf20Sopenharmony_ci		{43200,  9720}, /* 8PSK_3_5,   */
7248c2ecf20Sopenharmony_ci		{48600, 10800}, /* 8PSK_2_3,   */
7258c2ecf20Sopenharmony_ci		{51840, 11880}, /* 8PSK_3_4,   */
7268c2ecf20Sopenharmony_ci		{54000, 13320}, /* 8PSK_5_6,   */
7278c2ecf20Sopenharmony_ci		{57600, 14400}, /* 8PSK_8_9,   */
7288c2ecf20Sopenharmony_ci		{58320, 16000}, /* 8PSK_9_10,  */
7298c2ecf20Sopenharmony_ci		{43200, 10800}, /* 16APSK_2_3, */
7308c2ecf20Sopenharmony_ci		{48600, 11880}, /* 16APSK_3_4, */
7318c2ecf20Sopenharmony_ci		{51840, 12600}, /* 16APSK_4_5, */
7328c2ecf20Sopenharmony_ci		{54000, 13320}, /* 16APSK_5_6, */
7338c2ecf20Sopenharmony_ci		{57600, 14400}, /* 16APSK_8_9, */
7348c2ecf20Sopenharmony_ci		{58320, 16000}, /* 16APSK_9_10 */
7358c2ecf20Sopenharmony_ci		{48600, 11880}, /* 32APSK_3_4, */
7368c2ecf20Sopenharmony_ci		{51840, 12600}, /* 32APSK_4_5, */
7378c2ecf20Sopenharmony_ci		{54000, 13320}, /* 32APSK_5_6, */
7388c2ecf20Sopenharmony_ci		{57600, 14400}, /* 32APSK_8_9, */
7398c2ecf20Sopenharmony_ci		{58320, 16000}, /* 32APSK_9_10 */
7408c2ecf20Sopenharmony_ci	};
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	if (mod_cod >= DVBS2_QPSK_1_4 &&
7438c2ecf20Sopenharmony_ci	    mod_cod <= DVBS2_32APSK_9_10 && fectype <= DVBS2_16K)
7448c2ecf20Sopenharmony_ci		return nbch[mod_cod][fectype];
7458c2ecf20Sopenharmony_ci	return 64800;
7468c2ecf20Sopenharmony_ci}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_cistatic int get_bit_error_rate_s2(struct stv *state, u32 *bernumerator,
7498c2ecf20Sopenharmony_ci				 u32 *berdenominator)
7508c2ecf20Sopenharmony_ci{
7518c2ecf20Sopenharmony_ci	u8 regs[3];
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	int status = read_regs(state, RSTV0910_P2_ERRCNT12 + state->regoff,
7548c2ecf20Sopenharmony_ci			       regs, 3);
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	if (status)
7578c2ecf20Sopenharmony_ci		return -EINVAL;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	if ((regs[0] & 0x80) == 0) {
7608c2ecf20Sopenharmony_ci		state->last_berdenominator =
7618c2ecf20Sopenharmony_ci			dvbs2_nbch((enum dvbs2_mod_cod)state->mod_cod,
7628c2ecf20Sopenharmony_ci				   state->fectype) <<
7638c2ecf20Sopenharmony_ci			(state->berscale * 2);
7648c2ecf20Sopenharmony_ci		state->last_bernumerator = (((u32)regs[0] & 0x7F) << 16) |
7658c2ecf20Sopenharmony_ci			((u32)regs[1] << 8) | regs[2];
7668c2ecf20Sopenharmony_ci		if (state->last_bernumerator < 256 && state->berscale < 6) {
7678c2ecf20Sopenharmony_ci			state->berscale += 1;
7688c2ecf20Sopenharmony_ci			write_reg(state, RSTV0910_P2_ERRCTRL1 + state->regoff,
7698c2ecf20Sopenharmony_ci				  0x20 | state->berscale);
7708c2ecf20Sopenharmony_ci		} else if (state->last_bernumerator > 1024 &&
7718c2ecf20Sopenharmony_ci			   state->berscale > 2) {
7728c2ecf20Sopenharmony_ci			state->berscale -= 1;
7738c2ecf20Sopenharmony_ci			write_reg(state, RSTV0910_P2_ERRCTRL1 + state->regoff,
7748c2ecf20Sopenharmony_ci				  0x20 | state->berscale);
7758c2ecf20Sopenharmony_ci		}
7768c2ecf20Sopenharmony_ci	}
7778c2ecf20Sopenharmony_ci	*bernumerator = state->last_bernumerator;
7788c2ecf20Sopenharmony_ci	*berdenominator = state->last_berdenominator;
7798c2ecf20Sopenharmony_ci	return status;
7808c2ecf20Sopenharmony_ci}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_cistatic int get_bit_error_rate(struct stv *state, u32 *bernumerator,
7838c2ecf20Sopenharmony_ci			      u32 *berdenominator)
7848c2ecf20Sopenharmony_ci{
7858c2ecf20Sopenharmony_ci	*bernumerator = 0;
7868c2ecf20Sopenharmony_ci	*berdenominator = 1;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	switch (state->receive_mode) {
7898c2ecf20Sopenharmony_ci	case RCVMODE_DVBS:
7908c2ecf20Sopenharmony_ci		return get_bit_error_rate_s(state,
7918c2ecf20Sopenharmony_ci					    bernumerator, berdenominator);
7928c2ecf20Sopenharmony_ci	case RCVMODE_DVBS2:
7938c2ecf20Sopenharmony_ci		return get_bit_error_rate_s2(state,
7948c2ecf20Sopenharmony_ci					     bernumerator, berdenominator);
7958c2ecf20Sopenharmony_ci	default:
7968c2ecf20Sopenharmony_ci		break;
7978c2ecf20Sopenharmony_ci	}
7988c2ecf20Sopenharmony_ci	return 0;
7998c2ecf20Sopenharmony_ci}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_cistatic int set_mclock(struct stv *state, u32 master_clock)
8028c2ecf20Sopenharmony_ci{
8038c2ecf20Sopenharmony_ci	u32 idf = 1;
8048c2ecf20Sopenharmony_ci	u32 odf = 4;
8058c2ecf20Sopenharmony_ci	u32 quartz = state->base->extclk / 1000000;
8068c2ecf20Sopenharmony_ci	u32 fphi = master_clock / 1000000;
8078c2ecf20Sopenharmony_ci	u32 ndiv = (fphi * odf * idf) / quartz;
8088c2ecf20Sopenharmony_ci	u32 cp = 7;
8098c2ecf20Sopenharmony_ci	u32 fvco;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	if (ndiv >= 7 && ndiv <= 71)
8128c2ecf20Sopenharmony_ci		cp = 7;
8138c2ecf20Sopenharmony_ci	else if (ndiv >=  72 && ndiv <=  79)
8148c2ecf20Sopenharmony_ci		cp = 8;
8158c2ecf20Sopenharmony_ci	else if (ndiv >=  80 && ndiv <=  87)
8168c2ecf20Sopenharmony_ci		cp = 9;
8178c2ecf20Sopenharmony_ci	else if (ndiv >=  88 && ndiv <=  95)
8188c2ecf20Sopenharmony_ci		cp = 10;
8198c2ecf20Sopenharmony_ci	else if (ndiv >=  96 && ndiv <= 103)
8208c2ecf20Sopenharmony_ci		cp = 11;
8218c2ecf20Sopenharmony_ci	else if (ndiv >= 104 && ndiv <= 111)
8228c2ecf20Sopenharmony_ci		cp = 12;
8238c2ecf20Sopenharmony_ci	else if (ndiv >= 112 && ndiv <= 119)
8248c2ecf20Sopenharmony_ci		cp = 13;
8258c2ecf20Sopenharmony_ci	else if (ndiv >= 120 && ndiv <= 127)
8268c2ecf20Sopenharmony_ci		cp = 14;
8278c2ecf20Sopenharmony_ci	else if (ndiv >= 128 && ndiv <= 135)
8288c2ecf20Sopenharmony_ci		cp = 15;
8298c2ecf20Sopenharmony_ci	else if (ndiv >= 136 && ndiv <= 143)
8308c2ecf20Sopenharmony_ci		cp = 16;
8318c2ecf20Sopenharmony_ci	else if (ndiv >= 144 && ndiv <= 151)
8328c2ecf20Sopenharmony_ci		cp = 17;
8338c2ecf20Sopenharmony_ci	else if (ndiv >= 152 && ndiv <= 159)
8348c2ecf20Sopenharmony_ci		cp = 18;
8358c2ecf20Sopenharmony_ci	else if (ndiv >= 160 && ndiv <= 167)
8368c2ecf20Sopenharmony_ci		cp = 19;
8378c2ecf20Sopenharmony_ci	else if (ndiv >= 168 && ndiv <= 175)
8388c2ecf20Sopenharmony_ci		cp = 20;
8398c2ecf20Sopenharmony_ci	else if (ndiv >= 176 && ndiv <= 183)
8408c2ecf20Sopenharmony_ci		cp = 21;
8418c2ecf20Sopenharmony_ci	else if (ndiv >= 184 && ndiv <= 191)
8428c2ecf20Sopenharmony_ci		cp = 22;
8438c2ecf20Sopenharmony_ci	else if (ndiv >= 192 && ndiv <= 199)
8448c2ecf20Sopenharmony_ci		cp = 23;
8458c2ecf20Sopenharmony_ci	else if (ndiv >= 200 && ndiv <= 207)
8468c2ecf20Sopenharmony_ci		cp = 24;
8478c2ecf20Sopenharmony_ci	else if (ndiv >= 208 && ndiv <= 215)
8488c2ecf20Sopenharmony_ci		cp = 25;
8498c2ecf20Sopenharmony_ci	else if (ndiv >= 216 && ndiv <= 223)
8508c2ecf20Sopenharmony_ci		cp = 26;
8518c2ecf20Sopenharmony_ci	else if (ndiv >= 224 && ndiv <= 225)
8528c2ecf20Sopenharmony_ci		cp = 27;
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_NCOARSE, (cp << 3) | idf);
8558c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_NCOARSE2, odf);
8568c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_NCOARSE1, ndiv);
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	fvco = (quartz * 2 * ndiv) / idf;
8598c2ecf20Sopenharmony_ci	state->base->mclk = fvco / (2 * odf) * 1000000;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	return 0;
8628c2ecf20Sopenharmony_ci}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_cistatic int stop(struct stv *state)
8658c2ecf20Sopenharmony_ci{
8668c2ecf20Sopenharmony_ci	if (state->started) {
8678c2ecf20Sopenharmony_ci		u8 tmp;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci		write_reg(state, RSTV0910_P2_TSCFGH + state->regoff,
8708c2ecf20Sopenharmony_ci			  state->tscfgh | 0x01);
8718c2ecf20Sopenharmony_ci		read_reg(state, RSTV0910_P2_PDELCTRL1 + state->regoff, &tmp);
8728c2ecf20Sopenharmony_ci		tmp &= ~0x01; /* release reset DVBS2 packet delin */
8738c2ecf20Sopenharmony_ci		write_reg(state, RSTV0910_P2_PDELCTRL1 + state->regoff, tmp);
8748c2ecf20Sopenharmony_ci		/* Blind optim*/
8758c2ecf20Sopenharmony_ci		write_reg(state, RSTV0910_P2_AGC2O + state->regoff, 0x5B);
8768c2ecf20Sopenharmony_ci		/* Stop the demod */
8778c2ecf20Sopenharmony_ci		write_reg(state, RSTV0910_P2_DMDISTATE + state->regoff, 0x5c);
8788c2ecf20Sopenharmony_ci		state->started = 0;
8798c2ecf20Sopenharmony_ci	}
8808c2ecf20Sopenharmony_ci	state->receive_mode = RCVMODE_NONE;
8818c2ecf20Sopenharmony_ci	return 0;
8828c2ecf20Sopenharmony_ci}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cistatic void set_pls(struct stv *state, u32 pls_code)
8858c2ecf20Sopenharmony_ci{
8868c2ecf20Sopenharmony_ci	if (pls_code == state->cur_scrambling_code)
8878c2ecf20Sopenharmony_ci		return;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	/* PLROOT2 bit 2 = gold code */
8908c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_PLROOT0 + state->regoff,
8918c2ecf20Sopenharmony_ci		  pls_code & 0xff);
8928c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_PLROOT1 + state->regoff,
8938c2ecf20Sopenharmony_ci		  (pls_code >> 8) & 0xff);
8948c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_PLROOT2 + state->regoff,
8958c2ecf20Sopenharmony_ci		  0x04 | ((pls_code >> 16) & 0x03));
8968c2ecf20Sopenharmony_ci	state->cur_scrambling_code = pls_code;
8978c2ecf20Sopenharmony_ci}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_cistatic void set_isi(struct stv *state, u32 isi)
9008c2ecf20Sopenharmony_ci{
9018c2ecf20Sopenharmony_ci	if (isi == NO_STREAM_ID_FILTER)
9028c2ecf20Sopenharmony_ci		return;
9038c2ecf20Sopenharmony_ci	if (isi == 0x80000000) {
9048c2ecf20Sopenharmony_ci		SET_FIELD(FORCE_CONTINUOUS, 1);
9058c2ecf20Sopenharmony_ci		SET_FIELD(TSOUT_NOSYNC, 1);
9068c2ecf20Sopenharmony_ci	} else {
9078c2ecf20Sopenharmony_ci		SET_FIELD(FILTER_EN, 1);
9088c2ecf20Sopenharmony_ci		write_reg(state, RSTV0910_P2_ISIENTRY + state->regoff,
9098c2ecf20Sopenharmony_ci			  isi & 0xff);
9108c2ecf20Sopenharmony_ci		write_reg(state, RSTV0910_P2_ISIBITENA + state->regoff, 0xff);
9118c2ecf20Sopenharmony_ci	}
9128c2ecf20Sopenharmony_ci	SET_FIELD(ALGOSWRST, 1);
9138c2ecf20Sopenharmony_ci	SET_FIELD(ALGOSWRST, 0);
9148c2ecf20Sopenharmony_ci}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_cistatic void set_stream_modes(struct stv *state,
9178c2ecf20Sopenharmony_ci			     struct dtv_frontend_properties *p)
9188c2ecf20Sopenharmony_ci{
9198c2ecf20Sopenharmony_ci	set_isi(state, p->stream_id);
9208c2ecf20Sopenharmony_ci	set_pls(state, p->scrambling_sequence_index);
9218c2ecf20Sopenharmony_ci}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_cistatic int init_search_param(struct stv *state,
9248c2ecf20Sopenharmony_ci			     struct dtv_frontend_properties *p)
9258c2ecf20Sopenharmony_ci{
9268c2ecf20Sopenharmony_ci	SET_FIELD(FORCE_CONTINUOUS, 0);
9278c2ecf20Sopenharmony_ci	SET_FIELD(FRAME_MODE, 0);
9288c2ecf20Sopenharmony_ci	SET_FIELD(FILTER_EN, 0);
9298c2ecf20Sopenharmony_ci	SET_FIELD(TSOUT_NOSYNC, 0);
9308c2ecf20Sopenharmony_ci	SET_FIELD(TSFIFO_EMBINDVB, 0);
9318c2ecf20Sopenharmony_ci	SET_FIELD(TSDEL_SYNCBYTE, 0);
9328c2ecf20Sopenharmony_ci	SET_REG(UPLCCST0, 0xe0);
9338c2ecf20Sopenharmony_ci	SET_FIELD(TSINS_TOKEN, 0);
9348c2ecf20Sopenharmony_ci	SET_FIELD(HYSTERESIS_THRESHOLD, 0);
9358c2ecf20Sopenharmony_ci	SET_FIELD(ISIOBS_MODE, 1);
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	set_stream_modes(state, p);
9388c2ecf20Sopenharmony_ci	return 0;
9398c2ecf20Sopenharmony_ci}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_cistatic int enable_puncture_rate(struct stv *state, enum fe_code_rate rate)
9428c2ecf20Sopenharmony_ci{
9438c2ecf20Sopenharmony_ci	u8 val;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	switch (rate) {
9468c2ecf20Sopenharmony_ci	case FEC_1_2:
9478c2ecf20Sopenharmony_ci		val = 0x01;
9488c2ecf20Sopenharmony_ci		break;
9498c2ecf20Sopenharmony_ci	case FEC_2_3:
9508c2ecf20Sopenharmony_ci		val = 0x02;
9518c2ecf20Sopenharmony_ci		break;
9528c2ecf20Sopenharmony_ci	case FEC_3_4:
9538c2ecf20Sopenharmony_ci		val = 0x04;
9548c2ecf20Sopenharmony_ci		break;
9558c2ecf20Sopenharmony_ci	case FEC_5_6:
9568c2ecf20Sopenharmony_ci		val = 0x08;
9578c2ecf20Sopenharmony_ci		break;
9588c2ecf20Sopenharmony_ci	case FEC_7_8:
9598c2ecf20Sopenharmony_ci		val = 0x20;
9608c2ecf20Sopenharmony_ci		break;
9618c2ecf20Sopenharmony_ci	case FEC_NONE:
9628c2ecf20Sopenharmony_ci	default:
9638c2ecf20Sopenharmony_ci		val = 0x2f;
9648c2ecf20Sopenharmony_ci		break;
9658c2ecf20Sopenharmony_ci	}
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	return write_reg(state, RSTV0910_P2_PRVIT + state->regoff, val);
9688c2ecf20Sopenharmony_ci}
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_cistatic int set_vth_default(struct stv *state)
9718c2ecf20Sopenharmony_ci{
9728c2ecf20Sopenharmony_ci	state->vth[0] = 0xd7;
9738c2ecf20Sopenharmony_ci	state->vth[1] = 0x85;
9748c2ecf20Sopenharmony_ci	state->vth[2] = 0x58;
9758c2ecf20Sopenharmony_ci	state->vth[3] = 0x3a;
9768c2ecf20Sopenharmony_ci	state->vth[4] = 0x34;
9778c2ecf20Sopenharmony_ci	state->vth[5] = 0x28;
9788c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 0, state->vth[0]);
9798c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 1, state->vth[1]);
9808c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 2, state->vth[2]);
9818c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 3, state->vth[3]);
9828c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 4, state->vth[4]);
9838c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 5, state->vth[5]);
9848c2ecf20Sopenharmony_ci	return 0;
9858c2ecf20Sopenharmony_ci}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_cistatic int set_vth(struct stv *state)
9888c2ecf20Sopenharmony_ci{
9898c2ecf20Sopenharmony_ci	static const struct slookup vthlookup_table[] = {
9908c2ecf20Sopenharmony_ci		{250,	8780}, /* C/N= 1.5dB */
9918c2ecf20Sopenharmony_ci		{100,	7405}, /* C/N= 4.5dB */
9928c2ecf20Sopenharmony_ci		{40,	6330}, /* C/N= 6.5dB */
9938c2ecf20Sopenharmony_ci		{12,	5224}, /* C/N= 8.5dB */
9948c2ecf20Sopenharmony_ci		{5,	4236}  /* C/N=10.5dB */
9958c2ecf20Sopenharmony_ci	};
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	int i;
9988c2ecf20Sopenharmony_ci	u8 tmp[2];
9998c2ecf20Sopenharmony_ci	int status = read_regs(state,
10008c2ecf20Sopenharmony_ci			       RSTV0910_P2_NNOSDATAT1 + state->regoff,
10018c2ecf20Sopenharmony_ci			       tmp, 2);
10028c2ecf20Sopenharmony_ci	u16 reg_value = (tmp[0] << 8) | tmp[1];
10038c2ecf20Sopenharmony_ci	s32 vth = table_lookup(vthlookup_table, ARRAY_SIZE(vthlookup_table),
10048c2ecf20Sopenharmony_ci			      reg_value);
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i += 1)
10078c2ecf20Sopenharmony_ci		if (state->vth[i] > vth)
10088c2ecf20Sopenharmony_ci			state->vth[i] = vth;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 0, state->vth[0]);
10118c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 1, state->vth[1]);
10128c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 2, state->vth[2]);
10138c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 3, state->vth[3]);
10148c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 4, state->vth[4]);
10158c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 5, state->vth[5]);
10168c2ecf20Sopenharmony_ci	return status;
10178c2ecf20Sopenharmony_ci}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_cistatic int start(struct stv *state, struct dtv_frontend_properties *p)
10208c2ecf20Sopenharmony_ci{
10218c2ecf20Sopenharmony_ci	s32 freq;
10228c2ecf20Sopenharmony_ci	u8  reg_dmdcfgmd;
10238c2ecf20Sopenharmony_ci	u16 symb;
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	if (p->symbol_rate < 100000 || p->symbol_rate > 70000000)
10268c2ecf20Sopenharmony_ci		return -EINVAL;
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	state->receive_mode = RCVMODE_NONE;
10298c2ecf20Sopenharmony_ci	state->demod_lock_time = 0;
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	/* Demod Stop */
10328c2ecf20Sopenharmony_ci	if (state->started)
10338c2ecf20Sopenharmony_ci		write_reg(state, RSTV0910_P2_DMDISTATE + state->regoff, 0x5C);
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	init_search_param(state, p);
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	if (p->symbol_rate <= 1000000) { /* SR <=1Msps */
10388c2ecf20Sopenharmony_ci		state->demod_timeout = 3000;
10398c2ecf20Sopenharmony_ci		state->fec_timeout = 2000;
10408c2ecf20Sopenharmony_ci	} else if (p->symbol_rate <= 2000000) { /* 1Msps < SR <=2Msps */
10418c2ecf20Sopenharmony_ci		state->demod_timeout = 2500;
10428c2ecf20Sopenharmony_ci		state->fec_timeout = 1300;
10438c2ecf20Sopenharmony_ci	} else if (p->symbol_rate <= 5000000) { /* 2Msps< SR <=5Msps */
10448c2ecf20Sopenharmony_ci		state->demod_timeout = 1000;
10458c2ecf20Sopenharmony_ci		state->fec_timeout = 650;
10468c2ecf20Sopenharmony_ci	} else if (p->symbol_rate <= 10000000) { /* 5Msps< SR <=10Msps */
10478c2ecf20Sopenharmony_ci		state->demod_timeout = 700;
10488c2ecf20Sopenharmony_ci		state->fec_timeout = 350;
10498c2ecf20Sopenharmony_ci	} else if (p->symbol_rate < 20000000) { /* 10Msps< SR <=20Msps */
10508c2ecf20Sopenharmony_ci		state->demod_timeout = 400;
10518c2ecf20Sopenharmony_ci		state->fec_timeout = 200;
10528c2ecf20Sopenharmony_ci	} else { /* SR >=20Msps */
10538c2ecf20Sopenharmony_ci		state->demod_timeout = 300;
10548c2ecf20Sopenharmony_ci		state->fec_timeout = 200;
10558c2ecf20Sopenharmony_ci	}
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	/* Set the Init Symbol rate */
10588c2ecf20Sopenharmony_ci	symb = muldiv32(p->symbol_rate, 65536, state->base->mclk);
10598c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_SFRINIT1 + state->regoff,
10608c2ecf20Sopenharmony_ci		  ((symb >> 8) & 0x7F));
10618c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_SFRINIT0 + state->regoff, (symb & 0xFF));
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	state->demod_bits |= 0x80;
10648c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_DEMOD + state->regoff, state->demod_bits);
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	/* FE_STV0910_SetSearchStandard */
10678c2ecf20Sopenharmony_ci	read_reg(state, RSTV0910_P2_DMDCFGMD + state->regoff, &reg_dmdcfgmd);
10688c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_DMDCFGMD + state->regoff,
10698c2ecf20Sopenharmony_ci		  reg_dmdcfgmd |= 0xC0);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	write_shared_reg(state,
10728c2ecf20Sopenharmony_ci			 RSTV0910_TSTTSRS, state->nr ? 0x02 : 0x01, 0x00);
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	/* Disable DSS */
10758c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_FECM  + state->regoff, 0x00);
10768c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_PRVIT + state->regoff, 0x2F);
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	enable_puncture_rate(state, FEC_NONE);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	/* 8PSK 3/5, 8PSK 2/3 Poff tracking optimization WA */
10818c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_ACLC2S2Q + state->regoff, 0x0B);
10828c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_ACLC2S28 + state->regoff, 0x0A);
10838c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_BCLC2S2Q + state->regoff, 0x84);
10848c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_BCLC2S28 + state->regoff, 0x84);
10858c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_CARHDR + state->regoff, 0x1C);
10868c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_CARFREQ + state->regoff, 0x79);
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_ACLC2S216A + state->regoff, 0x29);
10898c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_ACLC2S232A + state->regoff, 0x09);
10908c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_BCLC2S216A + state->regoff, 0x84);
10918c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_BCLC2S232A + state->regoff, 0x84);
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	/*
10948c2ecf20Sopenharmony_ci	 * Reset CAR3, bug DVBS2->DVBS1 lock
10958c2ecf20Sopenharmony_ci	 * Note: The bit is only pulsed -> no lock on shared register needed
10968c2ecf20Sopenharmony_ci	 */
10978c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_TSTRES0, state->nr ? 0x04 : 0x08);
10988c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_TSTRES0, 0);
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	set_vth_default(state);
11018c2ecf20Sopenharmony_ci	/* Reset demod */
11028c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_DMDISTATE + state->regoff, 0x1F);
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_CARCFG + state->regoff, 0x46);
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	if (p->symbol_rate <= 5000000)
11078c2ecf20Sopenharmony_ci		freq = (state->search_range / 2000) + 80;
11088c2ecf20Sopenharmony_ci	else
11098c2ecf20Sopenharmony_ci		freq = (state->search_range / 2000) + 1600;
11108c2ecf20Sopenharmony_ci	freq = (freq << 16) / (state->base->mclk / 1000);
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_CFRUP1 + state->regoff,
11138c2ecf20Sopenharmony_ci		  (freq >> 8) & 0xff);
11148c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_CFRUP0 + state->regoff, (freq & 0xff));
11158c2ecf20Sopenharmony_ci	/* CFR Low Setting */
11168c2ecf20Sopenharmony_ci	freq = -freq;
11178c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_CFRLOW1 + state->regoff,
11188c2ecf20Sopenharmony_ci		  (freq >> 8) & 0xff);
11198c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_CFRLOW0 + state->regoff, (freq & 0xff));
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	/* init the demod frequency offset to 0 */
11228c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_CFRINIT1 + state->regoff, 0);
11238c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_CFRINIT0 + state->regoff, 0);
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_DMDISTATE + state->regoff, 0x1F);
11268c2ecf20Sopenharmony_ci	/* Trigger acq */
11278c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_DMDISTATE + state->regoff, 0x15);
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	state->demod_lock_time += TUNING_DELAY;
11308c2ecf20Sopenharmony_ci	state->started = 1;
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	return 0;
11338c2ecf20Sopenharmony_ci}
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_cistatic int init_diseqc(struct stv *state)
11368c2ecf20Sopenharmony_ci{
11378c2ecf20Sopenharmony_ci	u16 offs = state->nr ? 0x40 : 0; /* Address offset */
11388c2ecf20Sopenharmony_ci	u8 freq = ((state->base->mclk + 11000 * 32) / (22000 * 32));
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	/* Disable receiver */
11418c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_DISRXCFG + offs, 0x00);
11428c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0xBA); /* Reset = 1 */
11438c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A); /* Reset = 0 */
11448c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_DISTXF22 + offs, freq);
11458c2ecf20Sopenharmony_ci	return 0;
11468c2ecf20Sopenharmony_ci}
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_cistatic int probe(struct stv *state)
11498c2ecf20Sopenharmony_ci{
11508c2ecf20Sopenharmony_ci	u8 id;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	state->receive_mode = RCVMODE_NONE;
11538c2ecf20Sopenharmony_ci	state->started = 0;
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	if (read_reg(state, RSTV0910_MID, &id) < 0)
11568c2ecf20Sopenharmony_ci		return -ENODEV;
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	if (id != 0x51)
11598c2ecf20Sopenharmony_ci		return -EINVAL;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	/* Configure the I2C repeater to off */
11628c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_I2CRPT, 0x24);
11638c2ecf20Sopenharmony_ci	/* Configure the I2C repeater to off */
11648c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_I2CRPT, 0x24);
11658c2ecf20Sopenharmony_ci	/* Set the I2C to oversampling ratio */
11668c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_I2CCFG, 0x88); /* state->i2ccfg */
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_OUTCFG,    0x00); /* OUTCFG */
11698c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_PADCFG,    0x05); /* RFAGC Pads Dev = 05 */
11708c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_SYNTCTRL,  0x02); /* SYNTCTRL */
11718c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_TSGENERAL, state->tsgeneral); /* TSGENERAL */
11728c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_CFGEXT,    0x02); /* CFGEXT */
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	if (state->single)
11758c2ecf20Sopenharmony_ci		write_reg(state, RSTV0910_GENCFG, 0x14); /* GENCFG */
11768c2ecf20Sopenharmony_ci	else
11778c2ecf20Sopenharmony_ci		write_reg(state, RSTV0910_GENCFG, 0x15); /* GENCFG */
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_TNRCFG2, 0x02); /* IQSWAP = 0 */
11808c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_TNRCFG2, 0x82); /* IQSWAP = 1 */
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_CAR3CFG, 0x02);
11838c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_CAR3CFG, 0x02);
11848c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_DMDCFG4, 0x04);
11858c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_DMDCFG4, 0x04);
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_TSTRES0, 0x80); /* LDPC Reset */
11888c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_TSTRES0, 0x00);
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_TSPIDFLT1, 0x00);
11918c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_TSPIDFLT1, 0x00);
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_TMGCFG2, 0x80);
11948c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_TMGCFG2, 0x80);
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	set_mclock(state, 135000000);
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	/* TS output */
11998c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_TSCFGH, state->tscfgh | 0x01);
12008c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_TSCFGH, state->tscfgh);
12018c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_TSCFGM, 0xC0); /* Manual speed */
12028c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_TSCFGL, 0x20);
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_TSSPEED, state->tsspeed);
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_TSCFGH, state->tscfgh | 0x01);
12078c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_TSCFGH, state->tscfgh);
12088c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_TSCFGM, 0xC0); /* Manual speed */
12098c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_TSCFGL, 0x20);
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_TSSPEED, state->tsspeed);
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	/* Reset stream merger */
12148c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_TSCFGH, state->tscfgh | 0x01);
12158c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_TSCFGH, state->tscfgh | 0x01);
12168c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_TSCFGH, state->tscfgh);
12178c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_TSCFGH, state->tscfgh);
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_I2CRPT, state->i2crpt);
12208c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_I2CRPT, state->i2crpt);
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_TSINSDELM, 0x17);
12238c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P1_TSINSDELL, 0xff);
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_TSINSDELM, 0x17);
12268c2ecf20Sopenharmony_ci	write_reg(state, RSTV0910_P2_TSINSDELL, 0xff);
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	init_diseqc(state);
12298c2ecf20Sopenharmony_ci	return 0;
12308c2ecf20Sopenharmony_ci}
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_cistatic int gate_ctrl(struct dvb_frontend *fe, int enable)
12338c2ecf20Sopenharmony_ci{
12348c2ecf20Sopenharmony_ci	struct stv *state = fe->demodulator_priv;
12358c2ecf20Sopenharmony_ci	u8 i2crpt = state->i2crpt & ~0x86;
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	/*
12388c2ecf20Sopenharmony_ci	 * mutex_lock note: Concurrent I2C gate bus accesses must be
12398c2ecf20Sopenharmony_ci	 * prevented (STV0910 = dual demod on a single IC with a single I2C
12408c2ecf20Sopenharmony_ci	 * gate/bus, and two tuners attached), similar to most (if not all)
12418c2ecf20Sopenharmony_ci	 * other I2C host interfaces/buses.
12428c2ecf20Sopenharmony_ci	 *
12438c2ecf20Sopenharmony_ci	 * enable=1 (open I2C gate) will grab the lock
12448c2ecf20Sopenharmony_ci	 * enable=0 (close I2C gate) releases the lock
12458c2ecf20Sopenharmony_ci	 */
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	if (enable) {
12488c2ecf20Sopenharmony_ci		mutex_lock(&state->base->i2c_lock);
12498c2ecf20Sopenharmony_ci		i2crpt |= 0x80;
12508c2ecf20Sopenharmony_ci	} else {
12518c2ecf20Sopenharmony_ci		i2crpt |= 0x02;
12528c2ecf20Sopenharmony_ci	}
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	if (write_reg(state, state->nr ? RSTV0910_P2_I2CRPT :
12558c2ecf20Sopenharmony_ci		      RSTV0910_P1_I2CRPT, i2crpt) < 0) {
12568c2ecf20Sopenharmony_ci		/* don't hold the I2C bus lock on failure */
12578c2ecf20Sopenharmony_ci		if (!WARN_ON(!mutex_is_locked(&state->base->i2c_lock)))
12588c2ecf20Sopenharmony_ci			mutex_unlock(&state->base->i2c_lock);
12598c2ecf20Sopenharmony_ci		dev_err(&state->base->i2c->dev,
12608c2ecf20Sopenharmony_ci			"%s() write_reg failure (enable=%d)\n",
12618c2ecf20Sopenharmony_ci			__func__, enable);
12628c2ecf20Sopenharmony_ci		return -EIO;
12638c2ecf20Sopenharmony_ci	}
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	state->i2crpt = i2crpt;
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	if (!enable)
12688c2ecf20Sopenharmony_ci		if (!WARN_ON(!mutex_is_locked(&state->base->i2c_lock)))
12698c2ecf20Sopenharmony_ci			mutex_unlock(&state->base->i2c_lock);
12708c2ecf20Sopenharmony_ci	return 0;
12718c2ecf20Sopenharmony_ci}
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_cistatic void release(struct dvb_frontend *fe)
12748c2ecf20Sopenharmony_ci{
12758c2ecf20Sopenharmony_ci	struct stv *state = fe->demodulator_priv;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	state->base->count--;
12788c2ecf20Sopenharmony_ci	if (state->base->count == 0) {
12798c2ecf20Sopenharmony_ci		list_del(&state->base->stvlist);
12808c2ecf20Sopenharmony_ci		kfree(state->base);
12818c2ecf20Sopenharmony_ci	}
12828c2ecf20Sopenharmony_ci	kfree(state);
12838c2ecf20Sopenharmony_ci}
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_cistatic int set_parameters(struct dvb_frontend *fe)
12868c2ecf20Sopenharmony_ci{
12878c2ecf20Sopenharmony_ci	int stat = 0;
12888c2ecf20Sopenharmony_ci	struct stv *state = fe->demodulator_priv;
12898c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci	stop(state);
12928c2ecf20Sopenharmony_ci	if (fe->ops.tuner_ops.set_params)
12938c2ecf20Sopenharmony_ci		fe->ops.tuner_ops.set_params(fe);
12948c2ecf20Sopenharmony_ci	state->symbol_rate = p->symbol_rate;
12958c2ecf20Sopenharmony_ci	stat = start(state, p);
12968c2ecf20Sopenharmony_ci	return stat;
12978c2ecf20Sopenharmony_ci}
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_cistatic int manage_matype_info(struct stv *state)
13008c2ecf20Sopenharmony_ci{
13018c2ecf20Sopenharmony_ci	if (!state->started)
13028c2ecf20Sopenharmony_ci		return -EINVAL;
13038c2ecf20Sopenharmony_ci	if (state->receive_mode == RCVMODE_DVBS2) {
13048c2ecf20Sopenharmony_ci		u8 bbheader[2];
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci		read_regs(state, RSTV0910_P2_MATSTR1 + state->regoff,
13078c2ecf20Sopenharmony_ci			  bbheader, 2);
13088c2ecf20Sopenharmony_ci		state->feroll_off =
13098c2ecf20Sopenharmony_ci			(enum fe_stv0910_roll_off)(bbheader[0] & 0x03);
13108c2ecf20Sopenharmony_ci		state->is_vcm = (bbheader[0] & 0x10) == 0;
13118c2ecf20Sopenharmony_ci		state->is_standard_broadcast = (bbheader[0] & 0xFC) == 0xF0;
13128c2ecf20Sopenharmony_ci	} else if (state->receive_mode == RCVMODE_DVBS) {
13138c2ecf20Sopenharmony_ci		state->is_vcm = 0;
13148c2ecf20Sopenharmony_ci		state->is_standard_broadcast = 1;
13158c2ecf20Sopenharmony_ci		state->feroll_off = FE_SAT_35;
13168c2ecf20Sopenharmony_ci	}
13178c2ecf20Sopenharmony_ci	return 0;
13188c2ecf20Sopenharmony_ci}
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_cistatic int read_snr(struct dvb_frontend *fe)
13218c2ecf20Sopenharmony_ci{
13228c2ecf20Sopenharmony_ci	struct stv *state = fe->demodulator_priv;
13238c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
13248c2ecf20Sopenharmony_ci	s32 snrval;
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	if (!get_signal_to_noise(state, &snrval)) {
13278c2ecf20Sopenharmony_ci		p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
13288c2ecf20Sopenharmony_ci		p->cnr.stat[0].svalue = 100 * snrval; /* fix scale */
13298c2ecf20Sopenharmony_ci	} else {
13308c2ecf20Sopenharmony_ci		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
13318c2ecf20Sopenharmony_ci	}
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	return 0;
13348c2ecf20Sopenharmony_ci}
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_cistatic int read_ber(struct dvb_frontend *fe)
13378c2ecf20Sopenharmony_ci{
13388c2ecf20Sopenharmony_ci	struct stv *state = fe->demodulator_priv;
13398c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
13408c2ecf20Sopenharmony_ci	u32 n, d;
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	get_bit_error_rate(state, &n, &d);
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	p->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
13458c2ecf20Sopenharmony_ci	p->pre_bit_error.stat[0].uvalue = n;
13468c2ecf20Sopenharmony_ci	p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
13478c2ecf20Sopenharmony_ci	p->pre_bit_count.stat[0].uvalue = d;
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	return 0;
13508c2ecf20Sopenharmony_ci}
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_cistatic void read_signal_strength(struct dvb_frontend *fe)
13538c2ecf20Sopenharmony_ci{
13548c2ecf20Sopenharmony_ci	struct stv *state = fe->demodulator_priv;
13558c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &state->fe.dtv_property_cache;
13568c2ecf20Sopenharmony_ci	u8 reg[2];
13578c2ecf20Sopenharmony_ci	u16 agc;
13588c2ecf20Sopenharmony_ci	s32 padc, power = 0;
13598c2ecf20Sopenharmony_ci	int i;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	read_regs(state, RSTV0910_P2_AGCIQIN1 + state->regoff, reg, 2);
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	agc = (((u32)reg[0]) << 8) | reg[1];
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	for (i = 0; i < 5; i += 1) {
13668c2ecf20Sopenharmony_ci		read_regs(state, RSTV0910_P2_POWERI + state->regoff, reg, 2);
13678c2ecf20Sopenharmony_ci		power += (u32)reg[0] * (u32)reg[0]
13688c2ecf20Sopenharmony_ci			+ (u32)reg[1] * (u32)reg[1];
13698c2ecf20Sopenharmony_ci		usleep_range(3000, 4000);
13708c2ecf20Sopenharmony_ci	}
13718c2ecf20Sopenharmony_ci	power /= 5;
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	padc = table_lookup(padc_lookup, ARRAY_SIZE(padc_lookup), power) + 352;
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	p->strength.stat[0].scale = FE_SCALE_DECIBEL;
13768c2ecf20Sopenharmony_ci	p->strength.stat[0].svalue = (padc - agc);
13778c2ecf20Sopenharmony_ci}
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_cistatic int read_status(struct dvb_frontend *fe, enum fe_status *status)
13808c2ecf20Sopenharmony_ci{
13818c2ecf20Sopenharmony_ci	struct stv *state = fe->demodulator_priv;
13828c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
13838c2ecf20Sopenharmony_ci	u8 dmd_state = 0;
13848c2ecf20Sopenharmony_ci	u8 dstatus  = 0;
13858c2ecf20Sopenharmony_ci	enum receive_mode cur_receive_mode = RCVMODE_NONE;
13868c2ecf20Sopenharmony_ci	u32 feclock = 0;
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	*status = 0;
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci	read_reg(state, RSTV0910_P2_DMDSTATE + state->regoff, &dmd_state);
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	if (dmd_state & 0x40) {
13938c2ecf20Sopenharmony_ci		read_reg(state, RSTV0910_P2_DSTATUS + state->regoff, &dstatus);
13948c2ecf20Sopenharmony_ci		if (dstatus & 0x08)
13958c2ecf20Sopenharmony_ci			cur_receive_mode = (dmd_state & 0x20) ?
13968c2ecf20Sopenharmony_ci				RCVMODE_DVBS : RCVMODE_DVBS2;
13978c2ecf20Sopenharmony_ci	}
13988c2ecf20Sopenharmony_ci	if (cur_receive_mode == RCVMODE_NONE) {
13998c2ecf20Sopenharmony_ci		set_vth(state);
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci		/* reset signal statistics */
14028c2ecf20Sopenharmony_ci		p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
14038c2ecf20Sopenharmony_ci		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
14048c2ecf20Sopenharmony_ci		p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
14058c2ecf20Sopenharmony_ci		p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci		return 0;
14088c2ecf20Sopenharmony_ci	}
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	*status |= (FE_HAS_SIGNAL
14118c2ecf20Sopenharmony_ci		| FE_HAS_CARRIER
14128c2ecf20Sopenharmony_ci		| FE_HAS_VITERBI
14138c2ecf20Sopenharmony_ci		| FE_HAS_SYNC);
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	if (state->receive_mode == RCVMODE_NONE) {
14168c2ecf20Sopenharmony_ci		state->receive_mode = cur_receive_mode;
14178c2ecf20Sopenharmony_ci		state->demod_lock_time = jiffies;
14188c2ecf20Sopenharmony_ci		state->first_time_lock = 1;
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci		get_signal_parameters(state);
14218c2ecf20Sopenharmony_ci		tracking_optimization(state);
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci		write_reg(state, RSTV0910_P2_TSCFGH + state->regoff,
14248c2ecf20Sopenharmony_ci			  state->tscfgh);
14258c2ecf20Sopenharmony_ci		usleep_range(3000, 4000);
14268c2ecf20Sopenharmony_ci		write_reg(state, RSTV0910_P2_TSCFGH + state->regoff,
14278c2ecf20Sopenharmony_ci			  state->tscfgh | 0x01);
14288c2ecf20Sopenharmony_ci		write_reg(state, RSTV0910_P2_TSCFGH + state->regoff,
14298c2ecf20Sopenharmony_ci			  state->tscfgh);
14308c2ecf20Sopenharmony_ci	}
14318c2ecf20Sopenharmony_ci	if (dmd_state & 0x40) {
14328c2ecf20Sopenharmony_ci		if (state->receive_mode == RCVMODE_DVBS2) {
14338c2ecf20Sopenharmony_ci			u8 pdelstatus;
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci			read_reg(state,
14368c2ecf20Sopenharmony_ci				 RSTV0910_P2_PDELSTATUS1 + state->regoff,
14378c2ecf20Sopenharmony_ci				 &pdelstatus);
14388c2ecf20Sopenharmony_ci			feclock = (pdelstatus & 0x02) != 0;
14398c2ecf20Sopenharmony_ci		} else {
14408c2ecf20Sopenharmony_ci			u8 vstatus;
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci			read_reg(state,
14438c2ecf20Sopenharmony_ci				 RSTV0910_P2_VSTATUSVIT + state->regoff,
14448c2ecf20Sopenharmony_ci				 &vstatus);
14458c2ecf20Sopenharmony_ci			feclock = (vstatus & 0x08) != 0;
14468c2ecf20Sopenharmony_ci		}
14478c2ecf20Sopenharmony_ci	}
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	if (feclock) {
14508c2ecf20Sopenharmony_ci		*status |= FE_HAS_LOCK;
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci		if (state->first_time_lock) {
14538c2ecf20Sopenharmony_ci			u8 tmp;
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci			state->first_time_lock = 0;
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci			manage_matype_info(state);
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci			if (state->receive_mode == RCVMODE_DVBS2) {
14608c2ecf20Sopenharmony_ci				/*
14618c2ecf20Sopenharmony_ci				 * FSTV0910_P2_MANUALSX_ROLLOFF,
14628c2ecf20Sopenharmony_ci				 * FSTV0910_P2_MANUALS2_ROLLOFF = 0
14638c2ecf20Sopenharmony_ci				 */
14648c2ecf20Sopenharmony_ci				state->demod_bits &= ~0x84;
14658c2ecf20Sopenharmony_ci				write_reg(state,
14668c2ecf20Sopenharmony_ci					  RSTV0910_P2_DEMOD + state->regoff,
14678c2ecf20Sopenharmony_ci					  state->demod_bits);
14688c2ecf20Sopenharmony_ci				read_reg(state,
14698c2ecf20Sopenharmony_ci					 RSTV0910_P2_PDELCTRL2 + state->regoff,
14708c2ecf20Sopenharmony_ci					 &tmp);
14718c2ecf20Sopenharmony_ci				/* reset DVBS2 packet delinator error counter */
14728c2ecf20Sopenharmony_ci				tmp |= 0x40;
14738c2ecf20Sopenharmony_ci				write_reg(state,
14748c2ecf20Sopenharmony_ci					  RSTV0910_P2_PDELCTRL2 + state->regoff,
14758c2ecf20Sopenharmony_ci					  tmp);
14768c2ecf20Sopenharmony_ci				/* reset DVBS2 packet delinator error counter */
14778c2ecf20Sopenharmony_ci				tmp &= ~0x40;
14788c2ecf20Sopenharmony_ci				write_reg(state,
14798c2ecf20Sopenharmony_ci					  RSTV0910_P2_PDELCTRL2 + state->regoff,
14808c2ecf20Sopenharmony_ci					  tmp);
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci				state->berscale = 2;
14838c2ecf20Sopenharmony_ci				state->last_bernumerator = 0;
14848c2ecf20Sopenharmony_ci				state->last_berdenominator = 1;
14858c2ecf20Sopenharmony_ci				/* force to PRE BCH Rate */
14868c2ecf20Sopenharmony_ci				write_reg(state,
14878c2ecf20Sopenharmony_ci					  RSTV0910_P2_ERRCTRL1 + state->regoff,
14888c2ecf20Sopenharmony_ci					  BER_SRC_S2 | state->berscale);
14898c2ecf20Sopenharmony_ci			} else {
14908c2ecf20Sopenharmony_ci				state->berscale = 2;
14918c2ecf20Sopenharmony_ci				state->last_bernumerator = 0;
14928c2ecf20Sopenharmony_ci				state->last_berdenominator = 1;
14938c2ecf20Sopenharmony_ci				/* force to PRE RS Rate */
14948c2ecf20Sopenharmony_ci				write_reg(state,
14958c2ecf20Sopenharmony_ci					  RSTV0910_P2_ERRCTRL1 + state->regoff,
14968c2ecf20Sopenharmony_ci					  BER_SRC_S | state->berscale);
14978c2ecf20Sopenharmony_ci			}
14988c2ecf20Sopenharmony_ci			/* Reset the Total packet counter */
14998c2ecf20Sopenharmony_ci			write_reg(state,
15008c2ecf20Sopenharmony_ci				  RSTV0910_P2_FBERCPT4 + state->regoff, 0x00);
15018c2ecf20Sopenharmony_ci			/*
15028c2ecf20Sopenharmony_ci			 * Reset the packet Error counter2 (and Set it to
15038c2ecf20Sopenharmony_ci			 * infinite error count mode)
15048c2ecf20Sopenharmony_ci			 */
15058c2ecf20Sopenharmony_ci			write_reg(state,
15068c2ecf20Sopenharmony_ci				  RSTV0910_P2_ERRCTRL2 + state->regoff, 0xc1);
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci			set_vth_default(state);
15098c2ecf20Sopenharmony_ci			if (state->receive_mode == RCVMODE_DVBS)
15108c2ecf20Sopenharmony_ci				enable_puncture_rate(state,
15118c2ecf20Sopenharmony_ci						     state->puncture_rate);
15128c2ecf20Sopenharmony_ci		}
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci		/* Use highest signaled ModCod for quality */
15158c2ecf20Sopenharmony_ci		if (state->is_vcm) {
15168c2ecf20Sopenharmony_ci			u8 tmp;
15178c2ecf20Sopenharmony_ci			enum fe_stv0910_mod_cod mod_cod;
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci			read_reg(state, RSTV0910_P2_DMDMODCOD + state->regoff,
15208c2ecf20Sopenharmony_ci				 &tmp);
15218c2ecf20Sopenharmony_ci			mod_cod = (enum fe_stv0910_mod_cod)((tmp & 0x7c) >> 2);
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci			if (mod_cod > state->mod_cod)
15248c2ecf20Sopenharmony_ci				state->mod_cod = mod_cod;
15258c2ecf20Sopenharmony_ci		}
15268c2ecf20Sopenharmony_ci	}
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	/* read signal statistics */
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci	/* read signal strength */
15318c2ecf20Sopenharmony_ci	read_signal_strength(fe);
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	/* read carrier/noise on FE_HAS_CARRIER */
15348c2ecf20Sopenharmony_ci	if (*status & FE_HAS_CARRIER)
15358c2ecf20Sopenharmony_ci		read_snr(fe);
15368c2ecf20Sopenharmony_ci	else
15378c2ecf20Sopenharmony_ci		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	/* read ber */
15408c2ecf20Sopenharmony_ci	if (*status & FE_HAS_VITERBI) {
15418c2ecf20Sopenharmony_ci		read_ber(fe);
15428c2ecf20Sopenharmony_ci	} else {
15438c2ecf20Sopenharmony_ci		p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
15448c2ecf20Sopenharmony_ci		p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
15458c2ecf20Sopenharmony_ci	}
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci	return 0;
15488c2ecf20Sopenharmony_ci}
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_cistatic int get_frontend(struct dvb_frontend *fe,
15518c2ecf20Sopenharmony_ci			struct dtv_frontend_properties *p)
15528c2ecf20Sopenharmony_ci{
15538c2ecf20Sopenharmony_ci	struct stv *state = fe->demodulator_priv;
15548c2ecf20Sopenharmony_ci	u8 tmp;
15558c2ecf20Sopenharmony_ci	u32 symbolrate;
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	if (state->receive_mode == RCVMODE_DVBS2) {
15588c2ecf20Sopenharmony_ci		u32 mc;
15598c2ecf20Sopenharmony_ci		const enum fe_modulation modcod2mod[0x20] = {
15608c2ecf20Sopenharmony_ci			QPSK, QPSK, QPSK, QPSK,
15618c2ecf20Sopenharmony_ci			QPSK, QPSK, QPSK, QPSK,
15628c2ecf20Sopenharmony_ci			QPSK, QPSK, QPSK, QPSK,
15638c2ecf20Sopenharmony_ci			PSK_8, PSK_8, PSK_8, PSK_8,
15648c2ecf20Sopenharmony_ci			PSK_8, PSK_8, APSK_16, APSK_16,
15658c2ecf20Sopenharmony_ci			APSK_16, APSK_16, APSK_16, APSK_16,
15668c2ecf20Sopenharmony_ci			APSK_32, APSK_32, APSK_32, APSK_32,
15678c2ecf20Sopenharmony_ci			APSK_32,
15688c2ecf20Sopenharmony_ci		};
15698c2ecf20Sopenharmony_ci		const enum fe_code_rate modcod2fec[0x20] = {
15708c2ecf20Sopenharmony_ci			FEC_NONE, FEC_NONE, FEC_NONE, FEC_2_5,
15718c2ecf20Sopenharmony_ci			FEC_1_2, FEC_3_5, FEC_2_3, FEC_3_4,
15728c2ecf20Sopenharmony_ci			FEC_4_5, FEC_5_6, FEC_8_9, FEC_9_10,
15738c2ecf20Sopenharmony_ci			FEC_3_5, FEC_2_3, FEC_3_4, FEC_5_6,
15748c2ecf20Sopenharmony_ci			FEC_8_9, FEC_9_10, FEC_2_3, FEC_3_4,
15758c2ecf20Sopenharmony_ci			FEC_4_5, FEC_5_6, FEC_8_9, FEC_9_10,
15768c2ecf20Sopenharmony_ci			FEC_3_4, FEC_4_5, FEC_5_6, FEC_8_9,
15778c2ecf20Sopenharmony_ci			FEC_9_10
15788c2ecf20Sopenharmony_ci		};
15798c2ecf20Sopenharmony_ci		read_reg(state, RSTV0910_P2_DMDMODCOD + state->regoff, &tmp);
15808c2ecf20Sopenharmony_ci		mc = ((tmp & 0x7c) >> 2);
15818c2ecf20Sopenharmony_ci		p->pilot = (tmp & 0x01) ? PILOT_ON : PILOT_OFF;
15828c2ecf20Sopenharmony_ci		p->modulation = modcod2mod[mc];
15838c2ecf20Sopenharmony_ci		p->fec_inner = modcod2fec[mc];
15848c2ecf20Sopenharmony_ci	} else if (state->receive_mode == RCVMODE_DVBS) {
15858c2ecf20Sopenharmony_ci		read_reg(state, RSTV0910_P2_VITCURPUN + state->regoff, &tmp);
15868c2ecf20Sopenharmony_ci		switch (tmp & 0x1F) {
15878c2ecf20Sopenharmony_ci		case 0x0d:
15888c2ecf20Sopenharmony_ci			p->fec_inner = FEC_1_2;
15898c2ecf20Sopenharmony_ci			break;
15908c2ecf20Sopenharmony_ci		case 0x12:
15918c2ecf20Sopenharmony_ci			p->fec_inner = FEC_2_3;
15928c2ecf20Sopenharmony_ci			break;
15938c2ecf20Sopenharmony_ci		case 0x15:
15948c2ecf20Sopenharmony_ci			p->fec_inner = FEC_3_4;
15958c2ecf20Sopenharmony_ci			break;
15968c2ecf20Sopenharmony_ci		case 0x18:
15978c2ecf20Sopenharmony_ci			p->fec_inner = FEC_5_6;
15988c2ecf20Sopenharmony_ci			break;
15998c2ecf20Sopenharmony_ci		case 0x1a:
16008c2ecf20Sopenharmony_ci			p->fec_inner = FEC_7_8;
16018c2ecf20Sopenharmony_ci			break;
16028c2ecf20Sopenharmony_ci		default:
16038c2ecf20Sopenharmony_ci			p->fec_inner = FEC_NONE;
16048c2ecf20Sopenharmony_ci			break;
16058c2ecf20Sopenharmony_ci		}
16068c2ecf20Sopenharmony_ci		p->rolloff = ROLLOFF_35;
16078c2ecf20Sopenharmony_ci	}
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	if (state->receive_mode != RCVMODE_NONE) {
16108c2ecf20Sopenharmony_ci		get_cur_symbol_rate(state, &symbolrate);
16118c2ecf20Sopenharmony_ci		p->symbol_rate = symbolrate;
16128c2ecf20Sopenharmony_ci	}
16138c2ecf20Sopenharmony_ci	return 0;
16148c2ecf20Sopenharmony_ci}
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_cistatic int tune(struct dvb_frontend *fe, bool re_tune,
16178c2ecf20Sopenharmony_ci		unsigned int mode_flags,
16188c2ecf20Sopenharmony_ci		unsigned int *delay, enum fe_status *status)
16198c2ecf20Sopenharmony_ci{
16208c2ecf20Sopenharmony_ci	struct stv *state = fe->demodulator_priv;
16218c2ecf20Sopenharmony_ci	int r;
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	if (re_tune) {
16248c2ecf20Sopenharmony_ci		r = set_parameters(fe);
16258c2ecf20Sopenharmony_ci		if (r)
16268c2ecf20Sopenharmony_ci			return r;
16278c2ecf20Sopenharmony_ci		state->tune_time = jiffies;
16288c2ecf20Sopenharmony_ci	}
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	r = read_status(fe, status);
16318c2ecf20Sopenharmony_ci	if (r)
16328c2ecf20Sopenharmony_ci		return r;
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	if (*status & FE_HAS_LOCK)
16358c2ecf20Sopenharmony_ci		return 0;
16368c2ecf20Sopenharmony_ci	*delay = HZ;
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	return 0;
16398c2ecf20Sopenharmony_ci}
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_cistatic enum dvbfe_algo get_algo(struct dvb_frontend *fe)
16428c2ecf20Sopenharmony_ci{
16438c2ecf20Sopenharmony_ci	return DVBFE_ALGO_HW;
16448c2ecf20Sopenharmony_ci}
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_cistatic int set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone)
16478c2ecf20Sopenharmony_ci{
16488c2ecf20Sopenharmony_ci	struct stv *state = fe->demodulator_priv;
16498c2ecf20Sopenharmony_ci	u16 offs = state->nr ? 0x40 : 0;
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	switch (tone) {
16528c2ecf20Sopenharmony_ci	case SEC_TONE_ON:
16538c2ecf20Sopenharmony_ci		return write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x38);
16548c2ecf20Sopenharmony_ci	case SEC_TONE_OFF:
16558c2ecf20Sopenharmony_ci		return write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3a);
16568c2ecf20Sopenharmony_ci	default:
16578c2ecf20Sopenharmony_ci		break;
16588c2ecf20Sopenharmony_ci	}
16598c2ecf20Sopenharmony_ci	return -EINVAL;
16608c2ecf20Sopenharmony_ci}
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_cistatic int wait_dis(struct stv *state, u8 flag, u8 val)
16638c2ecf20Sopenharmony_ci{
16648c2ecf20Sopenharmony_ci	int i;
16658c2ecf20Sopenharmony_ci	u8 stat;
16668c2ecf20Sopenharmony_ci	u16 offs = state->nr ? 0x40 : 0;
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci	for (i = 0; i < 10; i++) {
16698c2ecf20Sopenharmony_ci		read_reg(state, RSTV0910_P1_DISTXSTATUS + offs, &stat);
16708c2ecf20Sopenharmony_ci		if ((stat & flag) == val)
16718c2ecf20Sopenharmony_ci			return 0;
16728c2ecf20Sopenharmony_ci		usleep_range(10000, 11000);
16738c2ecf20Sopenharmony_ci	}
16748c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
16758c2ecf20Sopenharmony_ci}
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_cistatic int send_master_cmd(struct dvb_frontend *fe,
16788c2ecf20Sopenharmony_ci			   struct dvb_diseqc_master_cmd *cmd)
16798c2ecf20Sopenharmony_ci{
16808c2ecf20Sopenharmony_ci	struct stv *state = fe->demodulator_priv;
16818c2ecf20Sopenharmony_ci	int i;
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	SET_FIELD(DISEQC_MODE, 2);
16848c2ecf20Sopenharmony_ci	SET_FIELD(DIS_PRECHARGE, 1);
16858c2ecf20Sopenharmony_ci	for (i = 0; i < cmd->msg_len; i++) {
16868c2ecf20Sopenharmony_ci		wait_dis(state, 0x40, 0x00);
16878c2ecf20Sopenharmony_ci		SET_REG(DISTXFIFO, cmd->msg[i]);
16888c2ecf20Sopenharmony_ci	}
16898c2ecf20Sopenharmony_ci	SET_FIELD(DIS_PRECHARGE, 0);
16908c2ecf20Sopenharmony_ci	wait_dis(state, 0x20, 0x20);
16918c2ecf20Sopenharmony_ci	return 0;
16928c2ecf20Sopenharmony_ci}
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_cistatic int send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd burst)
16958c2ecf20Sopenharmony_ci{
16968c2ecf20Sopenharmony_ci	struct stv *state = fe->demodulator_priv;
16978c2ecf20Sopenharmony_ci	u8 value;
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci	if (burst == SEC_MINI_A) {
17008c2ecf20Sopenharmony_ci		SET_FIELD(DISEQC_MODE, 3);
17018c2ecf20Sopenharmony_ci		value = 0x00;
17028c2ecf20Sopenharmony_ci	} else {
17038c2ecf20Sopenharmony_ci		SET_FIELD(DISEQC_MODE, 2);
17048c2ecf20Sopenharmony_ci		value = 0xFF;
17058c2ecf20Sopenharmony_ci	}
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ci	SET_FIELD(DIS_PRECHARGE, 1);
17088c2ecf20Sopenharmony_ci	wait_dis(state, 0x40, 0x00);
17098c2ecf20Sopenharmony_ci	SET_REG(DISTXFIFO, value);
17108c2ecf20Sopenharmony_ci	SET_FIELD(DIS_PRECHARGE, 0);
17118c2ecf20Sopenharmony_ci	wait_dis(state, 0x20, 0x20);
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci	return 0;
17148c2ecf20Sopenharmony_ci}
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_cistatic int sleep(struct dvb_frontend *fe)
17178c2ecf20Sopenharmony_ci{
17188c2ecf20Sopenharmony_ci	struct stv *state = fe->demodulator_priv;
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	stop(state);
17218c2ecf20Sopenharmony_ci	return 0;
17228c2ecf20Sopenharmony_ci}
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops stv0910_ops = {
17258c2ecf20Sopenharmony_ci	.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
17268c2ecf20Sopenharmony_ci	.info = {
17278c2ecf20Sopenharmony_ci		.name			= "ST STV0910",
17288c2ecf20Sopenharmony_ci		.frequency_min_hz	=  950 * MHz,
17298c2ecf20Sopenharmony_ci		.frequency_max_hz	= 2150 * MHz,
17308c2ecf20Sopenharmony_ci		.symbol_rate_min	= 100000,
17318c2ecf20Sopenharmony_ci		.symbol_rate_max	= 70000000,
17328c2ecf20Sopenharmony_ci		.caps			= FE_CAN_INVERSION_AUTO |
17338c2ecf20Sopenharmony_ci					  FE_CAN_FEC_AUTO       |
17348c2ecf20Sopenharmony_ci					  FE_CAN_QPSK           |
17358c2ecf20Sopenharmony_ci					  FE_CAN_2G_MODULATION  |
17368c2ecf20Sopenharmony_ci					  FE_CAN_MULTISTREAM
17378c2ecf20Sopenharmony_ci	},
17388c2ecf20Sopenharmony_ci	.sleep				= sleep,
17398c2ecf20Sopenharmony_ci	.release			= release,
17408c2ecf20Sopenharmony_ci	.i2c_gate_ctrl			= gate_ctrl,
17418c2ecf20Sopenharmony_ci	.set_frontend			= set_parameters,
17428c2ecf20Sopenharmony_ci	.get_frontend_algo		= get_algo,
17438c2ecf20Sopenharmony_ci	.get_frontend			= get_frontend,
17448c2ecf20Sopenharmony_ci	.tune				= tune,
17458c2ecf20Sopenharmony_ci	.read_status			= read_status,
17468c2ecf20Sopenharmony_ci	.set_tone			= set_tone,
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	.diseqc_send_master_cmd		= send_master_cmd,
17498c2ecf20Sopenharmony_ci	.diseqc_send_burst		= send_burst,
17508c2ecf20Sopenharmony_ci};
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_cistatic struct stv_base *match_base(struct i2c_adapter *i2c, u8 adr)
17538c2ecf20Sopenharmony_ci{
17548c2ecf20Sopenharmony_ci	struct stv_base *p;
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	list_for_each_entry(p, &stvlist, stvlist)
17578c2ecf20Sopenharmony_ci		if (p->i2c == i2c && p->adr == adr)
17588c2ecf20Sopenharmony_ci			return p;
17598c2ecf20Sopenharmony_ci	return NULL;
17608c2ecf20Sopenharmony_ci}
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_cistatic void stv0910_init_stats(struct stv *state)
17638c2ecf20Sopenharmony_ci{
17648c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &state->fe.dtv_property_cache;
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci	p->strength.len = 1;
17678c2ecf20Sopenharmony_ci	p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
17688c2ecf20Sopenharmony_ci	p->cnr.len = 1;
17698c2ecf20Sopenharmony_ci	p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
17708c2ecf20Sopenharmony_ci	p->pre_bit_error.len = 1;
17718c2ecf20Sopenharmony_ci	p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
17728c2ecf20Sopenharmony_ci	p->pre_bit_count.len = 1;
17738c2ecf20Sopenharmony_ci	p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
17748c2ecf20Sopenharmony_ci}
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_cistruct dvb_frontend *stv0910_attach(struct i2c_adapter *i2c,
17778c2ecf20Sopenharmony_ci				    struct stv0910_cfg *cfg,
17788c2ecf20Sopenharmony_ci				    int nr)
17798c2ecf20Sopenharmony_ci{
17808c2ecf20Sopenharmony_ci	struct stv *state;
17818c2ecf20Sopenharmony_ci	struct stv_base *base;
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci	state = kzalloc(sizeof(*state), GFP_KERNEL);
17848c2ecf20Sopenharmony_ci	if (!state)
17858c2ecf20Sopenharmony_ci		return NULL;
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	state->tscfgh = 0x20 | (cfg->parallel ? 0 : 0x40);
17888c2ecf20Sopenharmony_ci	state->tsgeneral = (cfg->parallel == 2) ? 0x02 : 0x00;
17898c2ecf20Sopenharmony_ci	state->i2crpt = 0x0A | ((cfg->rptlvl & 0x07) << 4);
17908c2ecf20Sopenharmony_ci	/* use safe tsspeed value if unspecified through stv0910_cfg */
17918c2ecf20Sopenharmony_ci	state->tsspeed = (cfg->tsspeed ? cfg->tsspeed : 0x28);
17928c2ecf20Sopenharmony_ci	state->nr = nr;
17938c2ecf20Sopenharmony_ci	state->regoff = state->nr ? 0 : 0x200;
17948c2ecf20Sopenharmony_ci	state->search_range = 16000000;
17958c2ecf20Sopenharmony_ci	state->demod_bits = 0x10; /* Inversion : Auto with reset to 0 */
17968c2ecf20Sopenharmony_ci	state->receive_mode = RCVMODE_NONE;
17978c2ecf20Sopenharmony_ci	state->cur_scrambling_code = (~0U);
17988c2ecf20Sopenharmony_ci	state->single = cfg->single ? 1 : 0;
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci	base = match_base(i2c, cfg->adr);
18018c2ecf20Sopenharmony_ci	if (base) {
18028c2ecf20Sopenharmony_ci		base->count++;
18038c2ecf20Sopenharmony_ci		state->base = base;
18048c2ecf20Sopenharmony_ci	} else {
18058c2ecf20Sopenharmony_ci		base = kzalloc(sizeof(*base), GFP_KERNEL);
18068c2ecf20Sopenharmony_ci		if (!base)
18078c2ecf20Sopenharmony_ci			goto fail;
18088c2ecf20Sopenharmony_ci		base->i2c = i2c;
18098c2ecf20Sopenharmony_ci		base->adr = cfg->adr;
18108c2ecf20Sopenharmony_ci		base->count = 1;
18118c2ecf20Sopenharmony_ci		base->extclk = cfg->clk ? cfg->clk : 30000000;
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci		mutex_init(&base->i2c_lock);
18148c2ecf20Sopenharmony_ci		mutex_init(&base->reg_lock);
18158c2ecf20Sopenharmony_ci		state->base = base;
18168c2ecf20Sopenharmony_ci		if (probe(state) < 0) {
18178c2ecf20Sopenharmony_ci			dev_info(&i2c->dev, "No demod found at adr %02X on %s\n",
18188c2ecf20Sopenharmony_ci				 cfg->adr, dev_name(&i2c->dev));
18198c2ecf20Sopenharmony_ci			kfree(base);
18208c2ecf20Sopenharmony_ci			goto fail;
18218c2ecf20Sopenharmony_ci		}
18228c2ecf20Sopenharmony_ci		list_add(&base->stvlist, &stvlist);
18238c2ecf20Sopenharmony_ci	}
18248c2ecf20Sopenharmony_ci	state->fe.ops = stv0910_ops;
18258c2ecf20Sopenharmony_ci	state->fe.demodulator_priv = state;
18268c2ecf20Sopenharmony_ci	state->nr = nr;
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci	dev_info(&i2c->dev, "%s demod found at adr %02X on %s\n",
18298c2ecf20Sopenharmony_ci		 state->fe.ops.info.name, cfg->adr, dev_name(&i2c->dev));
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_ci	stv0910_init_stats(state);
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	return &state->fe;
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_cifail:
18368c2ecf20Sopenharmony_ci	kfree(state);
18378c2ecf20Sopenharmony_ci	return NULL;
18388c2ecf20Sopenharmony_ci}
18398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(stv0910_attach);
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ST STV0910 multistandard frontend driver");
18428c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ralph and Marcus Metzler, Manfred Voelkel");
18438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1844