18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci	STB0899 Multistandard Frontend driver
48c2ecf20Sopenharmony_ci	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci	Copyright (C) ST Microelectronics
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci*/
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/init.h>
118c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/string.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/dvb/frontend.h>
188c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "stb0899_drv.h"
218c2ecf20Sopenharmony_ci#include "stb0899_priv.h"
228c2ecf20Sopenharmony_ci#include "stb0899_reg.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/* Max transfer size done by I2C transfer functions */
258c2ecf20Sopenharmony_ci#define MAX_XFER_SIZE  64
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic unsigned int verbose = 0;//1;
288c2ecf20Sopenharmony_cimodule_param(verbose, int, 0644);
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/* C/N in dB/10, NIRM/NIRL */
318c2ecf20Sopenharmony_cistatic const struct stb0899_tab stb0899_cn_tab[] = {
328c2ecf20Sopenharmony_ci	{ 200,	2600 },
338c2ecf20Sopenharmony_ci	{ 190,	2700 },
348c2ecf20Sopenharmony_ci	{ 180,	2860 },
358c2ecf20Sopenharmony_ci	{ 170,	3020 },
368c2ecf20Sopenharmony_ci	{ 160,	3210 },
378c2ecf20Sopenharmony_ci	{ 150,	3440 },
388c2ecf20Sopenharmony_ci	{ 140,	3710 },
398c2ecf20Sopenharmony_ci	{ 130,	4010 },
408c2ecf20Sopenharmony_ci	{ 120,	4360 },
418c2ecf20Sopenharmony_ci	{ 110,	4740 },
428c2ecf20Sopenharmony_ci	{ 100,	5190 },
438c2ecf20Sopenharmony_ci	{ 90,	5670 },
448c2ecf20Sopenharmony_ci	{ 80,	6200 },
458c2ecf20Sopenharmony_ci	{ 70,	6770 },
468c2ecf20Sopenharmony_ci	{ 60,	7360 },
478c2ecf20Sopenharmony_ci	{ 50,	7970 },
488c2ecf20Sopenharmony_ci	{ 40,	8250 },
498c2ecf20Sopenharmony_ci	{ 30,	9000 },
508c2ecf20Sopenharmony_ci	{ 20,	9450 },
518c2ecf20Sopenharmony_ci	{ 15,	9600 },
528c2ecf20Sopenharmony_ci};
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/* DVB-S AGCIQ_VALUE vs. signal level in dBm/10.
558c2ecf20Sopenharmony_ci * As measured, connected to a modulator.
568c2ecf20Sopenharmony_ci * -8.0 to -50.0 dBm directly connected,
578c2ecf20Sopenharmony_ci * -52.0 to -74.8 with extra attenuation.
588c2ecf20Sopenharmony_ci * Cut-off to AGCIQ_VALUE = 0x80 below -74.8dBm.
598c2ecf20Sopenharmony_ci * Crude linear extrapolation below -84.8dBm and above -8.0dBm.
608c2ecf20Sopenharmony_ci */
618c2ecf20Sopenharmony_cistatic const struct stb0899_tab stb0899_dvbsrf_tab[] = {
628c2ecf20Sopenharmony_ci	{ -750,	-128 },
638c2ecf20Sopenharmony_ci	{ -748,	 -94 },
648c2ecf20Sopenharmony_ci	{ -745,	 -92 },
658c2ecf20Sopenharmony_ci	{ -735,	 -90 },
668c2ecf20Sopenharmony_ci	{ -720,	 -87 },
678c2ecf20Sopenharmony_ci	{ -670,	 -77 },
688c2ecf20Sopenharmony_ci	{ -640,	 -70 },
698c2ecf20Sopenharmony_ci	{ -610,	 -62 },
708c2ecf20Sopenharmony_ci	{ -600,	 -60 },
718c2ecf20Sopenharmony_ci	{ -590,	 -56 },
728c2ecf20Sopenharmony_ci	{ -560,	 -41 },
738c2ecf20Sopenharmony_ci	{ -540,	 -25 },
748c2ecf20Sopenharmony_ci	{ -530,	 -17 },
758c2ecf20Sopenharmony_ci	{ -520,	 -11 },
768c2ecf20Sopenharmony_ci	{ -500,	   1 },
778c2ecf20Sopenharmony_ci	{ -490,	   6 },
788c2ecf20Sopenharmony_ci	{ -480,	  10 },
798c2ecf20Sopenharmony_ci	{ -440,	  22 },
808c2ecf20Sopenharmony_ci	{ -420,	  27 },
818c2ecf20Sopenharmony_ci	{ -400,	  31 },
828c2ecf20Sopenharmony_ci	{ -380,	  34 },
838c2ecf20Sopenharmony_ci	{ -340,	  40 },
848c2ecf20Sopenharmony_ci	{ -320,	  43 },
858c2ecf20Sopenharmony_ci	{ -280,	  48 },
868c2ecf20Sopenharmony_ci	{ -250,	  52 },
878c2ecf20Sopenharmony_ci	{ -230,	  55 },
888c2ecf20Sopenharmony_ci	{ -180,	  61 },
898c2ecf20Sopenharmony_ci	{ -140,	  66 },
908c2ecf20Sopenharmony_ci	{  -90,	  73 },
918c2ecf20Sopenharmony_ci	{  -80,	  74 },
928c2ecf20Sopenharmony_ci	{  500,	 127 }
938c2ecf20Sopenharmony_ci};
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci/* DVB-S2 IF_AGC_GAIN vs. signal level in dBm/10.
968c2ecf20Sopenharmony_ci * As measured, connected to a modulator.
978c2ecf20Sopenharmony_ci * -8.0 to -50.1 dBm directly connected,
988c2ecf20Sopenharmony_ci * -53.0 to -76.6 with extra attenuation.
998c2ecf20Sopenharmony_ci * Cut-off to IF_AGC_GAIN = 0x3fff below -76.6dBm.
1008c2ecf20Sopenharmony_ci * Crude linear extrapolation below -76.6dBm and above -8.0dBm.
1018c2ecf20Sopenharmony_ci */
1028c2ecf20Sopenharmony_cistatic const struct stb0899_tab stb0899_dvbs2rf_tab[] = {
1038c2ecf20Sopenharmony_ci	{  700,	    0 },
1048c2ecf20Sopenharmony_ci	{  -80,	 3217 },
1058c2ecf20Sopenharmony_ci	{ -150,	 3893 },
1068c2ecf20Sopenharmony_ci	{ -190,	 4217 },
1078c2ecf20Sopenharmony_ci	{ -240,	 4621 },
1088c2ecf20Sopenharmony_ci	{ -280,	 4945 },
1098c2ecf20Sopenharmony_ci	{ -320,	 5273 },
1108c2ecf20Sopenharmony_ci	{ -350,	 5545 },
1118c2ecf20Sopenharmony_ci	{ -370,	 5741 },
1128c2ecf20Sopenharmony_ci	{ -410,	 6147 },
1138c2ecf20Sopenharmony_ci	{ -450,	 6671 },
1148c2ecf20Sopenharmony_ci	{ -490,	 7413 },
1158c2ecf20Sopenharmony_ci	{ -501,	 7665 },
1168c2ecf20Sopenharmony_ci	{ -530,	 8767 },
1178c2ecf20Sopenharmony_ci	{ -560,	10219 },
1188c2ecf20Sopenharmony_ci	{ -580,	10939 },
1198c2ecf20Sopenharmony_ci	{ -590,	11518 },
1208c2ecf20Sopenharmony_ci	{ -600,	11723 },
1218c2ecf20Sopenharmony_ci	{ -650,	12659 },
1228c2ecf20Sopenharmony_ci	{ -690,	13219 },
1238c2ecf20Sopenharmony_ci	{ -730,	13645 },
1248c2ecf20Sopenharmony_ci	{ -750,	13909 },
1258c2ecf20Sopenharmony_ci	{ -766,	14153 },
1268c2ecf20Sopenharmony_ci	{ -950,	16383 }
1278c2ecf20Sopenharmony_ci};
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci/* DVB-S2 Es/N0 quant in dB/100 vs read value * 100*/
1308c2ecf20Sopenharmony_cistatic struct stb0899_tab stb0899_quant_tab[] = {
1318c2ecf20Sopenharmony_ci	{    0,	    0 },
1328c2ecf20Sopenharmony_ci	{    0,	  100 },
1338c2ecf20Sopenharmony_ci	{  600,	  200 },
1348c2ecf20Sopenharmony_ci	{  950,	  299 },
1358c2ecf20Sopenharmony_ci	{ 1200,	  398 },
1368c2ecf20Sopenharmony_ci	{ 1400,	  501 },
1378c2ecf20Sopenharmony_ci	{ 1560,	  603 },
1388c2ecf20Sopenharmony_ci	{ 1690,	  700 },
1398c2ecf20Sopenharmony_ci	{ 1810,	  804 },
1408c2ecf20Sopenharmony_ci	{ 1910,	  902 },
1418c2ecf20Sopenharmony_ci	{ 2000,	 1000 },
1428c2ecf20Sopenharmony_ci	{ 2080,	 1096 },
1438c2ecf20Sopenharmony_ci	{ 2160,	 1202 },
1448c2ecf20Sopenharmony_ci	{ 2230,	 1303 },
1458c2ecf20Sopenharmony_ci	{ 2350,	 1496 },
1468c2ecf20Sopenharmony_ci	{ 2410,	 1603 },
1478c2ecf20Sopenharmony_ci	{ 2460,	 1698 },
1488c2ecf20Sopenharmony_ci	{ 2510,	 1799 },
1498c2ecf20Sopenharmony_ci	{ 2600,	 1995 },
1508c2ecf20Sopenharmony_ci	{ 2650,	 2113 },
1518c2ecf20Sopenharmony_ci	{ 2690,  2213 },
1528c2ecf20Sopenharmony_ci	{ 2720,	 2291 },
1538c2ecf20Sopenharmony_ci	{ 2760,	 2399 },
1548c2ecf20Sopenharmony_ci	{ 2800,	 2512 },
1558c2ecf20Sopenharmony_ci	{ 2860,	 2692 },
1568c2ecf20Sopenharmony_ci	{ 2930,	 2917 },
1578c2ecf20Sopenharmony_ci	{ 2960,	 3020 },
1588c2ecf20Sopenharmony_ci	{ 3010,	 3199 },
1598c2ecf20Sopenharmony_ci	{ 3040,	 3311 },
1608c2ecf20Sopenharmony_ci	{ 3060,	 3388 },
1618c2ecf20Sopenharmony_ci	{ 3120,	 3631 },
1628c2ecf20Sopenharmony_ci	{ 3190,	 3936 },
1638c2ecf20Sopenharmony_ci	{ 3400,	 5012 },
1648c2ecf20Sopenharmony_ci	{ 3610,	 6383 },
1658c2ecf20Sopenharmony_ci	{ 3800,	 7943 },
1668c2ecf20Sopenharmony_ci	{ 4210,	12735 },
1678c2ecf20Sopenharmony_ci	{ 4500,	17783 },
1688c2ecf20Sopenharmony_ci	{ 4690,	22131 },
1698c2ecf20Sopenharmony_ci	{ 4810,	25410 }
1708c2ecf20Sopenharmony_ci};
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci/* DVB-S2 Es/N0 estimate in dB/100 vs read value */
1738c2ecf20Sopenharmony_cistatic struct stb0899_tab stb0899_est_tab[] = {
1748c2ecf20Sopenharmony_ci	{    0,	     0 },
1758c2ecf20Sopenharmony_ci	{    0,	     1 },
1768c2ecf20Sopenharmony_ci	{  301,	     2 },
1778c2ecf20Sopenharmony_ci	{ 1204,	    16 },
1788c2ecf20Sopenharmony_ci	{ 1806,	    64 },
1798c2ecf20Sopenharmony_ci	{ 2408,	   256 },
1808c2ecf20Sopenharmony_ci	{ 2709,	   512 },
1818c2ecf20Sopenharmony_ci	{ 3010,	  1023 },
1828c2ecf20Sopenharmony_ci	{ 3311,	  2046 },
1838c2ecf20Sopenharmony_ci	{ 3612,	  4093 },
1848c2ecf20Sopenharmony_ci	{ 3823,	  6653 },
1858c2ecf20Sopenharmony_ci	{ 3913,	  8185 },
1868c2ecf20Sopenharmony_ci	{ 4010,	 10233 },
1878c2ecf20Sopenharmony_ci	{ 4107,	 12794 },
1888c2ecf20Sopenharmony_ci	{ 4214,	 16368 },
1898c2ecf20Sopenharmony_ci	{ 4266,	 18450 },
1908c2ecf20Sopenharmony_ci	{ 4311,	 20464 },
1918c2ecf20Sopenharmony_ci	{ 4353,	 22542 },
1928c2ecf20Sopenharmony_ci	{ 4391,	 24604 },
1938c2ecf20Sopenharmony_ci	{ 4425,	 26607 },
1948c2ecf20Sopenharmony_ci	{ 4457,	 28642 },
1958c2ecf20Sopenharmony_ci	{ 4487,	 30690 },
1968c2ecf20Sopenharmony_ci	{ 4515,	 32734 },
1978c2ecf20Sopenharmony_ci	{ 4612,	 40926 },
1988c2ecf20Sopenharmony_ci	{ 4692,	 49204 },
1998c2ecf20Sopenharmony_ci	{ 4816,	 65464 },
2008c2ecf20Sopenharmony_ci	{ 4913,	 81846 },
2018c2ecf20Sopenharmony_ci	{ 4993,	 98401 },
2028c2ecf20Sopenharmony_ci	{ 5060,	114815 },
2038c2ecf20Sopenharmony_ci	{ 5118,	131220 },
2048c2ecf20Sopenharmony_ci	{ 5200,	158489 },
2058c2ecf20Sopenharmony_ci	{ 5300,	199526 },
2068c2ecf20Sopenharmony_ci	{ 5400,	251189 },
2078c2ecf20Sopenharmony_ci	{ 5500,	316228 },
2088c2ecf20Sopenharmony_ci	{ 5600,	398107 },
2098c2ecf20Sopenharmony_ci	{ 5720,	524807 },
2108c2ecf20Sopenharmony_ci	{ 5721,	526017 },
2118c2ecf20Sopenharmony_ci};
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic int _stb0899_read_reg(struct stb0899_state *state, unsigned int reg)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	int ret;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	u8 b0[] = { reg >> 8, reg & 0xff };
2188c2ecf20Sopenharmony_ci	u8 buf;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	struct i2c_msg msg[] = {
2218c2ecf20Sopenharmony_ci		{
2228c2ecf20Sopenharmony_ci			.addr	= state->config->demod_address,
2238c2ecf20Sopenharmony_ci			.flags	= 0,
2248c2ecf20Sopenharmony_ci			.buf	= b0,
2258c2ecf20Sopenharmony_ci			.len	= 2
2268c2ecf20Sopenharmony_ci		},{
2278c2ecf20Sopenharmony_ci			.addr	= state->config->demod_address,
2288c2ecf20Sopenharmony_ci			.flags	= I2C_M_RD,
2298c2ecf20Sopenharmony_ci			.buf	= &buf,
2308c2ecf20Sopenharmony_ci			.len	= 1
2318c2ecf20Sopenharmony_ci		}
2328c2ecf20Sopenharmony_ci	};
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	ret = i2c_transfer(state->i2c, msg, 2);
2358c2ecf20Sopenharmony_ci	if (ret != 2) {
2368c2ecf20Sopenharmony_ci		if (ret != -ERESTARTSYS)
2378c2ecf20Sopenharmony_ci			dprintk(state->verbose, FE_ERROR, 1,
2388c2ecf20Sopenharmony_ci				"Read error, Reg=[0x%02x], Status=%d",
2398c2ecf20Sopenharmony_ci				reg, ret);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci		return ret < 0 ? ret : -EREMOTEIO;
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci	if (unlikely(*state->verbose >= FE_DEBUGREG))
2448c2ecf20Sopenharmony_ci		dprintk(state->verbose, FE_ERROR, 1, "Reg=[0x%02x], data=%02x",
2458c2ecf20Sopenharmony_ci			reg, buf);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return (unsigned int)buf;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ciint stb0899_read_reg(struct stb0899_state *state, unsigned int reg)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	int result;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	result = _stb0899_read_reg(state, reg);
2558c2ecf20Sopenharmony_ci	/*
2568c2ecf20Sopenharmony_ci	 * Bug ID 9:
2578c2ecf20Sopenharmony_ci	 * access to 0xf2xx/0xf6xx
2588c2ecf20Sopenharmony_ci	 * must be followed by read from 0xf2ff/0xf6ff.
2598c2ecf20Sopenharmony_ci	 */
2608c2ecf20Sopenharmony_ci	if ((reg != 0xf2ff) && (reg != 0xf6ff) &&
2618c2ecf20Sopenharmony_ci	    (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600)))
2628c2ecf20Sopenharmony_ci		_stb0899_read_reg(state, (reg | 0x00ff));
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	return result;
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ciu32 _stb0899_read_s2reg(struct stb0899_state *state,
2688c2ecf20Sopenharmony_ci			u32 stb0899_i2cdev,
2698c2ecf20Sopenharmony_ci			u32 stb0899_base_addr,
2708c2ecf20Sopenharmony_ci			u16 stb0899_reg_offset)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	int status;
2738c2ecf20Sopenharmony_ci	u32 data;
2748c2ecf20Sopenharmony_ci	u8 buf[7] = { 0 };
2758c2ecf20Sopenharmony_ci	u16 tmpaddr;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	u8 buf_0[] = {
2788c2ecf20Sopenharmony_ci		GETBYTE(stb0899_i2cdev, BYTE1),		/* 0xf3	S2 Base Address (MSB)	*/
2798c2ecf20Sopenharmony_ci		GETBYTE(stb0899_i2cdev, BYTE0),		/* 0xfc	S2 Base Address (LSB)	*/
2808c2ecf20Sopenharmony_ci		GETBYTE(stb0899_base_addr, BYTE0),	/* 0x00	Base Address (LSB)	*/
2818c2ecf20Sopenharmony_ci		GETBYTE(stb0899_base_addr, BYTE1),	/* 0x04	Base Address (LSB)	*/
2828c2ecf20Sopenharmony_ci		GETBYTE(stb0899_base_addr, BYTE2),	/* 0x00	Base Address (MSB)	*/
2838c2ecf20Sopenharmony_ci		GETBYTE(stb0899_base_addr, BYTE3),	/* 0x00	Base Address (MSB)	*/
2848c2ecf20Sopenharmony_ci	};
2858c2ecf20Sopenharmony_ci	u8 buf_1[] = {
2868c2ecf20Sopenharmony_ci		0x00,	/* 0xf3	Reg Offset	*/
2878c2ecf20Sopenharmony_ci		0x00,	/* 0x44	Reg Offset	*/
2888c2ecf20Sopenharmony_ci	};
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	struct i2c_msg msg_0 = {
2918c2ecf20Sopenharmony_ci		.addr	= state->config->demod_address,
2928c2ecf20Sopenharmony_ci		.flags	= 0,
2938c2ecf20Sopenharmony_ci		.buf	= buf_0,
2948c2ecf20Sopenharmony_ci		.len	= 6
2958c2ecf20Sopenharmony_ci	};
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	struct i2c_msg msg_1 = {
2988c2ecf20Sopenharmony_ci		.addr	= state->config->demod_address,
2998c2ecf20Sopenharmony_ci		.flags	= 0,
3008c2ecf20Sopenharmony_ci		.buf	= buf_1,
3018c2ecf20Sopenharmony_ci		.len	= 2
3028c2ecf20Sopenharmony_ci	};
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	struct i2c_msg msg_r = {
3058c2ecf20Sopenharmony_ci		.addr	= state->config->demod_address,
3068c2ecf20Sopenharmony_ci		.flags	= I2C_M_RD,
3078c2ecf20Sopenharmony_ci		.buf	= buf,
3088c2ecf20Sopenharmony_ci		.len	= 4
3098c2ecf20Sopenharmony_ci	};
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	tmpaddr = stb0899_reg_offset & 0xff00;
3128c2ecf20Sopenharmony_ci	if (!(stb0899_reg_offset & 0x8))
3138c2ecf20Sopenharmony_ci		tmpaddr = stb0899_reg_offset | 0x20;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	buf_1[0] = GETBYTE(tmpaddr, BYTE1);
3168c2ecf20Sopenharmony_ci	buf_1[1] = GETBYTE(tmpaddr, BYTE0);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	status = i2c_transfer(state->i2c, &msg_0, 1);
3198c2ecf20Sopenharmony_ci	if (status < 1) {
3208c2ecf20Sopenharmony_ci		if (status != -ERESTARTSYS)
3218c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s ERR(1), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n",
3228c2ecf20Sopenharmony_ci			       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci		goto err;
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	/* Dummy	*/
3288c2ecf20Sopenharmony_ci	status = i2c_transfer(state->i2c, &msg_1, 1);
3298c2ecf20Sopenharmony_ci	if (status < 1)
3308c2ecf20Sopenharmony_ci		goto err;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	status = i2c_transfer(state->i2c, &msg_r, 1);
3338c2ecf20Sopenharmony_ci	if (status < 1)
3348c2ecf20Sopenharmony_ci		goto err;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	buf_1[0] = GETBYTE(stb0899_reg_offset, BYTE1);
3378c2ecf20Sopenharmony_ci	buf_1[1] = GETBYTE(stb0899_reg_offset, BYTE0);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	/* Actual	*/
3408c2ecf20Sopenharmony_ci	status = i2c_transfer(state->i2c, &msg_1, 1);
3418c2ecf20Sopenharmony_ci	if (status < 1) {
3428c2ecf20Sopenharmony_ci		if (status != -ERESTARTSYS)
3438c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s ERR(2), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n",
3448c2ecf20Sopenharmony_ci			       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status);
3458c2ecf20Sopenharmony_ci		goto err;
3468c2ecf20Sopenharmony_ci	}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	status = i2c_transfer(state->i2c, &msg_r, 1);
3498c2ecf20Sopenharmony_ci	if (status < 1) {
3508c2ecf20Sopenharmony_ci		if (status != -ERESTARTSYS)
3518c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s ERR(3), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n",
3528c2ecf20Sopenharmony_ci			       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status);
3538c2ecf20Sopenharmony_ci		return status < 0 ? status : -EREMOTEIO;
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	data = MAKEWORD32(buf[3], buf[2], buf[1], buf[0]);
3578c2ecf20Sopenharmony_ci	if (unlikely(*state->verbose >= FE_DEBUGREG))
3588c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Data=[0x%08x]\n",
3598c2ecf20Sopenharmony_ci		       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, data);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	return data;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cierr:
3648c2ecf20Sopenharmony_ci	return status < 0 ? status : -EREMOTEIO;
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ciint stb0899_write_s2reg(struct stb0899_state *state,
3688c2ecf20Sopenharmony_ci			u32 stb0899_i2cdev,
3698c2ecf20Sopenharmony_ci			u32 stb0899_base_addr,
3708c2ecf20Sopenharmony_ci			u16 stb0899_reg_offset,
3718c2ecf20Sopenharmony_ci			u32 stb0899_data)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	int status;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	/* Base Address Setup	*/
3768c2ecf20Sopenharmony_ci	u8 buf_0[] = {
3778c2ecf20Sopenharmony_ci		GETBYTE(stb0899_i2cdev, BYTE1),		/* 0xf3	S2 Base Address (MSB)	*/
3788c2ecf20Sopenharmony_ci		GETBYTE(stb0899_i2cdev, BYTE0),		/* 0xfc	S2 Base Address (LSB)	*/
3798c2ecf20Sopenharmony_ci		GETBYTE(stb0899_base_addr, BYTE0),	/* 0x00	Base Address (LSB)	*/
3808c2ecf20Sopenharmony_ci		GETBYTE(stb0899_base_addr, BYTE1),	/* 0x04	Base Address (LSB)	*/
3818c2ecf20Sopenharmony_ci		GETBYTE(stb0899_base_addr, BYTE2),	/* 0x00	Base Address (MSB)	*/
3828c2ecf20Sopenharmony_ci		GETBYTE(stb0899_base_addr, BYTE3),	/* 0x00	Base Address (MSB)	*/
3838c2ecf20Sopenharmony_ci	};
3848c2ecf20Sopenharmony_ci	u8 buf_1[] = {
3858c2ecf20Sopenharmony_ci		0x00,	/* 0xf3	Reg Offset	*/
3868c2ecf20Sopenharmony_ci		0x00,	/* 0x44	Reg Offset	*/
3878c2ecf20Sopenharmony_ci		0x00,	/* data			*/
3888c2ecf20Sopenharmony_ci		0x00,	/* data			*/
3898c2ecf20Sopenharmony_ci		0x00,	/* data			*/
3908c2ecf20Sopenharmony_ci		0x00,	/* data			*/
3918c2ecf20Sopenharmony_ci	};
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	struct i2c_msg msg_0 = {
3948c2ecf20Sopenharmony_ci		.addr	= state->config->demod_address,
3958c2ecf20Sopenharmony_ci		.flags	= 0,
3968c2ecf20Sopenharmony_ci		.buf	= buf_0,
3978c2ecf20Sopenharmony_ci		.len	= 6
3988c2ecf20Sopenharmony_ci	};
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	struct i2c_msg msg_1 = {
4018c2ecf20Sopenharmony_ci		.addr	= state->config->demod_address,
4028c2ecf20Sopenharmony_ci		.flags	= 0,
4038c2ecf20Sopenharmony_ci		.buf	= buf_1,
4048c2ecf20Sopenharmony_ci		.len	= 6
4058c2ecf20Sopenharmony_ci	};
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	buf_1[0] = GETBYTE(stb0899_reg_offset, BYTE1);
4088c2ecf20Sopenharmony_ci	buf_1[1] = GETBYTE(stb0899_reg_offset, BYTE0);
4098c2ecf20Sopenharmony_ci	buf_1[2] = GETBYTE(stb0899_data, BYTE0);
4108c2ecf20Sopenharmony_ci	buf_1[3] = GETBYTE(stb0899_data, BYTE1);
4118c2ecf20Sopenharmony_ci	buf_1[4] = GETBYTE(stb0899_data, BYTE2);
4128c2ecf20Sopenharmony_ci	buf_1[5] = GETBYTE(stb0899_data, BYTE3);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	if (unlikely(*state->verbose >= FE_DEBUGREG))
4158c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x]\n",
4168c2ecf20Sopenharmony_ci		       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	status = i2c_transfer(state->i2c, &msg_0, 1);
4198c2ecf20Sopenharmony_ci	if (unlikely(status < 1)) {
4208c2ecf20Sopenharmony_ci		if (status != -ERESTARTSYS)
4218c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s ERR (1), Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x], status=%d\n",
4228c2ecf20Sopenharmony_ci			       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data, status);
4238c2ecf20Sopenharmony_ci		goto err;
4248c2ecf20Sopenharmony_ci	}
4258c2ecf20Sopenharmony_ci	status = i2c_transfer(state->i2c, &msg_1, 1);
4268c2ecf20Sopenharmony_ci	if (unlikely(status < 1)) {
4278c2ecf20Sopenharmony_ci		if (status != -ERESTARTSYS)
4288c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s ERR (2), Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x], status=%d\n",
4298c2ecf20Sopenharmony_ci			       __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data, status);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci		return status < 0 ? status : -EREMOTEIO;
4328c2ecf20Sopenharmony_ci	}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	return 0;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cierr:
4378c2ecf20Sopenharmony_ci	return status < 0 ? status : -EREMOTEIO;
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ciint stb0899_read_regs(struct stb0899_state *state, unsigned int reg, u8 *buf, u32 count)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	int status;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	u8 b0[] = { reg >> 8, reg & 0xff };
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	struct i2c_msg msg[] = {
4478c2ecf20Sopenharmony_ci		{
4488c2ecf20Sopenharmony_ci			.addr	= state->config->demod_address,
4498c2ecf20Sopenharmony_ci			.flags	= 0,
4508c2ecf20Sopenharmony_ci			.buf	= b0,
4518c2ecf20Sopenharmony_ci			.len	= 2
4528c2ecf20Sopenharmony_ci		},{
4538c2ecf20Sopenharmony_ci			.addr	= state->config->demod_address,
4548c2ecf20Sopenharmony_ci			.flags	= I2C_M_RD,
4558c2ecf20Sopenharmony_ci			.buf	= buf,
4568c2ecf20Sopenharmony_ci			.len	= count
4578c2ecf20Sopenharmony_ci		}
4588c2ecf20Sopenharmony_ci	};
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	status = i2c_transfer(state->i2c, msg, 2);
4618c2ecf20Sopenharmony_ci	if (status != 2) {
4628c2ecf20Sopenharmony_ci		if (status != -ERESTARTSYS)
4638c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s Read error, Reg=[0x%04x], Count=%u, Status=%d\n",
4648c2ecf20Sopenharmony_ci			       __func__, reg, count, status);
4658c2ecf20Sopenharmony_ci		goto err;
4668c2ecf20Sopenharmony_ci	}
4678c2ecf20Sopenharmony_ci	/*
4688c2ecf20Sopenharmony_ci	 * Bug ID 9:
4698c2ecf20Sopenharmony_ci	 * access to 0xf2xx/0xf6xx
4708c2ecf20Sopenharmony_ci	 * must be followed by read from 0xf2ff/0xf6ff.
4718c2ecf20Sopenharmony_ci	 */
4728c2ecf20Sopenharmony_ci	if ((reg != 0xf2ff) && (reg != 0xf6ff) &&
4738c2ecf20Sopenharmony_ci	    (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600)))
4748c2ecf20Sopenharmony_ci		_stb0899_read_reg(state, (reg | 0x00ff));
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUGREG, 1,
4778c2ecf20Sopenharmony_ci		"%s [0x%04x]: %*ph", __func__, reg, count, buf);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	return 0;
4808c2ecf20Sopenharmony_cierr:
4818c2ecf20Sopenharmony_ci	return status < 0 ? status : -EREMOTEIO;
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ciint stb0899_write_regs(struct stb0899_state *state, unsigned int reg, u8 *data, u32 count)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	int ret;
4878c2ecf20Sopenharmony_ci	u8 buf[MAX_XFER_SIZE];
4888c2ecf20Sopenharmony_ci	struct i2c_msg i2c_msg = {
4898c2ecf20Sopenharmony_ci		.addr	= state->config->demod_address,
4908c2ecf20Sopenharmony_ci		.flags	= 0,
4918c2ecf20Sopenharmony_ci		.buf	= buf,
4928c2ecf20Sopenharmony_ci		.len	= 2 + count
4938c2ecf20Sopenharmony_ci	};
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	if (2 + count > sizeof(buf)) {
4968c2ecf20Sopenharmony_ci		printk(KERN_WARNING
4978c2ecf20Sopenharmony_ci		       "%s: i2c wr reg=%04x: len=%d is too big!\n",
4988c2ecf20Sopenharmony_ci		       KBUILD_MODNAME, reg, count);
4998c2ecf20Sopenharmony_ci		return -EINVAL;
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	buf[0] = reg >> 8;
5038c2ecf20Sopenharmony_ci	buf[1] = reg & 0xff;
5048c2ecf20Sopenharmony_ci	memcpy(&buf[2], data, count);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUGREG, 1,
5078c2ecf20Sopenharmony_ci		"%s [0x%04x]: %*ph", __func__, reg, count, data);
5088c2ecf20Sopenharmony_ci	ret = i2c_transfer(state->i2c, &i2c_msg, 1);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	/*
5118c2ecf20Sopenharmony_ci	 * Bug ID 9:
5128c2ecf20Sopenharmony_ci	 * access to 0xf2xx/0xf6xx
5138c2ecf20Sopenharmony_ci	 * must be followed by read from 0xf2ff/0xf6ff.
5148c2ecf20Sopenharmony_ci	 */
5158c2ecf20Sopenharmony_ci	if ((((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600)))
5168c2ecf20Sopenharmony_ci		stb0899_read_reg(state, (reg | 0x00ff));
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	if (ret != 1) {
5198c2ecf20Sopenharmony_ci		if (ret != -ERESTARTSYS)
5208c2ecf20Sopenharmony_ci			dprintk(state->verbose, FE_ERROR, 1, "Reg=[0x%04x], Data=[0x%02x ...], Count=%u, Status=%d",
5218c2ecf20Sopenharmony_ci				reg, data[0], count, ret);
5228c2ecf20Sopenharmony_ci		return ret < 0 ? ret : -EREMOTEIO;
5238c2ecf20Sopenharmony_ci	}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	return 0;
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ciint stb0899_write_reg(struct stb0899_state *state, unsigned int reg, u8 data)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	u8 tmp = data;
5318c2ecf20Sopenharmony_ci	return stb0899_write_regs(state, reg, &tmp, 1);
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci/*
5358c2ecf20Sopenharmony_ci * stb0899_get_mclk
5368c2ecf20Sopenharmony_ci * Get STB0899 master clock frequency
5378c2ecf20Sopenharmony_ci * ExtClk: external clock frequency (Hz)
5388c2ecf20Sopenharmony_ci */
5398c2ecf20Sopenharmony_cistatic u32 stb0899_get_mclk(struct stb0899_state *state)
5408c2ecf20Sopenharmony_ci{
5418c2ecf20Sopenharmony_ci	u32 mclk = 0, div = 0;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	div = stb0899_read_reg(state, STB0899_NCOARSE);
5448c2ecf20Sopenharmony_ci	mclk = (div + 1) * state->config->xtal_freq / 6;
5458c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUG, 1, "div=%d, mclk=%d", div, mclk);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	return mclk;
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci/*
5518c2ecf20Sopenharmony_ci * stb0899_set_mclk
5528c2ecf20Sopenharmony_ci * Set STB0899 master Clock frequency
5538c2ecf20Sopenharmony_ci * Mclk: demodulator master clock
5548c2ecf20Sopenharmony_ci * ExtClk: external clock frequency (Hz)
5558c2ecf20Sopenharmony_ci */
5568c2ecf20Sopenharmony_cistatic void stb0899_set_mclk(struct stb0899_state *state, u32 Mclk)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	struct stb0899_internal *internal = &state->internal;
5598c2ecf20Sopenharmony_ci	u8 mdiv = 0;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUG, 1, "state->config=%p", state->config);
5628c2ecf20Sopenharmony_ci	mdiv = ((6 * Mclk) / state->config->xtal_freq) - 1;
5638c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUG, 1, "mdiv=%d", mdiv);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	stb0899_write_reg(state, STB0899_NCOARSE, mdiv);
5668c2ecf20Sopenharmony_ci	internal->master_clk = stb0899_get_mclk(state);
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUG, 1, "MasterCLOCK=%d", internal->master_clk);
5698c2ecf20Sopenharmony_ci}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_cistatic int stb0899_postproc(struct stb0899_state *state, u8 ctl, int enable)
5728c2ecf20Sopenharmony_ci{
5738c2ecf20Sopenharmony_ci	struct stb0899_config *config		= state->config;
5748c2ecf20Sopenharmony_ci	const struct stb0899_postproc *postproc	= config->postproc;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	/* post process event */
5778c2ecf20Sopenharmony_ci	if (postproc) {
5788c2ecf20Sopenharmony_ci		if (enable) {
5798c2ecf20Sopenharmony_ci			if (postproc[ctl].level == STB0899_GPIOPULLUP)
5808c2ecf20Sopenharmony_ci				stb0899_write_reg(state, postproc[ctl].gpio, 0x02);
5818c2ecf20Sopenharmony_ci			else
5828c2ecf20Sopenharmony_ci				stb0899_write_reg(state, postproc[ctl].gpio, 0x82);
5838c2ecf20Sopenharmony_ci		} else {
5848c2ecf20Sopenharmony_ci			if (postproc[ctl].level == STB0899_GPIOPULLUP)
5858c2ecf20Sopenharmony_ci				stb0899_write_reg(state, postproc[ctl].gpio, 0x82);
5868c2ecf20Sopenharmony_ci			else
5878c2ecf20Sopenharmony_ci				stb0899_write_reg(state, postproc[ctl].gpio, 0x02);
5888c2ecf20Sopenharmony_ci		}
5898c2ecf20Sopenharmony_ci	}
5908c2ecf20Sopenharmony_ci	return 0;
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_cistatic void stb0899_detach(struct dvb_frontend *fe)
5948c2ecf20Sopenharmony_ci{
5958c2ecf20Sopenharmony_ci	struct stb0899_state *state = fe->demodulator_priv;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	/* post process event */
5988c2ecf20Sopenharmony_ci	stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0);
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cistatic void stb0899_release(struct dvb_frontend *fe)
6028c2ecf20Sopenharmony_ci{
6038c2ecf20Sopenharmony_ci	struct stb0899_state *state = fe->demodulator_priv;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUG, 1, "Release Frontend");
6068c2ecf20Sopenharmony_ci	kfree(state);
6078c2ecf20Sopenharmony_ci}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci/*
6108c2ecf20Sopenharmony_ci * stb0899_get_alpha
6118c2ecf20Sopenharmony_ci * return: rolloff
6128c2ecf20Sopenharmony_ci */
6138c2ecf20Sopenharmony_cistatic int stb0899_get_alpha(struct stb0899_state *state)
6148c2ecf20Sopenharmony_ci{
6158c2ecf20Sopenharmony_ci	u8 mode_coeff;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	mode_coeff = stb0899_read_reg(state, STB0899_DEMOD);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	if (STB0899_GETFIELD(MODECOEFF, mode_coeff) == 1)
6208c2ecf20Sopenharmony_ci		return 20;
6218c2ecf20Sopenharmony_ci	else
6228c2ecf20Sopenharmony_ci		return 35;
6238c2ecf20Sopenharmony_ci}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci/*
6268c2ecf20Sopenharmony_ci * stb0899_init_calc
6278c2ecf20Sopenharmony_ci */
6288c2ecf20Sopenharmony_cistatic void stb0899_init_calc(struct stb0899_state *state)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	struct stb0899_internal *internal = &state->internal;
6318c2ecf20Sopenharmony_ci	int master_clk;
6328c2ecf20Sopenharmony_ci	u8 agc[2];
6338c2ecf20Sopenharmony_ci	u32 reg;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	/* Read registers (in burst mode)	*/
6368c2ecf20Sopenharmony_ci	stb0899_read_regs(state, STB0899_AGC1REF, agc, 2); /* AGC1R and AGC2O	*/
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	/* Initial calculations	*/
6398c2ecf20Sopenharmony_ci	master_clk			= stb0899_get_mclk(state);
6408c2ecf20Sopenharmony_ci	internal->t_agc1		= 0;
6418c2ecf20Sopenharmony_ci	internal->t_agc2		= 0;
6428c2ecf20Sopenharmony_ci	internal->master_clk		= master_clk;
6438c2ecf20Sopenharmony_ci	internal->mclk			= master_clk / 65536L;
6448c2ecf20Sopenharmony_ci	internal->rolloff		= stb0899_get_alpha(state);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	/* DVBS2 Initial calculations	*/
6478c2ecf20Sopenharmony_ci	/* Set AGC value to the middle	*/
6488c2ecf20Sopenharmony_ci	internal->agc_gain		= 8154;
6498c2ecf20Sopenharmony_ci	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL);
6508c2ecf20Sopenharmony_ci	STB0899_SETFIELD_VAL(IF_GAIN_INIT, reg, internal->agc_gain);
6518c2ecf20Sopenharmony_ci	stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg);
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	reg = STB0899_READ_S2REG(STB0899_S2DEMOD, RRC_ALPHA);
6548c2ecf20Sopenharmony_ci	internal->rrc_alpha		= STB0899_GETFIELD(RRC_ALPHA, reg);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	internal->center_freq		= 0;
6578c2ecf20Sopenharmony_ci	internal->av_frame_coarse	= 10;
6588c2ecf20Sopenharmony_ci	internal->av_frame_fine		= 20;
6598c2ecf20Sopenharmony_ci	internal->step_size		= 2;
6608c2ecf20Sopenharmony_ci/*
6618c2ecf20Sopenharmony_ci	if ((pParams->SpectralInv == FE_IQ_NORMAL) || (pParams->SpectralInv == FE_IQ_AUTO))
6628c2ecf20Sopenharmony_ci		pParams->IQLocked = 0;
6638c2ecf20Sopenharmony_ci	else
6648c2ecf20Sopenharmony_ci		pParams->IQLocked = 1;
6658c2ecf20Sopenharmony_ci*/
6668c2ecf20Sopenharmony_ci}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_cistatic int stb0899_wait_diseqc_fifo_empty(struct stb0899_state *state, int timeout)
6698c2ecf20Sopenharmony_ci{
6708c2ecf20Sopenharmony_ci	u8 reg = 0;
6718c2ecf20Sopenharmony_ci	unsigned long start = jiffies;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	while (1) {
6748c2ecf20Sopenharmony_ci		reg = stb0899_read_reg(state, STB0899_DISSTATUS);
6758c2ecf20Sopenharmony_ci		if (!STB0899_GETFIELD(FIFOFULL, reg))
6768c2ecf20Sopenharmony_ci			break;
6778c2ecf20Sopenharmony_ci		if (time_after(jiffies, start + timeout)) {
6788c2ecf20Sopenharmony_ci			dprintk(state->verbose, FE_ERROR, 1, "timed out !!");
6798c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
6808c2ecf20Sopenharmony_ci		}
6818c2ecf20Sopenharmony_ci	}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	return 0;
6848c2ecf20Sopenharmony_ci}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_cistatic int stb0899_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	struct stb0899_state *state = fe->demodulator_priv;
6898c2ecf20Sopenharmony_ci	u8 reg, i;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	if (cmd->msg_len > sizeof(cmd->msg))
6928c2ecf20Sopenharmony_ci		return -EINVAL;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	/* enable FIFO precharge	*/
6958c2ecf20Sopenharmony_ci	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
6968c2ecf20Sopenharmony_ci	STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 1);
6978c2ecf20Sopenharmony_ci	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
6988c2ecf20Sopenharmony_ci	for (i = 0; i < cmd->msg_len; i++) {
6998c2ecf20Sopenharmony_ci		/* wait for FIFO empty	*/
7008c2ecf20Sopenharmony_ci		if (stb0899_wait_diseqc_fifo_empty(state, 100) < 0)
7018c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_DISFIFO, cmd->msg[i]);
7048c2ecf20Sopenharmony_ci	}
7058c2ecf20Sopenharmony_ci	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
7068c2ecf20Sopenharmony_ci	STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0);
7078c2ecf20Sopenharmony_ci	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
7088c2ecf20Sopenharmony_ci	msleep(100);
7098c2ecf20Sopenharmony_ci	return 0;
7108c2ecf20Sopenharmony_ci}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_cistatic int stb0899_wait_diseqc_rxidle(struct stb0899_state *state, int timeout)
7138c2ecf20Sopenharmony_ci{
7148c2ecf20Sopenharmony_ci	u8 reg = 0;
7158c2ecf20Sopenharmony_ci	unsigned long start = jiffies;
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	while (!STB0899_GETFIELD(RXEND, reg)) {
7188c2ecf20Sopenharmony_ci		reg = stb0899_read_reg(state, STB0899_DISRX_ST0);
7198c2ecf20Sopenharmony_ci		if (time_after(jiffies, start + timeout)) {
7208c2ecf20Sopenharmony_ci			dprintk(state->verbose, FE_ERROR, 1, "timed out!!");
7218c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
7228c2ecf20Sopenharmony_ci		}
7238c2ecf20Sopenharmony_ci		msleep(10);
7248c2ecf20Sopenharmony_ci	}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	return 0;
7278c2ecf20Sopenharmony_ci}
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_cistatic int stb0899_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply)
7308c2ecf20Sopenharmony_ci{
7318c2ecf20Sopenharmony_ci	struct stb0899_state *state = fe->demodulator_priv;
7328c2ecf20Sopenharmony_ci	u8 reg, length = 0, i;
7338c2ecf20Sopenharmony_ci	int result;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	if (stb0899_wait_diseqc_rxidle(state, 100) < 0)
7368c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	reg = stb0899_read_reg(state, STB0899_DISRX_ST0);
7398c2ecf20Sopenharmony_ci	if (STB0899_GETFIELD(RXEND, reg)) {
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci		reg = stb0899_read_reg(state, STB0899_DISRX_ST1);
7428c2ecf20Sopenharmony_ci		length = STB0899_GETFIELD(FIFOBYTENBR, reg);
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci		if (length > sizeof (reply->msg)) {
7458c2ecf20Sopenharmony_ci			result = -EOVERFLOW;
7468c2ecf20Sopenharmony_ci			goto exit;
7478c2ecf20Sopenharmony_ci		}
7488c2ecf20Sopenharmony_ci		reply->msg_len = length;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci		/* extract data */
7518c2ecf20Sopenharmony_ci		for (i = 0; i < length; i++)
7528c2ecf20Sopenharmony_ci			reply->msg[i] = stb0899_read_reg(state, STB0899_DISFIFO);
7538c2ecf20Sopenharmony_ci	}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	return 0;
7568c2ecf20Sopenharmony_ciexit:
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	return result;
7598c2ecf20Sopenharmony_ci}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_cistatic int stb0899_wait_diseqc_txidle(struct stb0899_state *state, int timeout)
7628c2ecf20Sopenharmony_ci{
7638c2ecf20Sopenharmony_ci	u8 reg = 0;
7648c2ecf20Sopenharmony_ci	unsigned long start = jiffies;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	while (!STB0899_GETFIELD(TXIDLE, reg)) {
7678c2ecf20Sopenharmony_ci		reg = stb0899_read_reg(state, STB0899_DISSTATUS);
7688c2ecf20Sopenharmony_ci		if (time_after(jiffies, start + timeout)) {
7698c2ecf20Sopenharmony_ci			dprintk(state->verbose, FE_ERROR, 1, "timed out!!");
7708c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
7718c2ecf20Sopenharmony_ci		}
7728c2ecf20Sopenharmony_ci		msleep(10);
7738c2ecf20Sopenharmony_ci	}
7748c2ecf20Sopenharmony_ci	return 0;
7758c2ecf20Sopenharmony_ci}
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_cistatic int stb0899_send_diseqc_burst(struct dvb_frontend *fe,
7788c2ecf20Sopenharmony_ci				     enum fe_sec_mini_cmd burst)
7798c2ecf20Sopenharmony_ci{
7808c2ecf20Sopenharmony_ci	struct stb0899_state *state = fe->demodulator_priv;
7818c2ecf20Sopenharmony_ci	u8 reg, old_state;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	/* wait for diseqc idle	*/
7848c2ecf20Sopenharmony_ci	if (stb0899_wait_diseqc_txidle(state, 100) < 0)
7858c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
7888c2ecf20Sopenharmony_ci	old_state = reg;
7898c2ecf20Sopenharmony_ci	/* set to burst mode	*/
7908c2ecf20Sopenharmony_ci	STB0899_SETFIELD_VAL(DISEQCMODE, reg, 0x03);
7918c2ecf20Sopenharmony_ci	STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x01);
7928c2ecf20Sopenharmony_ci	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
7938c2ecf20Sopenharmony_ci	switch (burst) {
7948c2ecf20Sopenharmony_ci	case SEC_MINI_A:
7958c2ecf20Sopenharmony_ci		/* unmodulated	*/
7968c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_DISFIFO, 0x00);
7978c2ecf20Sopenharmony_ci		break;
7988c2ecf20Sopenharmony_ci	case SEC_MINI_B:
7998c2ecf20Sopenharmony_ci		/* modulated	*/
8008c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_DISFIFO, 0xff);
8018c2ecf20Sopenharmony_ci		break;
8028c2ecf20Sopenharmony_ci	}
8038c2ecf20Sopenharmony_ci	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
8048c2ecf20Sopenharmony_ci	STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x00);
8058c2ecf20Sopenharmony_ci	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
8068c2ecf20Sopenharmony_ci	/* wait for diseqc idle	*/
8078c2ecf20Sopenharmony_ci	if (stb0899_wait_diseqc_txidle(state, 100) < 0)
8088c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	/* restore state	*/
8118c2ecf20Sopenharmony_ci	stb0899_write_reg(state, STB0899_DISCNTRL1, old_state);
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	return 0;
8148c2ecf20Sopenharmony_ci}
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_cistatic int stb0899_diseqc_init(struct stb0899_state *state)
8178c2ecf20Sopenharmony_ci{
8188c2ecf20Sopenharmony_ci/*
8198c2ecf20Sopenharmony_ci	struct dvb_diseqc_slave_reply rx_data;
8208c2ecf20Sopenharmony_ci*/
8218c2ecf20Sopenharmony_ci	u8 f22_tx, reg;
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	u32 mclk, tx_freq = 22000;/* count = 0, i; */
8248c2ecf20Sopenharmony_ci	reg = stb0899_read_reg(state, STB0899_DISCNTRL2);
8258c2ecf20Sopenharmony_ci	STB0899_SETFIELD_VAL(ONECHIP_TRX, reg, 0);
8268c2ecf20Sopenharmony_ci	stb0899_write_reg(state, STB0899_DISCNTRL2, reg);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	/* disable Tx spy	*/
8298c2ecf20Sopenharmony_ci	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
8308c2ecf20Sopenharmony_ci	STB0899_SETFIELD_VAL(DISEQCRESET, reg, 1);
8318c2ecf20Sopenharmony_ci	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
8348c2ecf20Sopenharmony_ci	STB0899_SETFIELD_VAL(DISEQCRESET, reg, 0);
8358c2ecf20Sopenharmony_ci	stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	mclk = stb0899_get_mclk(state);
8388c2ecf20Sopenharmony_ci	f22_tx = mclk / (tx_freq * 32);
8398c2ecf20Sopenharmony_ci	stb0899_write_reg(state, STB0899_DISF22, f22_tx); /* DiSEqC Tx freq	*/
8408c2ecf20Sopenharmony_ci	state->rx_freq = 20000;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	return 0;
8438c2ecf20Sopenharmony_ci}
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_cistatic int stb0899_sleep(struct dvb_frontend *fe)
8468c2ecf20Sopenharmony_ci{
8478c2ecf20Sopenharmony_ci	struct stb0899_state *state = fe->demodulator_priv;
8488c2ecf20Sopenharmony_ci/*
8498c2ecf20Sopenharmony_ci	u8 reg;
8508c2ecf20Sopenharmony_ci*/
8518c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUG, 1, "Going to Sleep .. (Really tired .. :-))");
8528c2ecf20Sopenharmony_ci	/* post process event */
8538c2ecf20Sopenharmony_ci	stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0);
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	return 0;
8568c2ecf20Sopenharmony_ci}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_cistatic int stb0899_wakeup(struct dvb_frontend *fe)
8598c2ecf20Sopenharmony_ci{
8608c2ecf20Sopenharmony_ci	int rc;
8618c2ecf20Sopenharmony_ci	struct stb0899_state *state = fe->demodulator_priv;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	if ((rc = stb0899_write_reg(state, STB0899_SYNTCTRL, STB0899_SELOSCI)))
8648c2ecf20Sopenharmony_ci		return rc;
8658c2ecf20Sopenharmony_ci	/* Activate all clocks; DVB-S2 registers are inaccessible otherwise. */
8668c2ecf20Sopenharmony_ci	if ((rc = stb0899_write_reg(state, STB0899_STOPCLK1, 0x00)))
8678c2ecf20Sopenharmony_ci		return rc;
8688c2ecf20Sopenharmony_ci	if ((rc = stb0899_write_reg(state, STB0899_STOPCLK2, 0x00)))
8698c2ecf20Sopenharmony_ci		return rc;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	/* post process event */
8728c2ecf20Sopenharmony_ci	stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 1);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	return 0;
8758c2ecf20Sopenharmony_ci}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_cistatic int stb0899_init(struct dvb_frontend *fe)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	int i;
8808c2ecf20Sopenharmony_ci	struct stb0899_state *state = fe->demodulator_priv;
8818c2ecf20Sopenharmony_ci	struct stb0899_config *config = state->config;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUG, 1, "Initializing STB0899 ... ");
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	/* init device		*/
8868c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUG, 1, "init device");
8878c2ecf20Sopenharmony_ci	for (i = 0; config->init_dev[i].address != 0xffff; i++)
8888c2ecf20Sopenharmony_ci		stb0899_write_reg(state, config->init_dev[i].address, config->init_dev[i].data);
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUG, 1, "init S2 demod");
8918c2ecf20Sopenharmony_ci	/* init S2 demod	*/
8928c2ecf20Sopenharmony_ci	for (i = 0; config->init_s2_demod[i].offset != 0xffff; i++)
8938c2ecf20Sopenharmony_ci		stb0899_write_s2reg(state, STB0899_S2DEMOD,
8948c2ecf20Sopenharmony_ci				    config->init_s2_demod[i].base_address,
8958c2ecf20Sopenharmony_ci				    config->init_s2_demod[i].offset,
8968c2ecf20Sopenharmony_ci				    config->init_s2_demod[i].data);
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUG, 1, "init S1 demod");
8998c2ecf20Sopenharmony_ci	/* init S1 demod	*/
9008c2ecf20Sopenharmony_ci	for (i = 0; config->init_s1_demod[i].address != 0xffff; i++)
9018c2ecf20Sopenharmony_ci		stb0899_write_reg(state, config->init_s1_demod[i].address, config->init_s1_demod[i].data);
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUG, 1, "init S2 FEC");
9048c2ecf20Sopenharmony_ci	/* init S2 fec		*/
9058c2ecf20Sopenharmony_ci	for (i = 0; config->init_s2_fec[i].offset != 0xffff; i++)
9068c2ecf20Sopenharmony_ci		stb0899_write_s2reg(state, STB0899_S2FEC,
9078c2ecf20Sopenharmony_ci				    config->init_s2_fec[i].base_address,
9088c2ecf20Sopenharmony_ci				    config->init_s2_fec[i].offset,
9098c2ecf20Sopenharmony_ci				    config->init_s2_fec[i].data);
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUG, 1, "init TST");
9128c2ecf20Sopenharmony_ci	/* init test		*/
9138c2ecf20Sopenharmony_ci	for (i = 0; config->init_tst[i].address != 0xffff; i++)
9148c2ecf20Sopenharmony_ci		stb0899_write_reg(state, config->init_tst[i].address, config->init_tst[i].data);
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	stb0899_init_calc(state);
9178c2ecf20Sopenharmony_ci	stb0899_diseqc_init(state);
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	return 0;
9208c2ecf20Sopenharmony_ci}
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_cistatic int stb0899_table_lookup(const struct stb0899_tab *tab, int max, int val)
9238c2ecf20Sopenharmony_ci{
9248c2ecf20Sopenharmony_ci	int res = 0;
9258c2ecf20Sopenharmony_ci	int min = 0, med;
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	if (val < tab[min].read)
9288c2ecf20Sopenharmony_ci		res = tab[min].real;
9298c2ecf20Sopenharmony_ci	else if (val >= tab[max].read)
9308c2ecf20Sopenharmony_ci		res = tab[max].real;
9318c2ecf20Sopenharmony_ci	else {
9328c2ecf20Sopenharmony_ci		while ((max - min) > 1) {
9338c2ecf20Sopenharmony_ci			med = (max + min) / 2;
9348c2ecf20Sopenharmony_ci			if (val >= tab[min].read && val < tab[med].read)
9358c2ecf20Sopenharmony_ci				max = med;
9368c2ecf20Sopenharmony_ci			else
9378c2ecf20Sopenharmony_ci				min = med;
9388c2ecf20Sopenharmony_ci		}
9398c2ecf20Sopenharmony_ci		res = ((val - tab[min].read) *
9408c2ecf20Sopenharmony_ci		       (tab[max].real - tab[min].real) /
9418c2ecf20Sopenharmony_ci		       (tab[max].read - tab[min].read)) +
9428c2ecf20Sopenharmony_ci			tab[min].real;
9438c2ecf20Sopenharmony_ci	}
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	return res;
9468c2ecf20Sopenharmony_ci}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_cistatic int stb0899_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
9498c2ecf20Sopenharmony_ci{
9508c2ecf20Sopenharmony_ci	struct stb0899_state *state		= fe->demodulator_priv;
9518c2ecf20Sopenharmony_ci	struct stb0899_internal *internal	= &state->internal;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	int val;
9548c2ecf20Sopenharmony_ci	u32 reg;
9558c2ecf20Sopenharmony_ci	*strength = 0;
9568c2ecf20Sopenharmony_ci	switch (state->delsys) {
9578c2ecf20Sopenharmony_ci	case SYS_DVBS:
9588c2ecf20Sopenharmony_ci	case SYS_DSS:
9598c2ecf20Sopenharmony_ci		if (internal->lock) {
9608c2ecf20Sopenharmony_ci			reg  = stb0899_read_reg(state, STB0899_VSTATUS);
9618c2ecf20Sopenharmony_ci			if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) {
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci				reg = stb0899_read_reg(state, STB0899_AGCIQIN);
9648c2ecf20Sopenharmony_ci				val = (s32)(s8)STB0899_GETFIELD(AGCIQVALUE, reg);
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci				*strength = stb0899_table_lookup(stb0899_dvbsrf_tab, ARRAY_SIZE(stb0899_dvbsrf_tab) - 1, val);
9678c2ecf20Sopenharmony_ci				*strength += 750;
9688c2ecf20Sopenharmony_ci				dprintk(state->verbose, FE_DEBUG, 1, "AGCIQVALUE = 0x%02x, C = %d * 0.1 dBm",
9698c2ecf20Sopenharmony_ci					val & 0xff, *strength);
9708c2ecf20Sopenharmony_ci			}
9718c2ecf20Sopenharmony_ci		}
9728c2ecf20Sopenharmony_ci		break;
9738c2ecf20Sopenharmony_ci	case SYS_DVBS2:
9748c2ecf20Sopenharmony_ci		if (internal->lock) {
9758c2ecf20Sopenharmony_ci			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_GAIN);
9768c2ecf20Sopenharmony_ci			val = STB0899_GETFIELD(IF_AGC_GAIN, reg);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci			*strength = stb0899_table_lookup(stb0899_dvbs2rf_tab, ARRAY_SIZE(stb0899_dvbs2rf_tab) - 1, val);
9798c2ecf20Sopenharmony_ci			*strength += 950;
9808c2ecf20Sopenharmony_ci			dprintk(state->verbose, FE_DEBUG, 1, "IF_AGC_GAIN = 0x%04x, C = %d * 0.1 dBm",
9818c2ecf20Sopenharmony_ci				val & 0x3fff, *strength);
9828c2ecf20Sopenharmony_ci		}
9838c2ecf20Sopenharmony_ci		break;
9848c2ecf20Sopenharmony_ci	default:
9858c2ecf20Sopenharmony_ci		dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system");
9868c2ecf20Sopenharmony_ci		return -EINVAL;
9878c2ecf20Sopenharmony_ci	}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	return 0;
9908c2ecf20Sopenharmony_ci}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_cistatic int stb0899_read_snr(struct dvb_frontend *fe, u16 *snr)
9938c2ecf20Sopenharmony_ci{
9948c2ecf20Sopenharmony_ci	struct stb0899_state *state		= fe->demodulator_priv;
9958c2ecf20Sopenharmony_ci	struct stb0899_internal *internal	= &state->internal;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	unsigned int val, quant, quantn = -1, est, estn = -1;
9988c2ecf20Sopenharmony_ci	u8 buf[2];
9998c2ecf20Sopenharmony_ci	u32 reg;
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	*snr = 0;
10028c2ecf20Sopenharmony_ci	reg  = stb0899_read_reg(state, STB0899_VSTATUS);
10038c2ecf20Sopenharmony_ci	switch (state->delsys) {
10048c2ecf20Sopenharmony_ci	case SYS_DVBS:
10058c2ecf20Sopenharmony_ci	case SYS_DSS:
10068c2ecf20Sopenharmony_ci		if (internal->lock) {
10078c2ecf20Sopenharmony_ci			if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) {
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci				stb0899_read_regs(state, STB0899_NIRM, buf, 2);
10108c2ecf20Sopenharmony_ci				val = MAKEWORD16(buf[0], buf[1]);
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci				*snr = stb0899_table_lookup(stb0899_cn_tab, ARRAY_SIZE(stb0899_cn_tab) - 1, val);
10138c2ecf20Sopenharmony_ci				dprintk(state->verbose, FE_DEBUG, 1, "NIR = 0x%02x%02x = %u, C/N = %d * 0.1 dBm\n",
10148c2ecf20Sopenharmony_ci					buf[0], buf[1], val, *snr);
10158c2ecf20Sopenharmony_ci			}
10168c2ecf20Sopenharmony_ci		}
10178c2ecf20Sopenharmony_ci		break;
10188c2ecf20Sopenharmony_ci	case SYS_DVBS2:
10198c2ecf20Sopenharmony_ci		if (internal->lock) {
10208c2ecf20Sopenharmony_ci			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1);
10218c2ecf20Sopenharmony_ci			quant = STB0899_GETFIELD(UWP_ESN0_QUANT, reg);
10228c2ecf20Sopenharmony_ci			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2);
10238c2ecf20Sopenharmony_ci			est = STB0899_GETFIELD(ESN0_EST, reg);
10248c2ecf20Sopenharmony_ci			if (est == 1)
10258c2ecf20Sopenharmony_ci				val = 301; /* C/N = 30.1 dB */
10268c2ecf20Sopenharmony_ci			else if (est == 2)
10278c2ecf20Sopenharmony_ci				val = 270; /* C/N = 27.0 dB */
10288c2ecf20Sopenharmony_ci			else {
10298c2ecf20Sopenharmony_ci				/* quantn = 100 * log(quant^2) */
10308c2ecf20Sopenharmony_ci				quantn = stb0899_table_lookup(stb0899_quant_tab, ARRAY_SIZE(stb0899_quant_tab) - 1, quant * 100);
10318c2ecf20Sopenharmony_ci				/* estn = 100 * log(est) */
10328c2ecf20Sopenharmony_ci				estn = stb0899_table_lookup(stb0899_est_tab, ARRAY_SIZE(stb0899_est_tab) - 1, est);
10338c2ecf20Sopenharmony_ci				/* snr(dBm/10) = -10*(log(est)-log(quant^2)) => snr(dBm/10) = (100*log(quant^2)-100*log(est))/10 */
10348c2ecf20Sopenharmony_ci				val = (quantn - estn) / 10;
10358c2ecf20Sopenharmony_ci			}
10368c2ecf20Sopenharmony_ci			*snr = val;
10378c2ecf20Sopenharmony_ci			dprintk(state->verbose, FE_DEBUG, 1, "Es/N0 quant = %d (%d) estimate = %u (%d), C/N = %d * 0.1 dBm",
10388c2ecf20Sopenharmony_ci				quant, quantn, est, estn, val);
10398c2ecf20Sopenharmony_ci		}
10408c2ecf20Sopenharmony_ci		break;
10418c2ecf20Sopenharmony_ci	default:
10428c2ecf20Sopenharmony_ci		dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system");
10438c2ecf20Sopenharmony_ci		return -EINVAL;
10448c2ecf20Sopenharmony_ci	}
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	return 0;
10478c2ecf20Sopenharmony_ci}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_cistatic int stb0899_read_status(struct dvb_frontend *fe, enum fe_status *status)
10508c2ecf20Sopenharmony_ci{
10518c2ecf20Sopenharmony_ci	struct stb0899_state *state		= fe->demodulator_priv;
10528c2ecf20Sopenharmony_ci	struct stb0899_internal *internal	= &state->internal;
10538c2ecf20Sopenharmony_ci	u8 reg;
10548c2ecf20Sopenharmony_ci	*status = 0;
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	switch (state->delsys) {
10578c2ecf20Sopenharmony_ci	case SYS_DVBS:
10588c2ecf20Sopenharmony_ci	case SYS_DSS:
10598c2ecf20Sopenharmony_ci		dprintk(state->verbose, FE_DEBUG, 1, "Delivery system DVB-S/DSS");
10608c2ecf20Sopenharmony_ci		if (internal->lock) {
10618c2ecf20Sopenharmony_ci			reg  = stb0899_read_reg(state, STB0899_VSTATUS);
10628c2ecf20Sopenharmony_ci			if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) {
10638c2ecf20Sopenharmony_ci				dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_CARRIER | FE_HAS_LOCK");
10648c2ecf20Sopenharmony_ci				*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci				reg = stb0899_read_reg(state, STB0899_PLPARM);
10678c2ecf20Sopenharmony_ci				if (STB0899_GETFIELD(VITCURPUN, reg)) {
10688c2ecf20Sopenharmony_ci					dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_VITERBI | FE_HAS_SYNC");
10698c2ecf20Sopenharmony_ci					*status |= FE_HAS_VITERBI | FE_HAS_SYNC;
10708c2ecf20Sopenharmony_ci					/* post process event */
10718c2ecf20Sopenharmony_ci					stb0899_postproc(state, STB0899_POSTPROC_GPIO_LOCK, 1);
10728c2ecf20Sopenharmony_ci				}
10738c2ecf20Sopenharmony_ci			}
10748c2ecf20Sopenharmony_ci		}
10758c2ecf20Sopenharmony_ci		break;
10768c2ecf20Sopenharmony_ci	case SYS_DVBS2:
10778c2ecf20Sopenharmony_ci		dprintk(state->verbose, FE_DEBUG, 1, "Delivery system DVB-S2");
10788c2ecf20Sopenharmony_ci		if (internal->lock) {
10798c2ecf20Sopenharmony_ci			reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2);
10808c2ecf20Sopenharmony_ci			if (STB0899_GETFIELD(UWP_LOCK, reg) && STB0899_GETFIELD(CSM_LOCK, reg)) {
10818c2ecf20Sopenharmony_ci				*status |= FE_HAS_CARRIER;
10828c2ecf20Sopenharmony_ci				dprintk(state->verbose, FE_DEBUG, 1,
10838c2ecf20Sopenharmony_ci					"UWP & CSM Lock ! ---> DVB-S2 FE_HAS_CARRIER");
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci				reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1);
10868c2ecf20Sopenharmony_ci				if (STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg)) {
10878c2ecf20Sopenharmony_ci					*status |= FE_HAS_LOCK;
10888c2ecf20Sopenharmony_ci					dprintk(state->verbose, FE_DEBUG, 1,
10898c2ecf20Sopenharmony_ci						"Packet Delineator Locked ! -----> DVB-S2 FE_HAS_LOCK");
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci				}
10928c2ecf20Sopenharmony_ci				if (STB0899_GETFIELD(CONTINUOUS_STREAM, reg)) {
10938c2ecf20Sopenharmony_ci					*status |= FE_HAS_VITERBI;
10948c2ecf20Sopenharmony_ci					dprintk(state->verbose, FE_DEBUG, 1,
10958c2ecf20Sopenharmony_ci						"Packet Delineator found VITERBI ! -----> DVB-S2 FE_HAS_VITERBI");
10968c2ecf20Sopenharmony_ci				}
10978c2ecf20Sopenharmony_ci				if (STB0899_GETFIELD(ACCEPTED_STREAM, reg)) {
10988c2ecf20Sopenharmony_ci					*status |= FE_HAS_SYNC;
10998c2ecf20Sopenharmony_ci					dprintk(state->verbose, FE_DEBUG, 1,
11008c2ecf20Sopenharmony_ci						"Packet Delineator found SYNC ! -----> DVB-S2 FE_HAS_SYNC");
11018c2ecf20Sopenharmony_ci					/* post process event */
11028c2ecf20Sopenharmony_ci					stb0899_postproc(state, STB0899_POSTPROC_GPIO_LOCK, 1);
11038c2ecf20Sopenharmony_ci				}
11048c2ecf20Sopenharmony_ci			}
11058c2ecf20Sopenharmony_ci		}
11068c2ecf20Sopenharmony_ci		break;
11078c2ecf20Sopenharmony_ci	default:
11088c2ecf20Sopenharmony_ci		dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system");
11098c2ecf20Sopenharmony_ci		return -EINVAL;
11108c2ecf20Sopenharmony_ci	}
11118c2ecf20Sopenharmony_ci	return 0;
11128c2ecf20Sopenharmony_ci}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci/*
11158c2ecf20Sopenharmony_ci * stb0899_get_error
11168c2ecf20Sopenharmony_ci * viterbi error for DVB-S/DSS
11178c2ecf20Sopenharmony_ci * packet error for DVB-S2
11188c2ecf20Sopenharmony_ci * Bit Error Rate or Packet Error Rate * 10 ^ 7
11198c2ecf20Sopenharmony_ci */
11208c2ecf20Sopenharmony_cistatic int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber)
11218c2ecf20Sopenharmony_ci{
11228c2ecf20Sopenharmony_ci	struct stb0899_state *state		= fe->demodulator_priv;
11238c2ecf20Sopenharmony_ci	struct stb0899_internal *internal	= &state->internal;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	u8  lsb, msb;
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	*ber = 0;
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	switch (state->delsys) {
11308c2ecf20Sopenharmony_ci	case SYS_DVBS:
11318c2ecf20Sopenharmony_ci	case SYS_DSS:
11328c2ecf20Sopenharmony_ci		if (internal->lock) {
11338c2ecf20Sopenharmony_ci			lsb = stb0899_read_reg(state, STB0899_ECNT1L);
11348c2ecf20Sopenharmony_ci			msb = stb0899_read_reg(state, STB0899_ECNT1M);
11358c2ecf20Sopenharmony_ci			*ber = MAKEWORD16(msb, lsb);
11368c2ecf20Sopenharmony_ci			/* Viterbi Check	*/
11378c2ecf20Sopenharmony_ci			if (STB0899_GETFIELD(VSTATUS_PRFVIT, internal->v_status)) {
11388c2ecf20Sopenharmony_ci				/* Error Rate		*/
11398c2ecf20Sopenharmony_ci				*ber *= 9766;
11408c2ecf20Sopenharmony_ci				/* ber = ber * 10 ^ 7	*/
11418c2ecf20Sopenharmony_ci				*ber /= (-1 + (1 << (2 * STB0899_GETFIELD(NOE, internal->err_ctrl))));
11428c2ecf20Sopenharmony_ci				*ber /= 8;
11438c2ecf20Sopenharmony_ci			}
11448c2ecf20Sopenharmony_ci		}
11458c2ecf20Sopenharmony_ci		break;
11468c2ecf20Sopenharmony_ci	case SYS_DVBS2:
11478c2ecf20Sopenharmony_ci		if (internal->lock) {
11488c2ecf20Sopenharmony_ci			lsb = stb0899_read_reg(state, STB0899_ECNT1L);
11498c2ecf20Sopenharmony_ci			msb = stb0899_read_reg(state, STB0899_ECNT1M);
11508c2ecf20Sopenharmony_ci			*ber = MAKEWORD16(msb, lsb);
11518c2ecf20Sopenharmony_ci			/* ber = ber * 10 ^ 7	*/
11528c2ecf20Sopenharmony_ci			*ber *= 10000000;
11538c2ecf20Sopenharmony_ci			*ber /= (-1 + (1 << (4 + 2 * STB0899_GETFIELD(NOE, internal->err_ctrl))));
11548c2ecf20Sopenharmony_ci		}
11558c2ecf20Sopenharmony_ci		break;
11568c2ecf20Sopenharmony_ci	default:
11578c2ecf20Sopenharmony_ci		dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system");
11588c2ecf20Sopenharmony_ci		return -EINVAL;
11598c2ecf20Sopenharmony_ci	}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	return 0;
11628c2ecf20Sopenharmony_ci}
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_cistatic int stb0899_set_voltage(struct dvb_frontend *fe,
11658c2ecf20Sopenharmony_ci			       enum fe_sec_voltage voltage)
11668c2ecf20Sopenharmony_ci{
11678c2ecf20Sopenharmony_ci	struct stb0899_state *state = fe->demodulator_priv;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	switch (voltage) {
11708c2ecf20Sopenharmony_ci	case SEC_VOLTAGE_13:
11718c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_GPIO00CFG, 0x82);
11728c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_GPIO01CFG, 0x02);
11738c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_GPIO02CFG, 0x00);
11748c2ecf20Sopenharmony_ci		break;
11758c2ecf20Sopenharmony_ci	case SEC_VOLTAGE_18:
11768c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_GPIO00CFG, 0x02);
11778c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_GPIO01CFG, 0x02);
11788c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_GPIO02CFG, 0x82);
11798c2ecf20Sopenharmony_ci		break;
11808c2ecf20Sopenharmony_ci	case SEC_VOLTAGE_OFF:
11818c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_GPIO00CFG, 0x82);
11828c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_GPIO01CFG, 0x82);
11838c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_GPIO02CFG, 0x82);
11848c2ecf20Sopenharmony_ci		break;
11858c2ecf20Sopenharmony_ci	default:
11868c2ecf20Sopenharmony_ci		return -EINVAL;
11878c2ecf20Sopenharmony_ci	}
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	return 0;
11908c2ecf20Sopenharmony_ci}
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_cistatic int stb0899_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone)
11938c2ecf20Sopenharmony_ci{
11948c2ecf20Sopenharmony_ci	struct stb0899_state *state = fe->demodulator_priv;
11958c2ecf20Sopenharmony_ci	struct stb0899_internal *internal = &state->internal;
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	u8 div, reg;
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	/* wait for diseqc idle	*/
12008c2ecf20Sopenharmony_ci	if (stb0899_wait_diseqc_txidle(state, 100) < 0)
12018c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	switch (tone) {
12048c2ecf20Sopenharmony_ci	case SEC_TONE_ON:
12058c2ecf20Sopenharmony_ci		div = (internal->master_clk / 100) / 5632;
12068c2ecf20Sopenharmony_ci		div = (div + 5) / 10;
12078c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_DISEQCOCFG, 0x66);
12088c2ecf20Sopenharmony_ci		reg = stb0899_read_reg(state, STB0899_ACRPRESC);
12098c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(ACRPRESC, reg, 0x03);
12108c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_ACRPRESC, reg);
12118c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_ACRDIV1, div);
12128c2ecf20Sopenharmony_ci		break;
12138c2ecf20Sopenharmony_ci	case SEC_TONE_OFF:
12148c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_DISEQCOCFG, 0x20);
12158c2ecf20Sopenharmony_ci		break;
12168c2ecf20Sopenharmony_ci	default:
12178c2ecf20Sopenharmony_ci		return -EINVAL;
12188c2ecf20Sopenharmony_ci	}
12198c2ecf20Sopenharmony_ci	return 0;
12208c2ecf20Sopenharmony_ci}
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ciint stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
12238c2ecf20Sopenharmony_ci{
12248c2ecf20Sopenharmony_ci	int i2c_stat;
12258c2ecf20Sopenharmony_ci	struct stb0899_state *state = fe->demodulator_priv;
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	i2c_stat = stb0899_read_reg(state, STB0899_I2CRPT);
12288c2ecf20Sopenharmony_ci	if (i2c_stat < 0)
12298c2ecf20Sopenharmony_ci		goto err;
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	if (enable) {
12328c2ecf20Sopenharmony_ci		dprintk(state->verbose, FE_DEBUG, 1, "Enabling I2C Repeater ...");
12338c2ecf20Sopenharmony_ci		i2c_stat |=  STB0899_I2CTON;
12348c2ecf20Sopenharmony_ci		if (stb0899_write_reg(state, STB0899_I2CRPT, i2c_stat) < 0)
12358c2ecf20Sopenharmony_ci			goto err;
12368c2ecf20Sopenharmony_ci	} else {
12378c2ecf20Sopenharmony_ci		dprintk(state->verbose, FE_DEBUG, 1, "Disabling I2C Repeater ...");
12388c2ecf20Sopenharmony_ci		i2c_stat &= ~STB0899_I2CTON;
12398c2ecf20Sopenharmony_ci		if (stb0899_write_reg(state, STB0899_I2CRPT, i2c_stat) < 0)
12408c2ecf20Sopenharmony_ci			goto err;
12418c2ecf20Sopenharmony_ci	}
12428c2ecf20Sopenharmony_ci	return 0;
12438c2ecf20Sopenharmony_cierr:
12448c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_ERROR, 1, "I2C Repeater control failed");
12458c2ecf20Sopenharmony_ci	return -EREMOTEIO;
12468c2ecf20Sopenharmony_ci}
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_cistatic inline void CONVERT32(u32 x, char *str)
12508c2ecf20Sopenharmony_ci{
12518c2ecf20Sopenharmony_ci	*str++	= (x >> 24) & 0xff;
12528c2ecf20Sopenharmony_ci	*str++	= (x >> 16) & 0xff;
12538c2ecf20Sopenharmony_ci	*str++	= (x >>  8) & 0xff;
12548c2ecf20Sopenharmony_ci	*str++	= (x >>  0) & 0xff;
12558c2ecf20Sopenharmony_ci	*str	= '\0';
12568c2ecf20Sopenharmony_ci}
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_cistatic int stb0899_get_dev_id(struct stb0899_state *state)
12598c2ecf20Sopenharmony_ci{
12608c2ecf20Sopenharmony_ci	u8 chip_id, release;
12618c2ecf20Sopenharmony_ci	u16 id;
12628c2ecf20Sopenharmony_ci	u32 demod_ver = 0, fec_ver = 0;
12638c2ecf20Sopenharmony_ci	char demod_str[5] = { 0 };
12648c2ecf20Sopenharmony_ci	char fec_str[5] = { 0 };
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	id = stb0899_read_reg(state, STB0899_DEV_ID);
12678c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUG, 1, "ID reg=[0x%02x]", id);
12688c2ecf20Sopenharmony_ci	chip_id = STB0899_GETFIELD(CHIP_ID, id);
12698c2ecf20Sopenharmony_ci	release = STB0899_GETFIELD(CHIP_REL, id);
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_ERROR, 1, "Device ID=[%d], Release=[%d]",
12728c2ecf20Sopenharmony_ci		chip_id, release);
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	CONVERT32(STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CORE_ID), (char *)&demod_str);
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	demod_ver = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_VERSION_ID);
12778c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_ERROR, 1, "Demodulator Core ID=[%s], Version=[%d]", (char *) &demod_str, demod_ver);
12788c2ecf20Sopenharmony_ci	CONVERT32(STB0899_READ_S2REG(STB0899_S2FEC, FEC_CORE_ID_REG), (char *)&fec_str);
12798c2ecf20Sopenharmony_ci	fec_ver = STB0899_READ_S2REG(STB0899_S2FEC, FEC_VER_ID_REG);
12808c2ecf20Sopenharmony_ci	if (! (chip_id > 0)) {
12818c2ecf20Sopenharmony_ci		dprintk(state->verbose, FE_ERROR, 1, "couldn't find a STB 0899");
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci		return -ENODEV;
12848c2ecf20Sopenharmony_ci	}
12858c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_ERROR, 1, "FEC Core ID=[%s], Version=[%d]", (char*) &fec_str, fec_ver);
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	return 0;
12888c2ecf20Sopenharmony_ci}
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_cistatic void stb0899_set_delivery(struct stb0899_state *state)
12918c2ecf20Sopenharmony_ci{
12928c2ecf20Sopenharmony_ci	u8 reg;
12938c2ecf20Sopenharmony_ci	u8 stop_clk[2];
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	stop_clk[0] = stb0899_read_reg(state, STB0899_STOPCLK1);
12968c2ecf20Sopenharmony_ci	stop_clk[1] = stb0899_read_reg(state, STB0899_STOPCLK2);
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	switch (state->delsys) {
12998c2ecf20Sopenharmony_ci	case SYS_DVBS:
13008c2ecf20Sopenharmony_ci		dprintk(state->verbose, FE_DEBUG, 1, "Delivery System -- DVB-S");
13018c2ecf20Sopenharmony_ci		/* FECM/Viterbi ON	*/
13028c2ecf20Sopenharmony_ci		reg = stb0899_read_reg(state, STB0899_FECM);
13038c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 0);
13048c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 1);
13058c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_FECM, reg);
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_RSULC, 0xb1);
13088c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_TSULC, 0x40);
13098c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_RSLLC, 0x42);
13108c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_TSLPL, 0x12);
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci		reg = stb0899_read_reg(state, STB0899_TSTRES);
13138c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(FRESLDPC, reg, 1);
13148c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_TSTRES, reg);
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1);
13178c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 1);
13188c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 1);
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 1);
13218c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 1);
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKINTBUF216, stop_clk[0], 1);
13248c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0);
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 1);
13278c2ecf20Sopenharmony_ci		break;
13288c2ecf20Sopenharmony_ci	case SYS_DVBS2:
13298c2ecf20Sopenharmony_ci		/* FECM/Viterbi OFF	*/
13308c2ecf20Sopenharmony_ci		reg = stb0899_read_reg(state, STB0899_FECM);
13318c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 0);
13328c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 0);
13338c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_FECM, reg);
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_RSULC, 0xb1);
13368c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_TSULC, 0x42);
13378c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_RSLLC, 0x40);
13388c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_TSLPL, 0x02);
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci		reg = stb0899_read_reg(state, STB0899_TSTRES);
13418c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(FRESLDPC, reg, 0);
13428c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_TSTRES, reg);
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1);
13458c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 0);
13468c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 0);
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 0);
13498c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 0);
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKINTBUF216, stop_clk[0], 0);
13528c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0);
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 0);
13558c2ecf20Sopenharmony_ci		break;
13568c2ecf20Sopenharmony_ci	case SYS_DSS:
13578c2ecf20Sopenharmony_ci		/* FECM/Viterbi ON	*/
13588c2ecf20Sopenharmony_ci		reg = stb0899_read_reg(state, STB0899_FECM);
13598c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 1);
13608c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 1);
13618c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_FECM, reg);
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_RSULC, 0xa1);
13648c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_TSULC, 0x61);
13658c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_RSLLC, 0x42);
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci		reg = stb0899_read_reg(state, STB0899_TSTRES);
13688c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(FRESLDPC, reg, 1);
13698c2ecf20Sopenharmony_ci		stb0899_write_reg(state, STB0899_TSTRES, reg);
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1);
13728c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 1);
13738c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 1);
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 1);
13768c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 1);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0);
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci		STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 1);
13818c2ecf20Sopenharmony_ci		break;
13828c2ecf20Sopenharmony_ci	default:
13838c2ecf20Sopenharmony_ci		dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system");
13848c2ecf20Sopenharmony_ci		break;
13858c2ecf20Sopenharmony_ci	}
13868c2ecf20Sopenharmony_ci	STB0899_SETFIELD_VAL(STOP_CKADCI108, stop_clk[0], 0);
13878c2ecf20Sopenharmony_ci	stb0899_write_regs(state, STB0899_STOPCLK1, stop_clk, 2);
13888c2ecf20Sopenharmony_ci}
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci/*
13918c2ecf20Sopenharmony_ci * stb0899_set_iterations
13928c2ecf20Sopenharmony_ci * set the LDPC iteration scale function
13938c2ecf20Sopenharmony_ci */
13948c2ecf20Sopenharmony_cistatic void stb0899_set_iterations(struct stb0899_state *state)
13958c2ecf20Sopenharmony_ci{
13968c2ecf20Sopenharmony_ci	struct stb0899_internal *internal = &state->internal;
13978c2ecf20Sopenharmony_ci	struct stb0899_config *config = state->config;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	s32 iter_scale;
14008c2ecf20Sopenharmony_ci	u32 reg;
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	iter_scale = 17 * (internal->master_clk / 1000);
14038c2ecf20Sopenharmony_ci	iter_scale += 410000;
14048c2ecf20Sopenharmony_ci	iter_scale /= (internal->srate / 1000000);
14058c2ecf20Sopenharmony_ci	iter_scale /= 1000;
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	if (iter_scale > config->ldpc_max_iter)
14088c2ecf20Sopenharmony_ci		iter_scale = config->ldpc_max_iter;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	reg = STB0899_READ_S2REG(STB0899_S2FEC, MAX_ITER);
14118c2ecf20Sopenharmony_ci	STB0899_SETFIELD_VAL(MAX_ITERATIONS, reg, iter_scale);
14128c2ecf20Sopenharmony_ci	stb0899_write_s2reg(state, STB0899_S2FEC, STB0899_BASE_MAX_ITER, STB0899_OFF0_MAX_ITER, reg);
14138c2ecf20Sopenharmony_ci}
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_cistatic enum dvbfe_search stb0899_search(struct dvb_frontend *fe)
14168c2ecf20Sopenharmony_ci{
14178c2ecf20Sopenharmony_ci	struct stb0899_state *state = fe->demodulator_priv;
14188c2ecf20Sopenharmony_ci	struct stb0899_params *i_params = &state->params;
14198c2ecf20Sopenharmony_ci	struct stb0899_internal *internal = &state->internal;
14208c2ecf20Sopenharmony_ci	struct stb0899_config *config = state->config;
14218c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *props = &fe->dtv_property_cache;
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	u32 SearchRange, gain;
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	i_params->freq	= props->frequency;
14268c2ecf20Sopenharmony_ci	i_params->srate = props->symbol_rate;
14278c2ecf20Sopenharmony_ci	state->delsys = props->delivery_system;
14288c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUG, 1, "delivery system=%d", state->delsys);
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	SearchRange = 10000000;
14318c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUG, 1, "Frequency=%d, Srate=%d", i_params->freq, i_params->srate);
14328c2ecf20Sopenharmony_ci	/* checking Search Range is meaningless for a fixed 3 Mhz			*/
14338c2ecf20Sopenharmony_ci	if (INRANGE(i_params->srate, 1000000, 45000000)) {
14348c2ecf20Sopenharmony_ci		dprintk(state->verbose, FE_DEBUG, 1, "Parameters IN RANGE");
14358c2ecf20Sopenharmony_ci		stb0899_set_delivery(state);
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci		if (state->config->tuner_set_rfsiggain) {
14388c2ecf20Sopenharmony_ci			if (internal->srate > 15000000)
14398c2ecf20Sopenharmony_ci				gain =  8; /* 15Mb < srate < 45Mb, gain = 8dB	*/
14408c2ecf20Sopenharmony_ci			else if (internal->srate > 5000000)
14418c2ecf20Sopenharmony_ci				gain = 12; /*  5Mb < srate < 15Mb, gain = 12dB	*/
14428c2ecf20Sopenharmony_ci			else
14438c2ecf20Sopenharmony_ci				gain = 14; /*  1Mb < srate <  5Mb, gain = 14db	*/
14448c2ecf20Sopenharmony_ci			state->config->tuner_set_rfsiggain(fe, gain);
14458c2ecf20Sopenharmony_ci		}
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci		if (i_params->srate <= 5000000)
14488c2ecf20Sopenharmony_ci			stb0899_set_mclk(state, config->lo_clk);
14498c2ecf20Sopenharmony_ci		else
14508c2ecf20Sopenharmony_ci			stb0899_set_mclk(state, config->hi_clk);
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci		switch (state->delsys) {
14538c2ecf20Sopenharmony_ci		case SYS_DVBS:
14548c2ecf20Sopenharmony_ci		case SYS_DSS:
14558c2ecf20Sopenharmony_ci			dprintk(state->verbose, FE_DEBUG, 1, "DVB-S delivery system");
14568c2ecf20Sopenharmony_ci			internal->freq	= i_params->freq;
14578c2ecf20Sopenharmony_ci			internal->srate	= i_params->srate;
14588c2ecf20Sopenharmony_ci			/*
14598c2ecf20Sopenharmony_ci			 * search = user search range +
14608c2ecf20Sopenharmony_ci			 *	    500Khz +
14618c2ecf20Sopenharmony_ci			 *	    2 * Tuner_step_size +
14628c2ecf20Sopenharmony_ci			 *	    10% of the symbol rate
14638c2ecf20Sopenharmony_ci			 */
14648c2ecf20Sopenharmony_ci			internal->srch_range	= SearchRange + 1500000 + (i_params->srate / 5);
14658c2ecf20Sopenharmony_ci			internal->derot_percent	= 30;
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci			/* What to do for tuners having no bandwidth setup ?	*/
14688c2ecf20Sopenharmony_ci			/* enable tuner I/O */
14698c2ecf20Sopenharmony_ci			stb0899_i2c_gate_ctrl(&state->frontend, 1);
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci			if (state->config->tuner_set_bandwidth)
14728c2ecf20Sopenharmony_ci				state->config->tuner_set_bandwidth(fe, (13 * (stb0899_carr_width(state) + SearchRange)) / 10);
14738c2ecf20Sopenharmony_ci			if (state->config->tuner_get_bandwidth)
14748c2ecf20Sopenharmony_ci				state->config->tuner_get_bandwidth(fe, &internal->tuner_bw);
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci			/* disable tuner I/O */
14778c2ecf20Sopenharmony_ci			stb0899_i2c_gate_ctrl(&state->frontend, 0);
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci			/* Set DVB-S1 AGC		*/
14808c2ecf20Sopenharmony_ci			stb0899_write_reg(state, STB0899_AGCRFCFG, 0x11);
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci			/* Run the search algorithm	*/
14838c2ecf20Sopenharmony_ci			dprintk(state->verbose, FE_DEBUG, 1, "running DVB-S search algo ..");
14848c2ecf20Sopenharmony_ci			if (stb0899_dvbs_algo(state)	== RANGEOK) {
14858c2ecf20Sopenharmony_ci				internal->lock		= 1;
14868c2ecf20Sopenharmony_ci				dprintk(state->verbose, FE_DEBUG, 1,
14878c2ecf20Sopenharmony_ci					"-------------------------------------> DVB-S LOCK !");
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci//				stb0899_write_reg(state, STB0899_ERRCTRL1, 0x3d); /* Viterbi Errors	*/
14908c2ecf20Sopenharmony_ci//				internal->v_status = stb0899_read_reg(state, STB0899_VSTATUS);
14918c2ecf20Sopenharmony_ci//				internal->err_ctrl = stb0899_read_reg(state, STB0899_ERRCTRL1);
14928c2ecf20Sopenharmony_ci//				dprintk(state->verbose, FE_DEBUG, 1, "VSTATUS=0x%02x", internal->v_status);
14938c2ecf20Sopenharmony_ci//				dprintk(state->verbose, FE_DEBUG, 1, "ERR_CTRL=0x%02x", internal->err_ctrl);
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci				return DVBFE_ALGO_SEARCH_SUCCESS;
14968c2ecf20Sopenharmony_ci			} else {
14978c2ecf20Sopenharmony_ci				internal->lock		= 0;
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci				return DVBFE_ALGO_SEARCH_FAILED;
15008c2ecf20Sopenharmony_ci			}
15018c2ecf20Sopenharmony_ci			break;
15028c2ecf20Sopenharmony_ci		case SYS_DVBS2:
15038c2ecf20Sopenharmony_ci			internal->freq			= i_params->freq;
15048c2ecf20Sopenharmony_ci			internal->srate			= i_params->srate;
15058c2ecf20Sopenharmony_ci			internal->srch_range		= SearchRange;
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci			/* enable tuner I/O */
15088c2ecf20Sopenharmony_ci			stb0899_i2c_gate_ctrl(&state->frontend, 1);
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci			if (state->config->tuner_set_bandwidth)
15118c2ecf20Sopenharmony_ci				state->config->tuner_set_bandwidth(fe, (stb0899_carr_width(state) + SearchRange));
15128c2ecf20Sopenharmony_ci			if (state->config->tuner_get_bandwidth)
15138c2ecf20Sopenharmony_ci				state->config->tuner_get_bandwidth(fe, &internal->tuner_bw);
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci			/* disable tuner I/O */
15168c2ecf20Sopenharmony_ci			stb0899_i2c_gate_ctrl(&state->frontend, 0);
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci//			pParams->SpectralInv		= pSearch->IQ_Inversion;
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci			/* Set DVB-S2 AGC		*/
15218c2ecf20Sopenharmony_ci			stb0899_write_reg(state, STB0899_AGCRFCFG, 0x1c);
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci			/* Set IterScale =f(MCLK,SYMB)	*/
15248c2ecf20Sopenharmony_ci			stb0899_set_iterations(state);
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci			/* Run the search algorithm	*/
15278c2ecf20Sopenharmony_ci			dprintk(state->verbose, FE_DEBUG, 1, "running DVB-S2 search algo ..");
15288c2ecf20Sopenharmony_ci			if (stb0899_dvbs2_algo(state)	== DVBS2_FEC_LOCK) {
15298c2ecf20Sopenharmony_ci				internal->lock		= 1;
15308c2ecf20Sopenharmony_ci				dprintk(state->verbose, FE_DEBUG, 1,
15318c2ecf20Sopenharmony_ci					"-------------------------------------> DVB-S2 LOCK !");
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci//				stb0899_write_reg(state, STB0899_ERRCTRL1, 0xb6); /* Packet Errors	*/
15348c2ecf20Sopenharmony_ci//				internal->v_status = stb0899_read_reg(state, STB0899_VSTATUS);
15358c2ecf20Sopenharmony_ci//				internal->err_ctrl = stb0899_read_reg(state, STB0899_ERRCTRL1);
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci				return DVBFE_ALGO_SEARCH_SUCCESS;
15388c2ecf20Sopenharmony_ci			} else {
15398c2ecf20Sopenharmony_ci				internal->lock		= 0;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci				return DVBFE_ALGO_SEARCH_FAILED;
15428c2ecf20Sopenharmony_ci			}
15438c2ecf20Sopenharmony_ci			break;
15448c2ecf20Sopenharmony_ci		default:
15458c2ecf20Sopenharmony_ci			dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system");
15468c2ecf20Sopenharmony_ci			return DVBFE_ALGO_SEARCH_INVALID;
15478c2ecf20Sopenharmony_ci		}
15488c2ecf20Sopenharmony_ci	}
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	return DVBFE_ALGO_SEARCH_ERROR;
15518c2ecf20Sopenharmony_ci}
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_cistatic int stb0899_get_frontend(struct dvb_frontend *fe,
15548c2ecf20Sopenharmony_ci				struct dtv_frontend_properties *p)
15558c2ecf20Sopenharmony_ci{
15568c2ecf20Sopenharmony_ci	struct stb0899_state *state		= fe->demodulator_priv;
15578c2ecf20Sopenharmony_ci	struct stb0899_internal *internal	= &state->internal;
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci	dprintk(state->verbose, FE_DEBUG, 1, "Get params");
15608c2ecf20Sopenharmony_ci	p->symbol_rate = internal->srate;
15618c2ecf20Sopenharmony_ci	p->frequency = internal->freq;
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	return 0;
15648c2ecf20Sopenharmony_ci}
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_cistatic enum dvbfe_algo stb0899_frontend_algo(struct dvb_frontend *fe)
15678c2ecf20Sopenharmony_ci{
15688c2ecf20Sopenharmony_ci	return DVBFE_ALGO_CUSTOM;
15698c2ecf20Sopenharmony_ci}
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops stb0899_ops = {
15728c2ecf20Sopenharmony_ci	.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
15738c2ecf20Sopenharmony_ci	.info = {
15748c2ecf20Sopenharmony_ci		.name			= "STB0899 Multistandard",
15758c2ecf20Sopenharmony_ci		.frequency_min_hz	=  950 * MHz,
15768c2ecf20Sopenharmony_ci		.frequency_max_hz	= 2150 * MHz,
15778c2ecf20Sopenharmony_ci		.symbol_rate_min	=  5000000,
15788c2ecf20Sopenharmony_ci		.symbol_rate_max	= 45000000,
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci		.caps			= FE_CAN_INVERSION_AUTO	|
15818c2ecf20Sopenharmony_ci					  FE_CAN_FEC_AUTO	|
15828c2ecf20Sopenharmony_ci					  FE_CAN_2G_MODULATION	|
15838c2ecf20Sopenharmony_ci					  FE_CAN_QPSK
15848c2ecf20Sopenharmony_ci	},
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	.detach				= stb0899_detach,
15878c2ecf20Sopenharmony_ci	.release			= stb0899_release,
15888c2ecf20Sopenharmony_ci	.init				= stb0899_init,
15898c2ecf20Sopenharmony_ci	.sleep				= stb0899_sleep,
15908c2ecf20Sopenharmony_ci//	.wakeup				= stb0899_wakeup,
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci	.i2c_gate_ctrl			= stb0899_i2c_gate_ctrl,
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci	.get_frontend_algo		= stb0899_frontend_algo,
15958c2ecf20Sopenharmony_ci	.search				= stb0899_search,
15968c2ecf20Sopenharmony_ci	.get_frontend                   = stb0899_get_frontend,
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	.read_status			= stb0899_read_status,
16008c2ecf20Sopenharmony_ci	.read_snr			= stb0899_read_snr,
16018c2ecf20Sopenharmony_ci	.read_signal_strength		= stb0899_read_signal_strength,
16028c2ecf20Sopenharmony_ci	.read_ber			= stb0899_read_ber,
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	.set_voltage			= stb0899_set_voltage,
16058c2ecf20Sopenharmony_ci	.set_tone			= stb0899_set_tone,
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	.diseqc_send_master_cmd		= stb0899_send_diseqc_msg,
16088c2ecf20Sopenharmony_ci	.diseqc_recv_slave_reply	= stb0899_recv_slave_reply,
16098c2ecf20Sopenharmony_ci	.diseqc_send_burst		= stb0899_send_diseqc_burst,
16108c2ecf20Sopenharmony_ci};
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_cistruct dvb_frontend *stb0899_attach(struct stb0899_config *config, struct i2c_adapter *i2c)
16138c2ecf20Sopenharmony_ci{
16148c2ecf20Sopenharmony_ci	struct stb0899_state *state = NULL;
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci	state = kzalloc(sizeof (struct stb0899_state), GFP_KERNEL);
16178c2ecf20Sopenharmony_ci	if (state == NULL)
16188c2ecf20Sopenharmony_ci		goto error;
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	state->verbose				= &verbose;
16218c2ecf20Sopenharmony_ci	state->config				= config;
16228c2ecf20Sopenharmony_ci	state->i2c				= i2c;
16238c2ecf20Sopenharmony_ci	state->frontend.ops			= stb0899_ops;
16248c2ecf20Sopenharmony_ci	state->frontend.demodulator_priv	= state;
16258c2ecf20Sopenharmony_ci	/* use configured inversion as default -- we'll later autodetect inversion */
16268c2ecf20Sopenharmony_ci	state->internal.inversion		= config->inversion;
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	stb0899_wakeup(&state->frontend);
16298c2ecf20Sopenharmony_ci	if (stb0899_get_dev_id(state) == -ENODEV) {
16308c2ecf20Sopenharmony_ci		printk("%s: Exiting .. !\n", __func__);
16318c2ecf20Sopenharmony_ci		goto error;
16328c2ecf20Sopenharmony_ci	}
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	printk("%s: Attaching STB0899 \n", __func__);
16358c2ecf20Sopenharmony_ci	return &state->frontend;
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_cierror:
16388c2ecf20Sopenharmony_ci	kfree(state);
16398c2ecf20Sopenharmony_ci	return NULL;
16408c2ecf20Sopenharmony_ci}
16418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(stb0899_attach);
16428c2ecf20Sopenharmony_ciMODULE_PARM_DESC(verbose, "Set Verbosity level");
16438c2ecf20Sopenharmony_ciMODULE_AUTHOR("Manu Abraham");
16448c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("STB0899 Multi-Std frontend");
16458c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1646