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