xref: /openbmc/linux/drivers/media/tuners/mt2063.c (revision 8be98d2f2a0a262f8bf8a0bc1fdf522b3c7aab17)
14ba774edSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ccae7af2SMauro Carvalho Chehab /*
3ccae7af2SMauro Carvalho Chehab  * Driver for mt2063 Micronas tuner
4ccae7af2SMauro Carvalho Chehab  *
537e59f87SMauro Carvalho Chehab  * Copyright (c) 2011 Mauro Carvalho Chehab
6ccae7af2SMauro Carvalho Chehab  *
7ccae7af2SMauro Carvalho Chehab  * This driver came from a driver originally written by:
8ccae7af2SMauro Carvalho Chehab  *		Henry Wang <Henry.wang@AzureWave.com>
9ccae7af2SMauro Carvalho Chehab  * Made publicly available by Terratec, at:
10ccae7af2SMauro Carvalho Chehab  *	http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
11ccae7af2SMauro Carvalho Chehab  */
12ccae7af2SMauro Carvalho Chehab 
13ccae7af2SMauro Carvalho Chehab #include <linux/init.h>
14ccae7af2SMauro Carvalho Chehab #include <linux/kernel.h>
15ccae7af2SMauro Carvalho Chehab #include <linux/module.h>
16ccae7af2SMauro Carvalho Chehab #include <linux/string.h>
17ccae7af2SMauro Carvalho Chehab #include <linux/videodev2.h>
18917d11a4SZhaoxiu Zeng #include <linux/gcd.h>
19ccae7af2SMauro Carvalho Chehab 
20ccae7af2SMauro Carvalho Chehab #include "mt2063.h"
21ccae7af2SMauro Carvalho Chehab 
22ccae7af2SMauro Carvalho Chehab static unsigned int debug;
23ccae7af2SMauro Carvalho Chehab module_param(debug, int, 0644);
24ccae7af2SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Set Verbosity level");
25ccae7af2SMauro Carvalho Chehab 
26ccae7af2SMauro Carvalho Chehab #define dprintk(level, fmt, arg...) do {				\
27ccae7af2SMauro Carvalho Chehab if (debug >= level)							\
28ccae7af2SMauro Carvalho Chehab 	printk(KERN_DEBUG "mt2063 %s: " fmt, __func__, ## arg);	\
29ccae7af2SMauro Carvalho Chehab } while (0)
30ccae7af2SMauro Carvalho Chehab 
31ccae7af2SMauro Carvalho Chehab 
32ccae7af2SMauro Carvalho Chehab /* positive error codes used internally */
33ccae7af2SMauro Carvalho Chehab 
34ccae7af2SMauro Carvalho Chehab /*  Info: Unavoidable LO-related spur may be present in the output  */
35ccae7af2SMauro Carvalho Chehab #define MT2063_SPUR_PRESENT_ERR             (0x00800000)
36ccae7af2SMauro Carvalho Chehab 
37ccae7af2SMauro Carvalho Chehab /*  Info: Mask of bits used for # of LO-related spurs that were avoided during tuning  */
38ccae7af2SMauro Carvalho Chehab #define MT2063_SPUR_CNT_MASK                (0x001f0000)
39ccae7af2SMauro Carvalho Chehab #define MT2063_SPUR_SHIFT                   (16)
40ccae7af2SMauro Carvalho Chehab 
41ccae7af2SMauro Carvalho Chehab /*  Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */
42ccae7af2SMauro Carvalho Chehab #define MT2063_UPC_RANGE                    (0x04000000)
43ccae7af2SMauro Carvalho Chehab 
44ccae7af2SMauro Carvalho Chehab /*  Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */
45ccae7af2SMauro Carvalho Chehab #define MT2063_DNC_RANGE                    (0x08000000)
46ccae7af2SMauro Carvalho Chehab 
47ccae7af2SMauro Carvalho Chehab /*
48ccae7af2SMauro Carvalho Chehab  *  Constant defining the version of the following structure
49ccae7af2SMauro Carvalho Chehab  *  and therefore the API for this code.
50ccae7af2SMauro Carvalho Chehab  *
51ccae7af2SMauro Carvalho Chehab  *  When compiling the tuner driver, the preprocessor will
52ccae7af2SMauro Carvalho Chehab  *  check against this version number to make sure that
53ccae7af2SMauro Carvalho Chehab  *  it matches the version that the tuner driver knows about.
54ccae7af2SMauro Carvalho Chehab  */
55ccae7af2SMauro Carvalho Chehab 
56ccae7af2SMauro Carvalho Chehab /* DECT Frequency Avoidance */
57ccae7af2SMauro Carvalho Chehab #define MT2063_DECT_AVOID_US_FREQS      0x00000001
58ccae7af2SMauro Carvalho Chehab 
59ccae7af2SMauro Carvalho Chehab #define MT2063_DECT_AVOID_EURO_FREQS    0x00000002
60ccae7af2SMauro Carvalho Chehab 
61ccae7af2SMauro Carvalho Chehab #define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0)
62ccae7af2SMauro Carvalho Chehab 
63ccae7af2SMauro Carvalho Chehab #define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0)
64ccae7af2SMauro Carvalho Chehab 
65ccae7af2SMauro Carvalho Chehab enum MT2063_DECT_Avoid_Type {
66ccae7af2SMauro Carvalho Chehab 	MT2063_NO_DECT_AVOIDANCE = 0,				/* Do not create DECT exclusion zones.     */
67ccae7af2SMauro Carvalho Chehab 	MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS,	/* Avoid US DECT frequencies.              */
68ccae7af2SMauro Carvalho Chehab 	MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS,	/* Avoid European DECT frequencies.        */
69ccae7af2SMauro Carvalho Chehab 	MT2063_AVOID_BOTH					/* Avoid both regions. Not typically used. */
70ccae7af2SMauro Carvalho Chehab };
71ccae7af2SMauro Carvalho Chehab 
72ccae7af2SMauro Carvalho Chehab #define MT2063_MAX_ZONES 48
73ccae7af2SMauro Carvalho Chehab 
74ccae7af2SMauro Carvalho Chehab struct MT2063_ExclZone_t {
75ccae7af2SMauro Carvalho Chehab 	u32 min_;
76ccae7af2SMauro Carvalho Chehab 	u32 max_;
77ccae7af2SMauro Carvalho Chehab 	struct MT2063_ExclZone_t *next_;
78ccae7af2SMauro Carvalho Chehab };
79ccae7af2SMauro Carvalho Chehab 
80ccae7af2SMauro Carvalho Chehab /*
81ccae7af2SMauro Carvalho Chehab  *  Structure of data needed for Spur Avoidance
82ccae7af2SMauro Carvalho Chehab  */
83ccae7af2SMauro Carvalho Chehab struct MT2063_AvoidSpursData_t {
84ccae7af2SMauro Carvalho Chehab 	u32 f_ref;
85ccae7af2SMauro Carvalho Chehab 	u32 f_in;
86ccae7af2SMauro Carvalho Chehab 	u32 f_LO1;
87ccae7af2SMauro Carvalho Chehab 	u32 f_if1_Center;
88ccae7af2SMauro Carvalho Chehab 	u32 f_if1_Request;
89ccae7af2SMauro Carvalho Chehab 	u32 f_if1_bw;
90ccae7af2SMauro Carvalho Chehab 	u32 f_LO2;
91ccae7af2SMauro Carvalho Chehab 	u32 f_out;
92ccae7af2SMauro Carvalho Chehab 	u32 f_out_bw;
93ccae7af2SMauro Carvalho Chehab 	u32 f_LO1_Step;
94ccae7af2SMauro Carvalho Chehab 	u32 f_LO2_Step;
95ccae7af2SMauro Carvalho Chehab 	u32 f_LO1_FracN_Avoid;
96ccae7af2SMauro Carvalho Chehab 	u32 f_LO2_FracN_Avoid;
97ccae7af2SMauro Carvalho Chehab 	u32 f_zif_bw;
98ccae7af2SMauro Carvalho Chehab 	u32 f_min_LO_Separation;
99ccae7af2SMauro Carvalho Chehab 	u32 maxH1;
100ccae7af2SMauro Carvalho Chehab 	u32 maxH2;
101ccae7af2SMauro Carvalho Chehab 	enum MT2063_DECT_Avoid_Type avoidDECT;
102ccae7af2SMauro Carvalho Chehab 	u32 bSpurPresent;
103ccae7af2SMauro Carvalho Chehab 	u32 bSpurAvoided;
104ccae7af2SMauro Carvalho Chehab 	u32 nSpursFound;
105ccae7af2SMauro Carvalho Chehab 	u32 nZones;
106ccae7af2SMauro Carvalho Chehab 	struct MT2063_ExclZone_t *freeZones;
107ccae7af2SMauro Carvalho Chehab 	struct MT2063_ExclZone_t *usedZones;
108ccae7af2SMauro Carvalho Chehab 	struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES];
109ccae7af2SMauro Carvalho Chehab };
110ccae7af2SMauro Carvalho Chehab 
111ccae7af2SMauro Carvalho Chehab /*
112ccae7af2SMauro Carvalho Chehab  * Parameter for function MT2063_SetPowerMask that specifies the power down
113ccae7af2SMauro Carvalho Chehab  * of various sections of the MT2063.
114ccae7af2SMauro Carvalho Chehab  */
115ccae7af2SMauro Carvalho Chehab enum MT2063_Mask_Bits {
116ccae7af2SMauro Carvalho Chehab 	MT2063_REG_SD = 0x0040,		/* Shutdown regulator                 */
117ccae7af2SMauro Carvalho Chehab 	MT2063_SRO_SD = 0x0020,		/* Shutdown SRO                       */
118ccae7af2SMauro Carvalho Chehab 	MT2063_AFC_SD = 0x0010,		/* Shutdown AFC A/D                   */
119ccae7af2SMauro Carvalho Chehab 	MT2063_PD_SD = 0x0002,		/* Enable power detector shutdown     */
120ccae7af2SMauro Carvalho Chehab 	MT2063_PDADC_SD = 0x0001,	/* Enable power detector A/D shutdown */
121ccae7af2SMauro Carvalho Chehab 	MT2063_VCO_SD = 0x8000,		/* Enable VCO shutdown                */
122ccae7af2SMauro Carvalho Chehab 	MT2063_LTX_SD = 0x4000,		/* Enable LTX shutdown                */
123ccae7af2SMauro Carvalho Chehab 	MT2063_LT1_SD = 0x2000,		/* Enable LT1 shutdown                */
124ccae7af2SMauro Carvalho Chehab 	MT2063_LNA_SD = 0x1000,		/* Enable LNA shutdown                */
125ccae7af2SMauro Carvalho Chehab 	MT2063_UPC_SD = 0x0800,		/* Enable upconverter shutdown        */
126ccae7af2SMauro Carvalho Chehab 	MT2063_DNC_SD = 0x0400,		/* Enable downconverter shutdown      */
127ccae7af2SMauro Carvalho Chehab 	MT2063_VGA_SD = 0x0200,		/* Enable VGA shutdown                */
128ccae7af2SMauro Carvalho Chehab 	MT2063_AMP_SD = 0x0100,		/* Enable AMP shutdown                */
129ccae7af2SMauro Carvalho Chehab 	MT2063_ALL_SD = 0xFF73,		/* All shutdown bits for this tuner   */
130ccae7af2SMauro Carvalho Chehab 	MT2063_NONE_SD = 0x0000		/* No shutdown bits                   */
131ccae7af2SMauro Carvalho Chehab };
132ccae7af2SMauro Carvalho Chehab 
133ccae7af2SMauro Carvalho Chehab /*
134ccae7af2SMauro Carvalho Chehab  *  Possible values for MT2063_DNC_OUTPUT
135ccae7af2SMauro Carvalho Chehab  */
136ccae7af2SMauro Carvalho Chehab enum MT2063_DNC_Output_Enable {
137ccae7af2SMauro Carvalho Chehab 	MT2063_DNC_NONE = 0,
138ccae7af2SMauro Carvalho Chehab 	MT2063_DNC_1,
139ccae7af2SMauro Carvalho Chehab 	MT2063_DNC_2,
140ccae7af2SMauro Carvalho Chehab 	MT2063_DNC_BOTH
141ccae7af2SMauro Carvalho Chehab };
142ccae7af2SMauro Carvalho Chehab 
143ccae7af2SMauro Carvalho Chehab /*
144ccae7af2SMauro Carvalho Chehab  *  Two-wire serial bus subaddresses of the tuner registers.
145ccae7af2SMauro Carvalho Chehab  *  Also known as the tuner's register addresses.
146ccae7af2SMauro Carvalho Chehab  */
147ccae7af2SMauro Carvalho Chehab enum MT2063_Register_Offsets {
148ccae7af2SMauro Carvalho Chehab 	MT2063_REG_PART_REV = 0,	/*  0x00: Part/Rev Code         */
149ccae7af2SMauro Carvalho Chehab 	MT2063_REG_LO1CQ_1,		/*  0x01: LO1C Queued Byte 1    */
150ccae7af2SMauro Carvalho Chehab 	MT2063_REG_LO1CQ_2,		/*  0x02: LO1C Queued Byte 2    */
151ccae7af2SMauro Carvalho Chehab 	MT2063_REG_LO2CQ_1,		/*  0x03: LO2C Queued Byte 1    */
152ccae7af2SMauro Carvalho Chehab 	MT2063_REG_LO2CQ_2,		/*  0x04: LO2C Queued Byte 2    */
153ccae7af2SMauro Carvalho Chehab 	MT2063_REG_LO2CQ_3,		/*  0x05: LO2C Queued Byte 3    */
154ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_06,		/*  0x06: Reserved              */
155ccae7af2SMauro Carvalho Chehab 	MT2063_REG_LO_STATUS,		/*  0x07: LO Status             */
156ccae7af2SMauro Carvalho Chehab 	MT2063_REG_FIFFC,		/*  0x08: FIFF Center           */
157ccae7af2SMauro Carvalho Chehab 	MT2063_REG_CLEARTUNE,		/*  0x09: ClearTune Filter      */
158ccae7af2SMauro Carvalho Chehab 	MT2063_REG_ADC_OUT,		/*  0x0A: ADC_OUT               */
159ccae7af2SMauro Carvalho Chehab 	MT2063_REG_LO1C_1,		/*  0x0B: LO1C Byte 1           */
160ccae7af2SMauro Carvalho Chehab 	MT2063_REG_LO1C_2,		/*  0x0C: LO1C Byte 2           */
161ccae7af2SMauro Carvalho Chehab 	MT2063_REG_LO2C_1,		/*  0x0D: LO2C Byte 1           */
162ccae7af2SMauro Carvalho Chehab 	MT2063_REG_LO2C_2,		/*  0x0E: LO2C Byte 2           */
163ccae7af2SMauro Carvalho Chehab 	MT2063_REG_LO2C_3,		/*  0x0F: LO2C Byte 3           */
164ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_10,		/*  0x10: Reserved              */
165ccae7af2SMauro Carvalho Chehab 	MT2063_REG_PWR_1,		/*  0x11: PWR Byte 1            */
166ccae7af2SMauro Carvalho Chehab 	MT2063_REG_PWR_2,		/*  0x12: PWR Byte 2            */
167ccae7af2SMauro Carvalho Chehab 	MT2063_REG_TEMP_STATUS,		/*  0x13: Temp Status           */
168ccae7af2SMauro Carvalho Chehab 	MT2063_REG_XO_STATUS,		/*  0x14: Crystal Status        */
169ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RF_STATUS,		/*  0x15: RF Attn Status        */
170ccae7af2SMauro Carvalho Chehab 	MT2063_REG_FIF_STATUS,		/*  0x16: FIF Attn Status       */
171ccae7af2SMauro Carvalho Chehab 	MT2063_REG_LNA_OV,		/*  0x17: LNA Attn Override     */
172ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RF_OV,		/*  0x18: RF Attn Override      */
173ccae7af2SMauro Carvalho Chehab 	MT2063_REG_FIF_OV,		/*  0x19: FIF Attn Override     */
174ccae7af2SMauro Carvalho Chehab 	MT2063_REG_LNA_TGT,		/*  0x1A: Reserved              */
175ccae7af2SMauro Carvalho Chehab 	MT2063_REG_PD1_TGT,		/*  0x1B: Pwr Det 1 Target      */
176ccae7af2SMauro Carvalho Chehab 	MT2063_REG_PD2_TGT,		/*  0x1C: Pwr Det 2 Target      */
177ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_1D,		/*  0x1D: Reserved              */
178ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_1E,		/*  0x1E: Reserved              */
179ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_1F,		/*  0x1F: Reserved              */
180ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_20,		/*  0x20: Reserved              */
181ccae7af2SMauro Carvalho Chehab 	MT2063_REG_BYP_CTRL,		/*  0x21: Bypass Control        */
182ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_22,		/*  0x22: Reserved              */
183ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_23,		/*  0x23: Reserved              */
184ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_24,		/*  0x24: Reserved              */
185ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_25,		/*  0x25: Reserved              */
186ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_26,		/*  0x26: Reserved              */
187ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_27,		/*  0x27: Reserved              */
188ccae7af2SMauro Carvalho Chehab 	MT2063_REG_FIFF_CTRL,		/*  0x28: FIFF Control          */
189ccae7af2SMauro Carvalho Chehab 	MT2063_REG_FIFF_OFFSET,		/*  0x29: FIFF Offset           */
190ccae7af2SMauro Carvalho Chehab 	MT2063_REG_CTUNE_CTRL,		/*  0x2A: Reserved              */
191ccae7af2SMauro Carvalho Chehab 	MT2063_REG_CTUNE_OV,		/*  0x2B: Reserved              */
192ccae7af2SMauro Carvalho Chehab 	MT2063_REG_CTRL_2C,		/*  0x2C: Reserved              */
193ccae7af2SMauro Carvalho Chehab 	MT2063_REG_FIFF_CTRL2,		/*  0x2D: Fiff Control          */
194ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_2E,		/*  0x2E: Reserved              */
195ccae7af2SMauro Carvalho Chehab 	MT2063_REG_DNC_GAIN,		/*  0x2F: DNC Control           */
196ccae7af2SMauro Carvalho Chehab 	MT2063_REG_VGA_GAIN,		/*  0x30: VGA Gain Ctrl         */
197ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_31,		/*  0x31: Reserved              */
198ccae7af2SMauro Carvalho Chehab 	MT2063_REG_TEMP_SEL,		/*  0x32: Temperature Selection */
199ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_33,		/*  0x33: Reserved              */
200ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_34,		/*  0x34: Reserved              */
201ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_35,		/*  0x35: Reserved              */
202ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_36,		/*  0x36: Reserved              */
203ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_37,		/*  0x37: Reserved              */
204ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_38,		/*  0x38: Reserved              */
205ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_39,		/*  0x39: Reserved              */
206ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_3A,		/*  0x3A: Reserved              */
207ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_3B,		/*  0x3B: Reserved              */
208ccae7af2SMauro Carvalho Chehab 	MT2063_REG_RSVD_3C,		/*  0x3C: Reserved              */
209ccae7af2SMauro Carvalho Chehab 	MT2063_REG_END_REGS
210ccae7af2SMauro Carvalho Chehab };
211ccae7af2SMauro Carvalho Chehab 
212ccae7af2SMauro Carvalho Chehab struct mt2063_state {
213ccae7af2SMauro Carvalho Chehab 	struct i2c_adapter *i2c;
214ccae7af2SMauro Carvalho Chehab 
215ccae7af2SMauro Carvalho Chehab 	bool init;
216ccae7af2SMauro Carvalho Chehab 
217ccae7af2SMauro Carvalho Chehab 	const struct mt2063_config *config;
218ccae7af2SMauro Carvalho Chehab 	struct dvb_tuner_ops ops;
219ccae7af2SMauro Carvalho Chehab 	struct dvb_frontend *frontend;
220ccae7af2SMauro Carvalho Chehab 
221ccae7af2SMauro Carvalho Chehab 	u32 frequency;
222ccae7af2SMauro Carvalho Chehab 	u32 srate;
223ccae7af2SMauro Carvalho Chehab 	u32 bandwidth;
224ccae7af2SMauro Carvalho Chehab 	u32 reference;
225ccae7af2SMauro Carvalho Chehab 
226ccae7af2SMauro Carvalho Chehab 	u32 tuner_id;
227ccae7af2SMauro Carvalho Chehab 	struct MT2063_AvoidSpursData_t AS_Data;
228ccae7af2SMauro Carvalho Chehab 	u32 f_IF1_actual;
229ccae7af2SMauro Carvalho Chehab 	u32 rcvr_mode;
230ccae7af2SMauro Carvalho Chehab 	u32 ctfilt_sw;
231ccae7af2SMauro Carvalho Chehab 	u32 CTFiltMax[31];
232ccae7af2SMauro Carvalho Chehab 	u32 num_regs;
233ccae7af2SMauro Carvalho Chehab 	u8 reg[MT2063_REG_END_REGS];
234ccae7af2SMauro Carvalho Chehab };
235ccae7af2SMauro Carvalho Chehab 
236ccae7af2SMauro Carvalho Chehab /*
237ccae7af2SMauro Carvalho Chehab  * mt2063_write - Write data into the I2C bus
238ccae7af2SMauro Carvalho Chehab  */
mt2063_write(struct mt2063_state * state,u8 reg,u8 * data,u32 len)23920eb13a7SMauro Carvalho Chehab static int mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len)
240ccae7af2SMauro Carvalho Chehab {
241ccae7af2SMauro Carvalho Chehab 	struct dvb_frontend *fe = state->frontend;
242ccae7af2SMauro Carvalho Chehab 	int ret;
243ccae7af2SMauro Carvalho Chehab 	u8 buf[60];
244ccae7af2SMauro Carvalho Chehab 	struct i2c_msg msg = {
245ccae7af2SMauro Carvalho Chehab 		.addr = state->config->tuner_address,
246ccae7af2SMauro Carvalho Chehab 		.flags = 0,
247ccae7af2SMauro Carvalho Chehab 		.buf = buf,
248ccae7af2SMauro Carvalho Chehab 		.len = len + 1
249ccae7af2SMauro Carvalho Chehab 	};
250ccae7af2SMauro Carvalho Chehab 
251ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
252ccae7af2SMauro Carvalho Chehab 
253ccae7af2SMauro Carvalho Chehab 	msg.buf[0] = reg;
254ccae7af2SMauro Carvalho Chehab 	memcpy(msg.buf + 1, data, len);
255ccae7af2SMauro Carvalho Chehab 
256ccae7af2SMauro Carvalho Chehab 	if (fe->ops.i2c_gate_ctrl)
257ccae7af2SMauro Carvalho Chehab 		fe->ops.i2c_gate_ctrl(fe, 1);
258ccae7af2SMauro Carvalho Chehab 	ret = i2c_transfer(state->i2c, &msg, 1);
259ccae7af2SMauro Carvalho Chehab 	if (fe->ops.i2c_gate_ctrl)
260ccae7af2SMauro Carvalho Chehab 		fe->ops.i2c_gate_ctrl(fe, 0);
261ccae7af2SMauro Carvalho Chehab 
262ccae7af2SMauro Carvalho Chehab 	if (ret < 0)
263ccae7af2SMauro Carvalho Chehab 		printk(KERN_ERR "%s error ret=%d\n", __func__, ret);
264ccae7af2SMauro Carvalho Chehab 
265ccae7af2SMauro Carvalho Chehab 	return ret;
266ccae7af2SMauro Carvalho Chehab }
267ccae7af2SMauro Carvalho Chehab 
268ccae7af2SMauro Carvalho Chehab /*
269ccae7af2SMauro Carvalho Chehab  * mt2063_write - Write register data into the I2C bus, caching the value
270ccae7af2SMauro Carvalho Chehab  */
mt2063_setreg(struct mt2063_state * state,u8 reg,u8 val)27120eb13a7SMauro Carvalho Chehab static int mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val)
272ccae7af2SMauro Carvalho Chehab {
27320eb13a7SMauro Carvalho Chehab 	int status;
274ccae7af2SMauro Carvalho Chehab 
275ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
276ccae7af2SMauro Carvalho Chehab 
277ccae7af2SMauro Carvalho Chehab 	if (reg >= MT2063_REG_END_REGS)
278ccae7af2SMauro Carvalho Chehab 		return -ERANGE;
279ccae7af2SMauro Carvalho Chehab 
280ccae7af2SMauro Carvalho Chehab 	status = mt2063_write(state, reg, &val, 1);
281ccae7af2SMauro Carvalho Chehab 	if (status < 0)
282ccae7af2SMauro Carvalho Chehab 		return status;
283ccae7af2SMauro Carvalho Chehab 
284ccae7af2SMauro Carvalho Chehab 	state->reg[reg] = val;
285ccae7af2SMauro Carvalho Chehab 
286ccae7af2SMauro Carvalho Chehab 	return 0;
287ccae7af2SMauro Carvalho Chehab }
288ccae7af2SMauro Carvalho Chehab 
289ccae7af2SMauro Carvalho Chehab /*
290ccae7af2SMauro Carvalho Chehab  * mt2063_read - Read data from the I2C bus
291ccae7af2SMauro Carvalho Chehab  */
mt2063_read(struct mt2063_state * state,u8 subAddress,u8 * pData,u32 cnt)29220eb13a7SMauro Carvalho Chehab static int mt2063_read(struct mt2063_state *state,
293ccae7af2SMauro Carvalho Chehab 			   u8 subAddress, u8 *pData, u32 cnt)
294ccae7af2SMauro Carvalho Chehab {
29520eb13a7SMauro Carvalho Chehab 	int status = 0;	/* Status to be returned        */
296ccae7af2SMauro Carvalho Chehab 	struct dvb_frontend *fe = state->frontend;
297ccae7af2SMauro Carvalho Chehab 	u32 i = 0;
298ccae7af2SMauro Carvalho Chehab 
299ccae7af2SMauro Carvalho Chehab 	dprintk(2, "addr 0x%02x, cnt %d\n", subAddress, cnt);
300ccae7af2SMauro Carvalho Chehab 
301ccae7af2SMauro Carvalho Chehab 	if (fe->ops.i2c_gate_ctrl)
302ccae7af2SMauro Carvalho Chehab 		fe->ops.i2c_gate_ctrl(fe, 1);
303ccae7af2SMauro Carvalho Chehab 
304ccae7af2SMauro Carvalho Chehab 	for (i = 0; i < cnt; i++) {
305ccae7af2SMauro Carvalho Chehab 		u8 b0[] = { subAddress + i };
306ccae7af2SMauro Carvalho Chehab 		struct i2c_msg msg[] = {
307ccae7af2SMauro Carvalho Chehab 			{
308ccae7af2SMauro Carvalho Chehab 				.addr = state->config->tuner_address,
309ccae7af2SMauro Carvalho Chehab 				.flags = 0,
310ccae7af2SMauro Carvalho Chehab 				.buf = b0,
311ccae7af2SMauro Carvalho Chehab 				.len = 1
312ccae7af2SMauro Carvalho Chehab 			}, {
313ccae7af2SMauro Carvalho Chehab 				.addr = state->config->tuner_address,
314ccae7af2SMauro Carvalho Chehab 				.flags = I2C_M_RD,
315ccae7af2SMauro Carvalho Chehab 				.buf = pData + i,
316ccae7af2SMauro Carvalho Chehab 				.len = 1
317ccae7af2SMauro Carvalho Chehab 			}
318ccae7af2SMauro Carvalho Chehab 		};
319ccae7af2SMauro Carvalho Chehab 
320ccae7af2SMauro Carvalho Chehab 		status = i2c_transfer(state->i2c, msg, 2);
321ccae7af2SMauro Carvalho Chehab 		dprintk(2, "addr 0x%02x, ret = %d, val = 0x%02x\n",
322ccae7af2SMauro Carvalho Chehab 			   subAddress + i, status, *(pData + i));
323ccae7af2SMauro Carvalho Chehab 		if (status < 0)
324ccae7af2SMauro Carvalho Chehab 			break;
325ccae7af2SMauro Carvalho Chehab 	}
326ccae7af2SMauro Carvalho Chehab 	if (fe->ops.i2c_gate_ctrl)
327ccae7af2SMauro Carvalho Chehab 		fe->ops.i2c_gate_ctrl(fe, 0);
328ccae7af2SMauro Carvalho Chehab 
329ccae7af2SMauro Carvalho Chehab 	if (status < 0)
330ccae7af2SMauro Carvalho Chehab 		printk(KERN_ERR "Can't read from address 0x%02x,\n",
331ccae7af2SMauro Carvalho Chehab 		       subAddress + i);
332ccae7af2SMauro Carvalho Chehab 
333ccae7af2SMauro Carvalho Chehab 	return status;
334ccae7af2SMauro Carvalho Chehab }
335ccae7af2SMauro Carvalho Chehab 
336ccae7af2SMauro Carvalho Chehab /*
337ccae7af2SMauro Carvalho Chehab  * FIXME: Is this really needed?
338ccae7af2SMauro Carvalho Chehab  */
MT2063_Sleep(struct dvb_frontend * fe)339ccae7af2SMauro Carvalho Chehab static int MT2063_Sleep(struct dvb_frontend *fe)
340ccae7af2SMauro Carvalho Chehab {
341ccae7af2SMauro Carvalho Chehab 	/*
342ccae7af2SMauro Carvalho Chehab 	 *  ToDo:  Add code here to implement a OS blocking
343ccae7af2SMauro Carvalho Chehab 	 */
344ccae7af2SMauro Carvalho Chehab 	msleep(100);
345ccae7af2SMauro Carvalho Chehab 
346ccae7af2SMauro Carvalho Chehab 	return 0;
347ccae7af2SMauro Carvalho Chehab }
348ccae7af2SMauro Carvalho Chehab 
349ccae7af2SMauro Carvalho Chehab /*
350ccae7af2SMauro Carvalho Chehab  * Microtune spur avoidance
351ccae7af2SMauro Carvalho Chehab  */
352ccae7af2SMauro Carvalho Chehab 
353ccae7af2SMauro Carvalho Chehab /*  Implement ceiling, floor functions.  */
354ccae7af2SMauro Carvalho Chehab #define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0))
355ccae7af2SMauro Carvalho Chehab #define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d))
356ccae7af2SMauro Carvalho Chehab 
357ccae7af2SMauro Carvalho Chehab struct MT2063_FIFZone_t {
358ccae7af2SMauro Carvalho Chehab 	s32 min_;
359ccae7af2SMauro Carvalho Chehab 	s32 max_;
360ccae7af2SMauro Carvalho Chehab };
361ccae7af2SMauro Carvalho Chehab 
InsertNode(struct MT2063_AvoidSpursData_t * pAS_Info,struct MT2063_ExclZone_t * pPrevNode)362ccae7af2SMauro Carvalho Chehab static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t
363ccae7af2SMauro Carvalho Chehab 					    *pAS_Info,
364ccae7af2SMauro Carvalho Chehab 					    struct MT2063_ExclZone_t *pPrevNode)
365ccae7af2SMauro Carvalho Chehab {
366ccae7af2SMauro Carvalho Chehab 	struct MT2063_ExclZone_t *pNode;
367ccae7af2SMauro Carvalho Chehab 
368ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
369ccae7af2SMauro Carvalho Chehab 
370ccae7af2SMauro Carvalho Chehab 	/*  Check for a node in the free list  */
371ccae7af2SMauro Carvalho Chehab 	if (pAS_Info->freeZones != NULL) {
372ccae7af2SMauro Carvalho Chehab 		/*  Use one from the free list  */
373ccae7af2SMauro Carvalho Chehab 		pNode = pAS_Info->freeZones;
374ccae7af2SMauro Carvalho Chehab 		pAS_Info->freeZones = pNode->next_;
375ccae7af2SMauro Carvalho Chehab 	} else {
376ccae7af2SMauro Carvalho Chehab 		/*  Grab a node from the array  */
377ccae7af2SMauro Carvalho Chehab 		pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones];
378ccae7af2SMauro Carvalho Chehab 	}
379ccae7af2SMauro Carvalho Chehab 
380ccae7af2SMauro Carvalho Chehab 	if (pPrevNode != NULL) {
381ccae7af2SMauro Carvalho Chehab 		pNode->next_ = pPrevNode->next_;
382ccae7af2SMauro Carvalho Chehab 		pPrevNode->next_ = pNode;
383ccae7af2SMauro Carvalho Chehab 	} else {		/*  insert at the beginning of the list  */
384ccae7af2SMauro Carvalho Chehab 
385ccae7af2SMauro Carvalho Chehab 		pNode->next_ = pAS_Info->usedZones;
386ccae7af2SMauro Carvalho Chehab 		pAS_Info->usedZones = pNode;
387ccae7af2SMauro Carvalho Chehab 	}
388ccae7af2SMauro Carvalho Chehab 
389ccae7af2SMauro Carvalho Chehab 	pAS_Info->nZones++;
390ccae7af2SMauro Carvalho Chehab 	return pNode;
391ccae7af2SMauro Carvalho Chehab }
392ccae7af2SMauro Carvalho Chehab 
RemoveNode(struct MT2063_AvoidSpursData_t * pAS_Info,struct MT2063_ExclZone_t * pPrevNode,struct MT2063_ExclZone_t * pNodeToRemove)393ccae7af2SMauro Carvalho Chehab static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t
394ccae7af2SMauro Carvalho Chehab 					    *pAS_Info,
395ccae7af2SMauro Carvalho Chehab 					    struct MT2063_ExclZone_t *pPrevNode,
396ccae7af2SMauro Carvalho Chehab 					    struct MT2063_ExclZone_t
397ccae7af2SMauro Carvalho Chehab 					    *pNodeToRemove)
398ccae7af2SMauro Carvalho Chehab {
399ccae7af2SMauro Carvalho Chehab 	struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_;
400ccae7af2SMauro Carvalho Chehab 
401ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
402ccae7af2SMauro Carvalho Chehab 
403ccae7af2SMauro Carvalho Chehab 	/*  Make previous node point to the subsequent node  */
404ccae7af2SMauro Carvalho Chehab 	if (pPrevNode != NULL)
405ccae7af2SMauro Carvalho Chehab 		pPrevNode->next_ = pNext;
406ccae7af2SMauro Carvalho Chehab 
407ccae7af2SMauro Carvalho Chehab 	/*  Add pNodeToRemove to the beginning of the freeZones  */
408ccae7af2SMauro Carvalho Chehab 	pNodeToRemove->next_ = pAS_Info->freeZones;
409ccae7af2SMauro Carvalho Chehab 	pAS_Info->freeZones = pNodeToRemove;
410ccae7af2SMauro Carvalho Chehab 
411ccae7af2SMauro Carvalho Chehab 	/*  Decrement node count  */
412ccae7af2SMauro Carvalho Chehab 	pAS_Info->nZones--;
413ccae7af2SMauro Carvalho Chehab 
414ccae7af2SMauro Carvalho Chehab 	return pNext;
415ccae7af2SMauro Carvalho Chehab }
416ccae7af2SMauro Carvalho Chehab 
417ccae7af2SMauro Carvalho Chehab /*
418ccae7af2SMauro Carvalho Chehab  * MT_AddExclZone()
419ccae7af2SMauro Carvalho Chehab  *
420ccae7af2SMauro Carvalho Chehab  * Add (and merge) an exclusion zone into the list.
421ccae7af2SMauro Carvalho Chehab  * If the range (f_min, f_max) is totally outside the
422ccae7af2SMauro Carvalho Chehab  * 1st IF BW, ignore the entry.
423ccae7af2SMauro Carvalho Chehab  * If the range (f_min, f_max) is negative, ignore the entry.
424ccae7af2SMauro Carvalho Chehab  */
MT2063_AddExclZone(struct MT2063_AvoidSpursData_t * pAS_Info,u32 f_min,u32 f_max)425ccae7af2SMauro Carvalho Chehab static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
426ccae7af2SMauro Carvalho Chehab 			       u32 f_min, u32 f_max)
427ccae7af2SMauro Carvalho Chehab {
428ccae7af2SMauro Carvalho Chehab 	struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
429ccae7af2SMauro Carvalho Chehab 	struct MT2063_ExclZone_t *pPrev = NULL;
430ccae7af2SMauro Carvalho Chehab 	struct MT2063_ExclZone_t *pNext = NULL;
431ccae7af2SMauro Carvalho Chehab 
432ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
433ccae7af2SMauro Carvalho Chehab 
434ccae7af2SMauro Carvalho Chehab 	/*  Check to see if this overlaps the 1st IF filter  */
435ccae7af2SMauro Carvalho Chehab 	if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2)))
436ccae7af2SMauro Carvalho Chehab 	    && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2)))
437ccae7af2SMauro Carvalho Chehab 	    && (f_min < f_max)) {
438ccae7af2SMauro Carvalho Chehab 		/*
439ccae7af2SMauro Carvalho Chehab 		 *                1        2         3      4       5        6
440ccae7af2SMauro Carvalho Chehab 		 *
441ccae7af2SMauro Carvalho Chehab 		 *   New entry:  |---|    |--|      |--|    |-|    |---|    |--|
442ccae7af2SMauro Carvalho Chehab 		 *                or       or        or     or      or
443ccae7af2SMauro Carvalho Chehab 		 *   Existing:  |--|      |--|      |--|    |---|  |-|      |--|
444ccae7af2SMauro Carvalho Chehab 		 */
445ccae7af2SMauro Carvalho Chehab 
446ccae7af2SMauro Carvalho Chehab 		/*  Check for our place in the list  */
447ccae7af2SMauro Carvalho Chehab 		while ((pNode != NULL) && (pNode->max_ < f_min)) {
448ccae7af2SMauro Carvalho Chehab 			pPrev = pNode;
449ccae7af2SMauro Carvalho Chehab 			pNode = pNode->next_;
450ccae7af2SMauro Carvalho Chehab 		}
451ccae7af2SMauro Carvalho Chehab 
452ccae7af2SMauro Carvalho Chehab 		if ((pNode != NULL) && (pNode->min_ < f_max)) {
453ccae7af2SMauro Carvalho Chehab 			/*  Combine me with pNode  */
454ccae7af2SMauro Carvalho Chehab 			if (f_min < pNode->min_)
455ccae7af2SMauro Carvalho Chehab 				pNode->min_ = f_min;
456ccae7af2SMauro Carvalho Chehab 			if (f_max > pNode->max_)
457ccae7af2SMauro Carvalho Chehab 				pNode->max_ = f_max;
458ccae7af2SMauro Carvalho Chehab 		} else {
459ccae7af2SMauro Carvalho Chehab 			pNode = InsertNode(pAS_Info, pPrev);
460ccae7af2SMauro Carvalho Chehab 			pNode->min_ = f_min;
461ccae7af2SMauro Carvalho Chehab 			pNode->max_ = f_max;
462ccae7af2SMauro Carvalho Chehab 		}
463ccae7af2SMauro Carvalho Chehab 
464ccae7af2SMauro Carvalho Chehab 		/*  Look for merging possibilities  */
465ccae7af2SMauro Carvalho Chehab 		pNext = pNode->next_;
466ccae7af2SMauro Carvalho Chehab 		while ((pNext != NULL) && (pNext->min_ < pNode->max_)) {
467ccae7af2SMauro Carvalho Chehab 			if (pNext->max_ > pNode->max_)
468ccae7af2SMauro Carvalho Chehab 				pNode->max_ = pNext->max_;
469ccae7af2SMauro Carvalho Chehab 			/*  Remove pNext, return ptr to pNext->next  */
470ccae7af2SMauro Carvalho Chehab 			pNext = RemoveNode(pAS_Info, pNode, pNext);
471ccae7af2SMauro Carvalho Chehab 		}
472ccae7af2SMauro Carvalho Chehab 	}
473ccae7af2SMauro Carvalho Chehab }
474ccae7af2SMauro Carvalho Chehab 
475ccae7af2SMauro Carvalho Chehab /*
476ccae7af2SMauro Carvalho Chehab  *  Reset all exclusion zones.
477ccae7af2SMauro Carvalho Chehab  *  Add zones to protect the PLL FracN regions near zero
478ccae7af2SMauro Carvalho Chehab  */
MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t * pAS_Info)479ccae7af2SMauro Carvalho Chehab static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info)
480ccae7af2SMauro Carvalho Chehab {
481ccae7af2SMauro Carvalho Chehab 	u32 center;
482ccae7af2SMauro Carvalho Chehab 
483ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
484ccae7af2SMauro Carvalho Chehab 
485ccae7af2SMauro Carvalho Chehab 	pAS_Info->nZones = 0;	/*  this clears the used list  */
486ccae7af2SMauro Carvalho Chehab 	pAS_Info->usedZones = NULL;	/*  reset ptr                  */
487ccae7af2SMauro Carvalho Chehab 	pAS_Info->freeZones = NULL;	/*  reset ptr                  */
488ccae7af2SMauro Carvalho Chehab 
489ccae7af2SMauro Carvalho Chehab 	center =
490ccae7af2SMauro Carvalho Chehab 	    pAS_Info->f_ref *
491ccae7af2SMauro Carvalho Chehab 	    ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 +
492ccae7af2SMauro Carvalho Chehab 	      pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in;
493ccae7af2SMauro Carvalho Chehab 	while (center <
494ccae7af2SMauro Carvalho Chehab 	       pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
495ccae7af2SMauro Carvalho Chehab 	       pAS_Info->f_LO1_FracN_Avoid) {
496ccae7af2SMauro Carvalho Chehab 		/*  Exclude LO1 FracN  */
497ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info,
498ccae7af2SMauro Carvalho Chehab 				   center - pAS_Info->f_LO1_FracN_Avoid,
499ccae7af2SMauro Carvalho Chehab 				   center - 1);
500ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, center + 1,
501ccae7af2SMauro Carvalho Chehab 				   center + pAS_Info->f_LO1_FracN_Avoid);
502ccae7af2SMauro Carvalho Chehab 		center += pAS_Info->f_ref;
503ccae7af2SMauro Carvalho Chehab 	}
504ccae7af2SMauro Carvalho Chehab 
505ccae7af2SMauro Carvalho Chehab 	center =
506ccae7af2SMauro Carvalho Chehab 	    pAS_Info->f_ref *
507ccae7af2SMauro Carvalho Chehab 	    ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 -
508ccae7af2SMauro Carvalho Chehab 	      pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out;
509ccae7af2SMauro Carvalho Chehab 	while (center <
510ccae7af2SMauro Carvalho Chehab 	       pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
511ccae7af2SMauro Carvalho Chehab 	       pAS_Info->f_LO2_FracN_Avoid) {
512ccae7af2SMauro Carvalho Chehab 		/*  Exclude LO2 FracN  */
513ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info,
514ccae7af2SMauro Carvalho Chehab 				   center - pAS_Info->f_LO2_FracN_Avoid,
515ccae7af2SMauro Carvalho Chehab 				   center - 1);
516ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, center + 1,
517ccae7af2SMauro Carvalho Chehab 				   center + pAS_Info->f_LO2_FracN_Avoid);
518ccae7af2SMauro Carvalho Chehab 		center += pAS_Info->f_ref;
519ccae7af2SMauro Carvalho Chehab 	}
520ccae7af2SMauro Carvalho Chehab 
521ccae7af2SMauro Carvalho Chehab 	if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
522ccae7af2SMauro Carvalho Chehab 		/*  Exclude LO1 values that conflict with DECT channels */
523ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in);	/* Ctr = 1921.536 */
524ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in);	/* Ctr = 1923.264 */
525ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in);	/* Ctr = 1924.992 */
526ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in);	/* Ctr = 1926.720 */
527ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in);	/* Ctr = 1928.448 */
528ccae7af2SMauro Carvalho Chehab 	}
529ccae7af2SMauro Carvalho Chehab 
530ccae7af2SMauro Carvalho Chehab 	if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
531ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in);	/* Ctr = 1897.344 */
532ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in);	/* Ctr = 1895.616 */
533ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in);	/* Ctr = 1893.888 */
534ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in);	/* Ctr = 1892.16  */
535ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in);	/* Ctr = 1890.432 */
536ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in);	/* Ctr = 1888.704 */
537ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in);	/* Ctr = 1886.976 */
538ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in);	/* Ctr = 1885.248 */
539ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in);	/* Ctr = 1883.52  */
540ccae7af2SMauro Carvalho Chehab 		MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in);	/* Ctr = 1881.792 */
541ccae7af2SMauro Carvalho Chehab 	}
542ccae7af2SMauro Carvalho Chehab }
543ccae7af2SMauro Carvalho Chehab 
544ccae7af2SMauro Carvalho Chehab /*
545ccae7af2SMauro Carvalho Chehab  * MT_ChooseFirstIF - Choose the best available 1st IF
546ccae7af2SMauro Carvalho Chehab  *                    If f_Desired is not excluded, choose that first.
547ccae7af2SMauro Carvalho Chehab  *                    Otherwise, return the value closest to f_Center that is
548ccae7af2SMauro Carvalho Chehab  *                    not excluded
549ccae7af2SMauro Carvalho Chehab  */
MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t * pAS_Info)550ccae7af2SMauro Carvalho Chehab static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info)
551ccae7af2SMauro Carvalho Chehab {
552ccae7af2SMauro Carvalho Chehab 	/*
553ccae7af2SMauro Carvalho Chehab 	 * Update "f_Desired" to be the nearest "combinational-multiple" of
554ccae7af2SMauro Carvalho Chehab 	 * "f_LO1_Step".
555ccae7af2SMauro Carvalho Chehab 	 * The resulting number, F_LO1 must be a multiple of f_LO1_Step.
556ccae7af2SMauro Carvalho Chehab 	 * And F_LO1 is the arithmetic sum of f_in + f_Center.
557ccae7af2SMauro Carvalho Chehab 	 * Neither f_in, nor f_Center must be a multiple of f_LO1_Step.
558ccae7af2SMauro Carvalho Chehab 	 * However, the sum must be.
559ccae7af2SMauro Carvalho Chehab 	 */
560ccae7af2SMauro Carvalho Chehab 	const u32 f_Desired =
561ccae7af2SMauro Carvalho Chehab 	    pAS_Info->f_LO1_Step *
562ccae7af2SMauro Carvalho Chehab 	    ((pAS_Info->f_if1_Request + pAS_Info->f_in +
563ccae7af2SMauro Carvalho Chehab 	      pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) -
564ccae7af2SMauro Carvalho Chehab 	    pAS_Info->f_in;
565ccae7af2SMauro Carvalho Chehab 	const u32 f_Step =
566ccae7af2SMauro Carvalho Chehab 	    (pAS_Info->f_LO1_Step >
567ccae7af2SMauro Carvalho Chehab 	     pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info->
568ccae7af2SMauro Carvalho Chehab 	    f_LO2_Step;
569ccae7af2SMauro Carvalho Chehab 	u32 f_Center;
570ccae7af2SMauro Carvalho Chehab 	s32 i;
571ccae7af2SMauro Carvalho Chehab 	s32 j = 0;
572ccae7af2SMauro Carvalho Chehab 	u32 bDesiredExcluded = 0;
573ccae7af2SMauro Carvalho Chehab 	u32 bZeroExcluded = 0;
574ccae7af2SMauro Carvalho Chehab 	s32 tmpMin, tmpMax;
575ccae7af2SMauro Carvalho Chehab 	s32 bestDiff;
576ccae7af2SMauro Carvalho Chehab 	struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
577ccae7af2SMauro Carvalho Chehab 	struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES];
578ccae7af2SMauro Carvalho Chehab 
579ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
580ccae7af2SMauro Carvalho Chehab 
581ccae7af2SMauro Carvalho Chehab 	if (pAS_Info->nZones == 0)
582ccae7af2SMauro Carvalho Chehab 		return f_Desired;
583ccae7af2SMauro Carvalho Chehab 
584ccae7af2SMauro Carvalho Chehab 	/*
585ccae7af2SMauro Carvalho Chehab 	 *  f_Center needs to be an integer multiple of f_Step away
586ccae7af2SMauro Carvalho Chehab 	 *  from f_Desired
587ccae7af2SMauro Carvalho Chehab 	 */
588ccae7af2SMauro Carvalho Chehab 	if (pAS_Info->f_if1_Center > f_Desired)
589ccae7af2SMauro Carvalho Chehab 		f_Center =
590ccae7af2SMauro Carvalho Chehab 		    f_Desired +
591ccae7af2SMauro Carvalho Chehab 		    f_Step *
592ccae7af2SMauro Carvalho Chehab 		    ((pAS_Info->f_if1_Center - f_Desired +
593ccae7af2SMauro Carvalho Chehab 		      f_Step / 2) / f_Step);
594ccae7af2SMauro Carvalho Chehab 	else
595ccae7af2SMauro Carvalho Chehab 		f_Center =
596ccae7af2SMauro Carvalho Chehab 		    f_Desired -
597ccae7af2SMauro Carvalho Chehab 		    f_Step *
598ccae7af2SMauro Carvalho Chehab 		    ((f_Desired - pAS_Info->f_if1_Center +
599ccae7af2SMauro Carvalho Chehab 		      f_Step / 2) / f_Step);
600ccae7af2SMauro Carvalho Chehab 
601ccae7af2SMauro Carvalho Chehab 	/*
602ccae7af2SMauro Carvalho Chehab 	 * Take MT_ExclZones, center around f_Center and change the
603ccae7af2SMauro Carvalho Chehab 	 * resolution to f_Step
604ccae7af2SMauro Carvalho Chehab 	 */
605ccae7af2SMauro Carvalho Chehab 	while (pNode != NULL) {
606ccae7af2SMauro Carvalho Chehab 		/*  floor function  */
607ccae7af2SMauro Carvalho Chehab 		tmpMin =
608ccae7af2SMauro Carvalho Chehab 		    floor((s32) (pNode->min_ - f_Center), (s32) f_Step);
609ccae7af2SMauro Carvalho Chehab 
610ccae7af2SMauro Carvalho Chehab 		/*  ceil function  */
611ccae7af2SMauro Carvalho Chehab 		tmpMax =
612ccae7af2SMauro Carvalho Chehab 		    ceil((s32) (pNode->max_ - f_Center), (s32) f_Step);
613ccae7af2SMauro Carvalho Chehab 
614ccae7af2SMauro Carvalho Chehab 		if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired))
615ccae7af2SMauro Carvalho Chehab 			bDesiredExcluded = 1;
616ccae7af2SMauro Carvalho Chehab 
617ccae7af2SMauro Carvalho Chehab 		if ((tmpMin < 0) && (tmpMax > 0))
618ccae7af2SMauro Carvalho Chehab 			bZeroExcluded = 1;
619ccae7af2SMauro Carvalho Chehab 
620ccae7af2SMauro Carvalho Chehab 		/*  See if this zone overlaps the previous  */
621ccae7af2SMauro Carvalho Chehab 		if ((j > 0) && (tmpMin < zones[j - 1].max_))
622ccae7af2SMauro Carvalho Chehab 			zones[j - 1].max_ = tmpMax;
623ccae7af2SMauro Carvalho Chehab 		else {
624ccae7af2SMauro Carvalho Chehab 			/*  Add new zone  */
625ccae7af2SMauro Carvalho Chehab 			zones[j].min_ = tmpMin;
626ccae7af2SMauro Carvalho Chehab 			zones[j].max_ = tmpMax;
627ccae7af2SMauro Carvalho Chehab 			j++;
628ccae7af2SMauro Carvalho Chehab 		}
629ccae7af2SMauro Carvalho Chehab 		pNode = pNode->next_;
630ccae7af2SMauro Carvalho Chehab 	}
631ccae7af2SMauro Carvalho Chehab 
632ccae7af2SMauro Carvalho Chehab 	/*
633ccae7af2SMauro Carvalho Chehab 	 *  If the desired is okay, return with it
634ccae7af2SMauro Carvalho Chehab 	 */
635ccae7af2SMauro Carvalho Chehab 	if (bDesiredExcluded == 0)
636ccae7af2SMauro Carvalho Chehab 		return f_Desired;
637ccae7af2SMauro Carvalho Chehab 
638ccae7af2SMauro Carvalho Chehab 	/*
639ccae7af2SMauro Carvalho Chehab 	 *  If the desired is excluded and the center is okay, return with it
640ccae7af2SMauro Carvalho Chehab 	 */
641ccae7af2SMauro Carvalho Chehab 	if (bZeroExcluded == 0)
642ccae7af2SMauro Carvalho Chehab 		return f_Center;
643ccae7af2SMauro Carvalho Chehab 
644ccae7af2SMauro Carvalho Chehab 	/*  Find the value closest to 0 (f_Center)  */
645ccae7af2SMauro Carvalho Chehab 	bestDiff = zones[0].min_;
646ccae7af2SMauro Carvalho Chehab 	for (i = 0; i < j; i++) {
647ccae7af2SMauro Carvalho Chehab 		if (abs(zones[i].min_) < abs(bestDiff))
648ccae7af2SMauro Carvalho Chehab 			bestDiff = zones[i].min_;
649ccae7af2SMauro Carvalho Chehab 		if (abs(zones[i].max_) < abs(bestDiff))
650ccae7af2SMauro Carvalho Chehab 			bestDiff = zones[i].max_;
651ccae7af2SMauro Carvalho Chehab 	}
652ccae7af2SMauro Carvalho Chehab 
653ccae7af2SMauro Carvalho Chehab 	if (bestDiff < 0)
654ccae7af2SMauro Carvalho Chehab 		return f_Center - ((u32) (-bestDiff) * f_Step);
655ccae7af2SMauro Carvalho Chehab 
656ccae7af2SMauro Carvalho Chehab 	return f_Center + (bestDiff * f_Step);
657ccae7af2SMauro Carvalho Chehab }
658ccae7af2SMauro Carvalho Chehab 
659ccae7af2SMauro Carvalho Chehab /**
660ccae7af2SMauro Carvalho Chehab  * IsSpurInBand() - Checks to see if a spur will be present within the IF's
661ccae7af2SMauro Carvalho Chehab  *                  bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW)
662ccae7af2SMauro Carvalho Chehab  *
663ccae7af2SMauro Carvalho Chehab  *                    ma   mb                                     mc   md
664ccae7af2SMauro Carvalho Chehab  *                  <--+-+-+-------------------+-------------------+-+-+-->
665ccae7af2SMauro Carvalho Chehab  *                     |   ^                   0                   ^   |
666ccae7af2SMauro Carvalho Chehab  *                     ^   b=-fIFOut+fIFBW/2      -b=+fIFOut-fIFBW/2   ^
667ccae7af2SMauro Carvalho Chehab  *                     a=-fIFOut-fIFBW/2              -a=+fIFOut+fIFBW/2
668ccae7af2SMauro Carvalho Chehab  *
669ccae7af2SMauro Carvalho Chehab  *                  Note that some equations are doubled to prevent round-off
670ccae7af2SMauro Carvalho Chehab  *                  problems when calculating fIFBW/2
671ccae7af2SMauro Carvalho Chehab  *
672ccae7af2SMauro Carvalho Chehab  * @pAS_Info:	Avoid Spurs information block
673ccae7af2SMauro Carvalho Chehab  * @fm:		If spur, amount f_IF1 has to move negative
674ccae7af2SMauro Carvalho Chehab  * @fp:		If spur, amount f_IF1 has to move positive
675ccae7af2SMauro Carvalho Chehab  *
676ccae7af2SMauro Carvalho Chehab  *  Returns 1 if an LO spur would be present, otherwise 0.
677ccae7af2SMauro Carvalho Chehab  */
IsSpurInBand(struct MT2063_AvoidSpursData_t * pAS_Info,u32 * fm,u32 * fp)678ccae7af2SMauro Carvalho Chehab static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info,
679ccae7af2SMauro Carvalho Chehab 			u32 *fm, u32 * fp)
680ccae7af2SMauro Carvalho Chehab {
681ccae7af2SMauro Carvalho Chehab 	/*
682ccae7af2SMauro Carvalho Chehab 	 **  Calculate LO frequency settings.
683ccae7af2SMauro Carvalho Chehab 	 */
684ccae7af2SMauro Carvalho Chehab 	u32 n, n0;
685ccae7af2SMauro Carvalho Chehab 	const u32 f_LO1 = pAS_Info->f_LO1;
686ccae7af2SMauro Carvalho Chehab 	const u32 f_LO2 = pAS_Info->f_LO2;
687ccae7af2SMauro Carvalho Chehab 	const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2;
688ccae7af2SMauro Carvalho Chehab 	const u32 c = d - pAS_Info->f_out_bw;
689ccae7af2SMauro Carvalho Chehab 	const u32 f = pAS_Info->f_zif_bw / 2;
690ccae7af2SMauro Carvalho Chehab 	const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1;
691ccae7af2SMauro Carvalho Chehab 	s32 f_nsLO1, f_nsLO2;
692ccae7af2SMauro Carvalho Chehab 	s32 f_Spur;
693ccae7af2SMauro Carvalho Chehab 	u32 ma, mb, mc, md, me, mf;
694ccae7af2SMauro Carvalho Chehab 	u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs;
695ccae7af2SMauro Carvalho Chehab 
696ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
697ccae7af2SMauro Carvalho Chehab 
698ccae7af2SMauro Carvalho Chehab 	*fm = 0;
699ccae7af2SMauro Carvalho Chehab 
700ccae7af2SMauro Carvalho Chehab 	/*
701ccae7af2SMauro Carvalho Chehab 	 ** For each edge (d, c & f), calculate a scale, based on the gcd
702ccae7af2SMauro Carvalho Chehab 	 ** of f_LO1, f_LO2 and the edge value.  Use the larger of this
703ccae7af2SMauro Carvalho Chehab 	 ** gcd-based scale factor or f_Scale.
704ccae7af2SMauro Carvalho Chehab 	 */
705917d11a4SZhaoxiu Zeng 	lo_gcd = gcd(f_LO1, f_LO2);
706917d11a4SZhaoxiu Zeng 	gd_Scale = max((u32) gcd(lo_gcd, d), f_Scale);
707ccae7af2SMauro Carvalho Chehab 	hgds = gd_Scale / 2;
708917d11a4SZhaoxiu Zeng 	gc_Scale = max((u32) gcd(lo_gcd, c), f_Scale);
709ccae7af2SMauro Carvalho Chehab 	hgcs = gc_Scale / 2;
710917d11a4SZhaoxiu Zeng 	gf_Scale = max((u32) gcd(lo_gcd, f), f_Scale);
711ccae7af2SMauro Carvalho Chehab 	hgfs = gf_Scale / 2;
712ccae7af2SMauro Carvalho Chehab 
713ccae7af2SMauro Carvalho Chehab 	n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2);
714ccae7af2SMauro Carvalho Chehab 
715ccae7af2SMauro Carvalho Chehab 	/*  Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic  */
716ccae7af2SMauro Carvalho Chehab 	for (n = n0; n <= pAS_Info->maxH1; ++n) {
717ccae7af2SMauro Carvalho Chehab 		md = (n * ((f_LO1 + hgds) / gd_Scale) -
718ccae7af2SMauro Carvalho Chehab 		      ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
719ccae7af2SMauro Carvalho Chehab 
720ccae7af2SMauro Carvalho Chehab 		/*  If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present  */
721ccae7af2SMauro Carvalho Chehab 		if (md >= pAS_Info->maxH1)
722ccae7af2SMauro Carvalho Chehab 			break;
723ccae7af2SMauro Carvalho Chehab 
724ccae7af2SMauro Carvalho Chehab 		ma = (n * ((f_LO1 + hgds) / gd_Scale) +
725ccae7af2SMauro Carvalho Chehab 		      ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
726ccae7af2SMauro Carvalho Chehab 
727ccae7af2SMauro Carvalho Chehab 		/*  If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic  */
728ccae7af2SMauro Carvalho Chehab 		if (md == ma)
729ccae7af2SMauro Carvalho Chehab 			continue;
730ccae7af2SMauro Carvalho Chehab 
731ccae7af2SMauro Carvalho Chehab 		mc = (n * ((f_LO1 + hgcs) / gc_Scale) -
732ccae7af2SMauro Carvalho Chehab 		      ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
733ccae7af2SMauro Carvalho Chehab 		if (mc != md) {
734ccae7af2SMauro Carvalho Chehab 			f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale));
735ccae7af2SMauro Carvalho Chehab 			f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale));
736ccae7af2SMauro Carvalho Chehab 			f_Spur =
737ccae7af2SMauro Carvalho Chehab 			    (gc_Scale * (f_nsLO1 - f_nsLO2)) +
738ccae7af2SMauro Carvalho Chehab 			    n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale);
739ccae7af2SMauro Carvalho Chehab 
740ccae7af2SMauro Carvalho Chehab 			*fp = ((f_Spur - (s32) c) / (mc - n)) + 1;
741ccae7af2SMauro Carvalho Chehab 			*fm = (((s32) d - f_Spur) / (mc - n)) + 1;
742ccae7af2SMauro Carvalho Chehab 			return 1;
743ccae7af2SMauro Carvalho Chehab 		}
744ccae7af2SMauro Carvalho Chehab 
745ccae7af2SMauro Carvalho Chehab 		/*  Location of Zero-IF-spur to be checked  */
746ccae7af2SMauro Carvalho Chehab 		me = (n * ((f_LO1 + hgfs) / gf_Scale) +
747ccae7af2SMauro Carvalho Chehab 		      ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
748ccae7af2SMauro Carvalho Chehab 		mf = (n * ((f_LO1 + hgfs) / gf_Scale) -
749ccae7af2SMauro Carvalho Chehab 		      ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
750ccae7af2SMauro Carvalho Chehab 		if (me != mf) {
751ccae7af2SMauro Carvalho Chehab 			f_nsLO1 = n * (f_LO1 / gf_Scale);
752ccae7af2SMauro Carvalho Chehab 			f_nsLO2 = me * (f_LO2 / gf_Scale);
753ccae7af2SMauro Carvalho Chehab 			f_Spur =
754ccae7af2SMauro Carvalho Chehab 			    (gf_Scale * (f_nsLO1 - f_nsLO2)) +
755ccae7af2SMauro Carvalho Chehab 			    n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale);
756ccae7af2SMauro Carvalho Chehab 
757ccae7af2SMauro Carvalho Chehab 			*fp = ((f_Spur + (s32) f) / (me - n)) + 1;
758ccae7af2SMauro Carvalho Chehab 			*fm = (((s32) f - f_Spur) / (me - n)) + 1;
759ccae7af2SMauro Carvalho Chehab 			return 1;
760ccae7af2SMauro Carvalho Chehab 		}
761ccae7af2SMauro Carvalho Chehab 
762ccae7af2SMauro Carvalho Chehab 		mb = (n * ((f_LO1 + hgcs) / gc_Scale) +
763ccae7af2SMauro Carvalho Chehab 		      ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
764ccae7af2SMauro Carvalho Chehab 		if (ma != mb) {
765ccae7af2SMauro Carvalho Chehab 			f_nsLO1 = n * (f_LO1 / gc_Scale);
766ccae7af2SMauro Carvalho Chehab 			f_nsLO2 = ma * (f_LO2 / gc_Scale);
767ccae7af2SMauro Carvalho Chehab 			f_Spur =
768ccae7af2SMauro Carvalho Chehab 			    (gc_Scale * (f_nsLO1 - f_nsLO2)) +
769ccae7af2SMauro Carvalho Chehab 			    n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale);
770ccae7af2SMauro Carvalho Chehab 
771ccae7af2SMauro Carvalho Chehab 			*fp = (((s32) d + f_Spur) / (ma - n)) + 1;
772ccae7af2SMauro Carvalho Chehab 			*fm = (-(f_Spur + (s32) c) / (ma - n)) + 1;
773ccae7af2SMauro Carvalho Chehab 			return 1;
774ccae7af2SMauro Carvalho Chehab 		}
775ccae7af2SMauro Carvalho Chehab 	}
776ccae7af2SMauro Carvalho Chehab 
777ccae7af2SMauro Carvalho Chehab 	/*  No spurs found  */
778ccae7af2SMauro Carvalho Chehab 	return 0;
779ccae7af2SMauro Carvalho Chehab }
780ccae7af2SMauro Carvalho Chehab 
781ccae7af2SMauro Carvalho Chehab /*
782ccae7af2SMauro Carvalho Chehab  * MT_AvoidSpurs() - Main entry point to avoid spurs.
783ccae7af2SMauro Carvalho Chehab  *                   Checks for existing spurs in present LO1, LO2 freqs
784ccae7af2SMauro Carvalho Chehab  *                   and if present, chooses spur-free LO1, LO2 combination
785ccae7af2SMauro Carvalho Chehab  *                   that tunes the same input/output frequencies.
786ccae7af2SMauro Carvalho Chehab  */
MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t * pAS_Info)787ccae7af2SMauro Carvalho Chehab static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info)
788ccae7af2SMauro Carvalho Chehab {
78920eb13a7SMauro Carvalho Chehab 	int status = 0;
790ccae7af2SMauro Carvalho Chehab 	u32 fm, fp;		/*  restricted range on LO's        */
791ccae7af2SMauro Carvalho Chehab 	pAS_Info->bSpurAvoided = 0;
792ccae7af2SMauro Carvalho Chehab 	pAS_Info->nSpursFound = 0;
793ccae7af2SMauro Carvalho Chehab 
794ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
795ccae7af2SMauro Carvalho Chehab 
796ccae7af2SMauro Carvalho Chehab 	if (pAS_Info->maxH1 == 0)
797ccae7af2SMauro Carvalho Chehab 		return 0;
798ccae7af2SMauro Carvalho Chehab 
799ccae7af2SMauro Carvalho Chehab 	/*
800ccae7af2SMauro Carvalho Chehab 	 * Avoid LO Generated Spurs
801ccae7af2SMauro Carvalho Chehab 	 *
802ccae7af2SMauro Carvalho Chehab 	 * Make sure that have no LO-related spurs within the IF output
803ccae7af2SMauro Carvalho Chehab 	 * bandwidth.
804ccae7af2SMauro Carvalho Chehab 	 *
805ccae7af2SMauro Carvalho Chehab 	 * If there is an LO spur in this band, start at the current IF1 frequency
806ccae7af2SMauro Carvalho Chehab 	 * and work out until we find a spur-free frequency or run up against the
807ccae7af2SMauro Carvalho Chehab 	 * 1st IF SAW band edge.  Use temporary copies of fLO1 and fLO2 so that they
808ccae7af2SMauro Carvalho Chehab 	 * will be unchanged if a spur-free setting is not found.
809ccae7af2SMauro Carvalho Chehab 	 */
810ccae7af2SMauro Carvalho Chehab 	pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
811ccae7af2SMauro Carvalho Chehab 	if (pAS_Info->bSpurPresent) {
812ccae7af2SMauro Carvalho Chehab 		u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in;	/*  current attempt at a 1st IF  */
813ccae7af2SMauro Carvalho Chehab 		u32 zfLO1 = pAS_Info->f_LO1;	/*  current attempt at an LO1 freq  */
814ccae7af2SMauro Carvalho Chehab 		u32 zfLO2 = pAS_Info->f_LO2;	/*  current attempt at an LO2 freq  */
815ccae7af2SMauro Carvalho Chehab 		u32 delta_IF1;
816ccae7af2SMauro Carvalho Chehab 		u32 new_IF1;
817ccae7af2SMauro Carvalho Chehab 
818ccae7af2SMauro Carvalho Chehab 		/*
819ccae7af2SMauro Carvalho Chehab 		 **  Spur was found, attempt to find a spur-free 1st IF
820ccae7af2SMauro Carvalho Chehab 		 */
821ccae7af2SMauro Carvalho Chehab 		do {
822ccae7af2SMauro Carvalho Chehab 			pAS_Info->nSpursFound++;
823ccae7af2SMauro Carvalho Chehab 
824ccae7af2SMauro Carvalho Chehab 			/*  Raise f_IF1_upper, if needed  */
825ccae7af2SMauro Carvalho Chehab 			MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp);
826ccae7af2SMauro Carvalho Chehab 
827ccae7af2SMauro Carvalho Chehab 			/*  Choose next IF1 that is closest to f_IF1_CENTER              */
828ccae7af2SMauro Carvalho Chehab 			new_IF1 = MT2063_ChooseFirstIF(pAS_Info);
829ccae7af2SMauro Carvalho Chehab 
830ccae7af2SMauro Carvalho Chehab 			if (new_IF1 > zfIF1) {
831ccae7af2SMauro Carvalho Chehab 				pAS_Info->f_LO1 += (new_IF1 - zfIF1);
832ccae7af2SMauro Carvalho Chehab 				pAS_Info->f_LO2 += (new_IF1 - zfIF1);
833ccae7af2SMauro Carvalho Chehab 			} else {
834ccae7af2SMauro Carvalho Chehab 				pAS_Info->f_LO1 -= (zfIF1 - new_IF1);
835ccae7af2SMauro Carvalho Chehab 				pAS_Info->f_LO2 -= (zfIF1 - new_IF1);
836ccae7af2SMauro Carvalho Chehab 			}
837ccae7af2SMauro Carvalho Chehab 			zfIF1 = new_IF1;
838ccae7af2SMauro Carvalho Chehab 
839ccae7af2SMauro Carvalho Chehab 			if (zfIF1 > pAS_Info->f_if1_Center)
840ccae7af2SMauro Carvalho Chehab 				delta_IF1 = zfIF1 - pAS_Info->f_if1_Center;
841ccae7af2SMauro Carvalho Chehab 			else
842ccae7af2SMauro Carvalho Chehab 				delta_IF1 = pAS_Info->f_if1_Center - zfIF1;
843ccae7af2SMauro Carvalho Chehab 
844ccae7af2SMauro Carvalho Chehab 			pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
845ccae7af2SMauro Carvalho Chehab 		/*
846ccae7af2SMauro Carvalho Chehab 		 *  Continue while the new 1st IF is still within the 1st IF bandwidth
847ccae7af2SMauro Carvalho Chehab 		 *  and there is a spur in the band (again)
848ccae7af2SMauro Carvalho Chehab 		 */
849ccae7af2SMauro Carvalho Chehab 		} while ((2 * delta_IF1 + pAS_Info->f_out_bw <= pAS_Info->f_if1_bw) && pAS_Info->bSpurPresent);
850ccae7af2SMauro Carvalho Chehab 
851ccae7af2SMauro Carvalho Chehab 		/*
852ccae7af2SMauro Carvalho Chehab 		 * Use the LO-spur free values found.  If the search went all
853ccae7af2SMauro Carvalho Chehab 		 * the way to the 1st IF band edge and always found spurs, just
854ccae7af2SMauro Carvalho Chehab 		 * leave the original choice.  It's as "good" as any other.
855ccae7af2SMauro Carvalho Chehab 		 */
856ccae7af2SMauro Carvalho Chehab 		if (pAS_Info->bSpurPresent == 1) {
857ccae7af2SMauro Carvalho Chehab 			status |= MT2063_SPUR_PRESENT_ERR;
858ccae7af2SMauro Carvalho Chehab 			pAS_Info->f_LO1 = zfLO1;
859ccae7af2SMauro Carvalho Chehab 			pAS_Info->f_LO2 = zfLO2;
860ccae7af2SMauro Carvalho Chehab 		} else
861ccae7af2SMauro Carvalho Chehab 			pAS_Info->bSpurAvoided = 1;
862ccae7af2SMauro Carvalho Chehab 	}
863ccae7af2SMauro Carvalho Chehab 
864ccae7af2SMauro Carvalho Chehab 	status |=
865ccae7af2SMauro Carvalho Chehab 	    ((pAS_Info->
866ccae7af2SMauro Carvalho Chehab 	      nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK);
867ccae7af2SMauro Carvalho Chehab 
868ccae7af2SMauro Carvalho Chehab 	return status;
869ccae7af2SMauro Carvalho Chehab }
870ccae7af2SMauro Carvalho Chehab 
871ccae7af2SMauro Carvalho Chehab /*
872ccae7af2SMauro Carvalho Chehab  * Constants used by the tuning algorithm
873ccae7af2SMauro Carvalho Chehab  */
874ccae7af2SMauro Carvalho Chehab #define MT2063_REF_FREQ          (16000000UL)	/* Reference oscillator Frequency (in Hz) */
875ccae7af2SMauro Carvalho Chehab #define MT2063_IF1_BW            (22000000UL)	/* The IF1 filter bandwidth (in Hz) */
876ccae7af2SMauro Carvalho Chehab #define MT2063_TUNE_STEP_SIZE       (50000UL)	/* Tune in steps of 50 kHz */
877ccae7af2SMauro Carvalho Chehab #define MT2063_SPUR_STEP_HZ        (250000UL)	/* Step size (in Hz) to move IF1 when avoiding spurs */
878ccae7af2SMauro Carvalho Chehab #define MT2063_ZIF_BW             (2000000UL)	/* Zero-IF spur-free bandwidth (in Hz) */
879ccae7af2SMauro Carvalho Chehab #define MT2063_MAX_HARMONICS_1         (15UL)	/* Highest intra-tuner LO Spur Harmonic to be avoided */
880ccae7af2SMauro Carvalho Chehab #define MT2063_MAX_HARMONICS_2          (5UL)	/* Highest inter-tuner LO Spur Harmonic to be avoided */
881ccae7af2SMauro Carvalho Chehab #define MT2063_MIN_LO_SEP         (1000000UL)	/* Minimum inter-tuner LO frequency separation */
882ccae7af2SMauro Carvalho Chehab #define MT2063_LO1_FRACN_AVOID          (0UL)	/* LO1 FracN numerator avoid region (in Hz) */
883ccae7af2SMauro Carvalho Chehab #define MT2063_LO2_FRACN_AVOID     (199999UL)	/* LO2 FracN numerator avoid region (in Hz) */
884ccae7af2SMauro Carvalho Chehab #define MT2063_MIN_FIN_FREQ      (44000000UL)	/* Minimum input frequency (in Hz) */
885ccae7af2SMauro Carvalho Chehab #define MT2063_MAX_FIN_FREQ    (1100000000UL)	/* Maximum input frequency (in Hz) */
886ccae7af2SMauro Carvalho Chehab #define MT2063_MIN_FOUT_FREQ     (36000000UL)	/* Minimum output frequency (in Hz) */
887ccae7af2SMauro Carvalho Chehab #define MT2063_MAX_FOUT_FREQ     (57000000UL)	/* Maximum output frequency (in Hz) */
888ccae7af2SMauro Carvalho Chehab #define MT2063_MIN_DNC_FREQ    (1293000000UL)	/* Minimum LO2 frequency (in Hz) */
889ccae7af2SMauro Carvalho Chehab #define MT2063_MAX_DNC_FREQ    (1614000000UL)	/* Maximum LO2 frequency (in Hz) */
890ccae7af2SMauro Carvalho Chehab #define MT2063_MIN_UPC_FREQ    (1396000000UL)	/* Minimum LO1 frequency (in Hz) */
891ccae7af2SMauro Carvalho Chehab #define MT2063_MAX_UPC_FREQ    (2750000000UL)	/* Maximum LO1 frequency (in Hz) */
892ccae7af2SMauro Carvalho Chehab 
893ccae7af2SMauro Carvalho Chehab /*
894ccae7af2SMauro Carvalho Chehab  *  Define the supported Part/Rev codes for the MT2063
895ccae7af2SMauro Carvalho Chehab  */
896ccae7af2SMauro Carvalho Chehab #define MT2063_B0       (0x9B)
897ccae7af2SMauro Carvalho Chehab #define MT2063_B1       (0x9C)
898ccae7af2SMauro Carvalho Chehab #define MT2063_B2       (0x9D)
899ccae7af2SMauro Carvalho Chehab #define MT2063_B3       (0x9E)
900ccae7af2SMauro Carvalho Chehab 
901ccae7af2SMauro Carvalho Chehab /**
902ccae7af2SMauro Carvalho Chehab  * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked
903ccae7af2SMauro Carvalho Chehab  *
904ccae7af2SMauro Carvalho Chehab  * @state:	struct mt2063_state pointer
905ccae7af2SMauro Carvalho Chehab  *
906ccae7af2SMauro Carvalho Chehab  * This function returns 0, if no lock, 1 if locked and a value < 1 if error
907ccae7af2SMauro Carvalho Chehab  */
mt2063_lockStatus(struct mt2063_state * state)90820eb13a7SMauro Carvalho Chehab static int mt2063_lockStatus(struct mt2063_state *state)
909ccae7af2SMauro Carvalho Chehab {
910ccae7af2SMauro Carvalho Chehab 	const u32 nMaxWait = 100;	/*  wait a maximum of 100 msec   */
911ccae7af2SMauro Carvalho Chehab 	const u32 nPollRate = 2;	/*  poll status bits every 2 ms */
912ccae7af2SMauro Carvalho Chehab 	const u32 nMaxLoops = nMaxWait / nPollRate;
913ccae7af2SMauro Carvalho Chehab 	const u8 LO1LK = 0x80;
914ccae7af2SMauro Carvalho Chehab 	u8 LO2LK = 0x08;
91520eb13a7SMauro Carvalho Chehab 	int status;
916ccae7af2SMauro Carvalho Chehab 	u32 nDelays = 0;
917ccae7af2SMauro Carvalho Chehab 
918ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
919ccae7af2SMauro Carvalho Chehab 
920ccae7af2SMauro Carvalho Chehab 	/*  LO2 Lock bit was in a different place for B0 version  */
921ccae7af2SMauro Carvalho Chehab 	if (state->tuner_id == MT2063_B0)
922ccae7af2SMauro Carvalho Chehab 		LO2LK = 0x40;
923ccae7af2SMauro Carvalho Chehab 
924ccae7af2SMauro Carvalho Chehab 	do {
925ccae7af2SMauro Carvalho Chehab 		status = mt2063_read(state, MT2063_REG_LO_STATUS,
926ccae7af2SMauro Carvalho Chehab 				     &state->reg[MT2063_REG_LO_STATUS], 1);
927ccae7af2SMauro Carvalho Chehab 
928ccae7af2SMauro Carvalho Chehab 		if (status < 0)
929ccae7af2SMauro Carvalho Chehab 			return status;
930ccae7af2SMauro Carvalho Chehab 
931ccae7af2SMauro Carvalho Chehab 		if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) ==
932ccae7af2SMauro Carvalho Chehab 		    (LO1LK | LO2LK)) {
933ccae7af2SMauro Carvalho Chehab 			return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO;
934ccae7af2SMauro Carvalho Chehab 		}
935ccae7af2SMauro Carvalho Chehab 		msleep(nPollRate);	/*  Wait between retries  */
936ccae7af2SMauro Carvalho Chehab 	} while (++nDelays < nMaxLoops);
937ccae7af2SMauro Carvalho Chehab 
938ccae7af2SMauro Carvalho Chehab 	/*
939ccae7af2SMauro Carvalho Chehab 	 * Got no lock or partial lock
940ccae7af2SMauro Carvalho Chehab 	 */
941ccae7af2SMauro Carvalho Chehab 	return 0;
942ccae7af2SMauro Carvalho Chehab }
943ccae7af2SMauro Carvalho Chehab 
944ccae7af2SMauro Carvalho Chehab /*
945ccae7af2SMauro Carvalho Chehab  *  Constants for setting receiver modes.
946ccae7af2SMauro Carvalho Chehab  *  (6 modes defined at this time, enumerated by mt2063_delivery_sys)
947ccae7af2SMauro Carvalho Chehab  *  (DNC1GC & DNC2GC are the values, which are used, when the specific
948ccae7af2SMauro Carvalho Chehab  *   DNC Output is selected, the other is always off)
949ccae7af2SMauro Carvalho Chehab  *
950ccae7af2SMauro Carvalho Chehab  *                enum mt2063_delivery_sys
951ccae7af2SMauro Carvalho Chehab  * -------------+----------------------------------------------
952ccae7af2SMauro Carvalho Chehab  * Mode 0 :     | MT2063_CABLE_QAM
953ccae7af2SMauro Carvalho Chehab  * Mode 1 :     | MT2063_CABLE_ANALOG
954ccae7af2SMauro Carvalho Chehab  * Mode 2 :     | MT2063_OFFAIR_COFDM
955ccae7af2SMauro Carvalho Chehab  * Mode 3 :     | MT2063_OFFAIR_COFDM_SAWLESS
956ccae7af2SMauro Carvalho Chehab  * Mode 4 :     | MT2063_OFFAIR_ANALOG
957ccae7af2SMauro Carvalho Chehab  * Mode 5 :     | MT2063_OFFAIR_8VSB
958ccae7af2SMauro Carvalho Chehab  * --------------+----------------------------------------------
959ccae7af2SMauro Carvalho Chehab  *
960ccae7af2SMauro Carvalho Chehab  *                |<----------   Mode  -------------->|
961ccae7af2SMauro Carvalho Chehab  *    Reg Field   |  0  |  1  |  2  |  3  |  4  |  5  |
962ccae7af2SMauro Carvalho Chehab  *    ------------+-----+-----+-----+-----+-----+-----+
963ccae7af2SMauro Carvalho Chehab  *    RFAGCen     | OFF | OFF | OFF | OFF | OFF | OFF
964ccae7af2SMauro Carvalho Chehab  *    LNARin      |   0 |   0 |   3 |   3 |  3  |  3
965ccae7af2SMauro Carvalho Chehab  *    FIFFQen     |   1 |   1 |   1 |   1 |  1  |  1
966ccae7af2SMauro Carvalho Chehab  *    FIFFq       |   0 |   0 |   0 |   0 |  0  |  0
967ccae7af2SMauro Carvalho Chehab  *    DNC1gc      |   0 |   0 |   0 |   0 |  0  |  0
968ccae7af2SMauro Carvalho Chehab  *    DNC2gc      |   0 |   0 |   0 |   0 |  0  |  0
969ccae7af2SMauro Carvalho Chehab  *    GCU Auto    |   1 |   1 |   1 |   1 |  1  |  1
970ccae7af2SMauro Carvalho Chehab  *    LNA max Atn |  31 |  31 |  31 |  31 | 31  | 31
971ccae7af2SMauro Carvalho Chehab  *    LNA Target  |  44 |  43 |  43 |  43 | 43  | 43
972ccae7af2SMauro Carvalho Chehab  *    ign  RF Ovl |   0 |   0 |   0 |   0 |  0  |  0
973ccae7af2SMauro Carvalho Chehab  *    RF  max Atn |  31 |  31 |  31 |  31 | 31  | 31
974ccae7af2SMauro Carvalho Chehab  *    PD1 Target  |  36 |  36 |  38 |  38 | 36  | 38
975ccae7af2SMauro Carvalho Chehab  *    ign FIF Ovl |   0 |   0 |   0 |   0 |  0  |  0
976ccae7af2SMauro Carvalho Chehab  *    FIF max Atn |   5 |   5 |   5 |   5 |  5  |  5
977ccae7af2SMauro Carvalho Chehab  *    PD2 Target  |  40 |  33 |  42 |  42 | 33  | 42
978ccae7af2SMauro Carvalho Chehab  */
979ccae7af2SMauro Carvalho Chehab 
980ccae7af2SMauro Carvalho Chehab enum mt2063_delivery_sys {
981ccae7af2SMauro Carvalho Chehab 	MT2063_CABLE_QAM = 0,
982ccae7af2SMauro Carvalho Chehab 	MT2063_CABLE_ANALOG,
983ccae7af2SMauro Carvalho Chehab 	MT2063_OFFAIR_COFDM,
984ccae7af2SMauro Carvalho Chehab 	MT2063_OFFAIR_COFDM_SAWLESS,
985ccae7af2SMauro Carvalho Chehab 	MT2063_OFFAIR_ANALOG,
986ccae7af2SMauro Carvalho Chehab 	MT2063_OFFAIR_8VSB,
987ccae7af2SMauro Carvalho Chehab 	MT2063_NUM_RCVR_MODES
988ccae7af2SMauro Carvalho Chehab };
989ccae7af2SMauro Carvalho Chehab 
990ccae7af2SMauro Carvalho Chehab static const char *mt2063_mode_name[] = {
991ccae7af2SMauro Carvalho Chehab 	[MT2063_CABLE_QAM]		= "digital cable",
992ccae7af2SMauro Carvalho Chehab 	[MT2063_CABLE_ANALOG]		= "analog cable",
993ccae7af2SMauro Carvalho Chehab 	[MT2063_OFFAIR_COFDM]		= "digital offair",
994ccae7af2SMauro Carvalho Chehab 	[MT2063_OFFAIR_COFDM_SAWLESS]	= "digital offair without SAW",
995ccae7af2SMauro Carvalho Chehab 	[MT2063_OFFAIR_ANALOG]		= "analog offair",
996ccae7af2SMauro Carvalho Chehab 	[MT2063_OFFAIR_8VSB]		= "analog offair 8vsb",
997ccae7af2SMauro Carvalho Chehab };
998ccae7af2SMauro Carvalho Chehab 
999ccae7af2SMauro Carvalho Chehab static const u8 RFAGCEN[]	= {  0,  0,  0,  0,  0,  0 };
1000ccae7af2SMauro Carvalho Chehab static const u8 LNARIN[]	= {  0,  0,  3,  3,  3,  3 };
1001ccae7af2SMauro Carvalho Chehab static const u8 FIFFQEN[]	= {  1,  1,  1,  1,  1,  1 };
1002ccae7af2SMauro Carvalho Chehab static const u8 FIFFQ[]		= {  0,  0,  0,  0,  0,  0 };
1003ccae7af2SMauro Carvalho Chehab static const u8 DNC1GC[]	= {  0,  0,  0,  0,  0,  0 };
1004ccae7af2SMauro Carvalho Chehab static const u8 DNC2GC[]	= {  0,  0,  0,  0,  0,  0 };
1005ccae7af2SMauro Carvalho Chehab static const u8 ACLNAMAX[]	= { 31, 31, 31, 31, 31, 31 };
1006ccae7af2SMauro Carvalho Chehab static const u8 LNATGT[]	= { 44, 43, 43, 43, 43, 43 };
1007ccae7af2SMauro Carvalho Chehab static const u8 RFOVDIS[]	= {  0,  0,  0,  0,  0,  0 };
1008ccae7af2SMauro Carvalho Chehab static const u8 ACRFMAX[]	= { 31, 31, 31, 31, 31, 31 };
1009ccae7af2SMauro Carvalho Chehab static const u8 PD1TGT[]	= { 36, 36, 38, 38, 36, 38 };
1010ccae7af2SMauro Carvalho Chehab static const u8 FIFOVDIS[]	= {  0,  0,  0,  0,  0,  0 };
1011ccae7af2SMauro Carvalho Chehab static const u8 ACFIFMAX[]	= { 29, 29, 29, 29, 29, 29 };
1012ccae7af2SMauro Carvalho Chehab static const u8 PD2TGT[]	= { 40, 33, 38, 42, 30, 38 };
1013ccae7af2SMauro Carvalho Chehab 
1014ccae7af2SMauro Carvalho Chehab /*
1015ccae7af2SMauro Carvalho Chehab  * mt2063_set_dnc_output_enable()
1016ccae7af2SMauro Carvalho Chehab  */
mt2063_get_dnc_output_enable(struct mt2063_state * state,enum MT2063_DNC_Output_Enable * pValue)1017ccae7af2SMauro Carvalho Chehab static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state,
1018ccae7af2SMauro Carvalho Chehab 					enum MT2063_DNC_Output_Enable *pValue)
1019ccae7af2SMauro Carvalho Chehab {
1020ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
1021ccae7af2SMauro Carvalho Chehab 
1022ccae7af2SMauro Carvalho Chehab 	if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) {	/* if DNC1 is off */
1023ccae7af2SMauro Carvalho Chehab 		if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03)	/* if DNC2 is off */
1024ccae7af2SMauro Carvalho Chehab 			*pValue = MT2063_DNC_NONE;
1025ccae7af2SMauro Carvalho Chehab 		else
1026ccae7af2SMauro Carvalho Chehab 			*pValue = MT2063_DNC_2;
1027ccae7af2SMauro Carvalho Chehab 	} else {	/* DNC1 is on */
1028ccae7af2SMauro Carvalho Chehab 		if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03)	/* if DNC2 is off */
1029ccae7af2SMauro Carvalho Chehab 			*pValue = MT2063_DNC_1;
1030ccae7af2SMauro Carvalho Chehab 		else
1031ccae7af2SMauro Carvalho Chehab 			*pValue = MT2063_DNC_BOTH;
1032ccae7af2SMauro Carvalho Chehab 	}
1033ccae7af2SMauro Carvalho Chehab 	return 0;
1034ccae7af2SMauro Carvalho Chehab }
1035ccae7af2SMauro Carvalho Chehab 
1036ccae7af2SMauro Carvalho Chehab /*
1037ccae7af2SMauro Carvalho Chehab  * mt2063_set_dnc_output_enable()
1038ccae7af2SMauro Carvalho Chehab  */
mt2063_set_dnc_output_enable(struct mt2063_state * state,enum MT2063_DNC_Output_Enable nValue)1039ccae7af2SMauro Carvalho Chehab static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state,
1040ccae7af2SMauro Carvalho Chehab 					enum MT2063_DNC_Output_Enable nValue)
1041ccae7af2SMauro Carvalho Chehab {
104220eb13a7SMauro Carvalho Chehab 	int status = 0;	/* Status to be returned        */
1043ccae7af2SMauro Carvalho Chehab 	u8 val = 0;
1044ccae7af2SMauro Carvalho Chehab 
1045ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
1046ccae7af2SMauro Carvalho Chehab 
1047ccae7af2SMauro Carvalho Chehab 	/* selects, which DNC output is used */
1048ccae7af2SMauro Carvalho Chehab 	switch (nValue) {
1049ccae7af2SMauro Carvalho Chehab 	case MT2063_DNC_NONE:
1050ccae7af2SMauro Carvalho Chehab 		val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03;	/* Set DNC1GC=3 */
1051ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_DNC_GAIN] !=
1052ccae7af2SMauro Carvalho Chehab 		    val)
1053ccae7af2SMauro Carvalho Chehab 			status |=
1054ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state,
1055ccae7af2SMauro Carvalho Chehab 					  MT2063_REG_DNC_GAIN,
1056ccae7af2SMauro Carvalho Chehab 					  val);
1057ccae7af2SMauro Carvalho Chehab 
1058ccae7af2SMauro Carvalho Chehab 		val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03;	/* Set DNC2GC=3 */
1059ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_VGA_GAIN] !=
1060ccae7af2SMauro Carvalho Chehab 		    val)
1061ccae7af2SMauro Carvalho Chehab 			status |=
1062ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state,
1063ccae7af2SMauro Carvalho Chehab 					  MT2063_REG_VGA_GAIN,
1064ccae7af2SMauro Carvalho Chehab 					  val);
1065ccae7af2SMauro Carvalho Chehab 
1066ccae7af2SMauro Carvalho Chehab 		val = (state->reg[MT2063_REG_RSVD_20] & ~0x40);	/* Set PD2MUX=0 */
1067ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_RSVD_20] !=
1068ccae7af2SMauro Carvalho Chehab 		    val)
1069ccae7af2SMauro Carvalho Chehab 			status |=
1070ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state,
1071ccae7af2SMauro Carvalho Chehab 					  MT2063_REG_RSVD_20,
1072ccae7af2SMauro Carvalho Chehab 					  val);
1073ccae7af2SMauro Carvalho Chehab 
1074ccae7af2SMauro Carvalho Chehab 		break;
1075ccae7af2SMauro Carvalho Chehab 	case MT2063_DNC_1:
1076ccae7af2SMauro Carvalho Chehab 		val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03);	/* Set DNC1GC=x */
1077ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_DNC_GAIN] !=
1078ccae7af2SMauro Carvalho Chehab 		    val)
1079ccae7af2SMauro Carvalho Chehab 			status |=
1080ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state,
1081ccae7af2SMauro Carvalho Chehab 					  MT2063_REG_DNC_GAIN,
1082ccae7af2SMauro Carvalho Chehab 					  val);
1083ccae7af2SMauro Carvalho Chehab 
1084ccae7af2SMauro Carvalho Chehab 		val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03;	/* Set DNC2GC=3 */
1085ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_VGA_GAIN] !=
1086ccae7af2SMauro Carvalho Chehab 		    val)
1087ccae7af2SMauro Carvalho Chehab 			status |=
1088ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state,
1089ccae7af2SMauro Carvalho Chehab 					  MT2063_REG_VGA_GAIN,
1090ccae7af2SMauro Carvalho Chehab 					  val);
1091ccae7af2SMauro Carvalho Chehab 
1092ccae7af2SMauro Carvalho Chehab 		val = (state->reg[MT2063_REG_RSVD_20] & ~0x40);	/* Set PD2MUX=0 */
1093ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_RSVD_20] !=
1094ccae7af2SMauro Carvalho Chehab 		    val)
1095ccae7af2SMauro Carvalho Chehab 			status |=
1096ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state,
1097ccae7af2SMauro Carvalho Chehab 					  MT2063_REG_RSVD_20,
1098ccae7af2SMauro Carvalho Chehab 					  val);
1099ccae7af2SMauro Carvalho Chehab 
1100ccae7af2SMauro Carvalho Chehab 		break;
1101ccae7af2SMauro Carvalho Chehab 	case MT2063_DNC_2:
1102ccae7af2SMauro Carvalho Chehab 		val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03;	/* Set DNC1GC=3 */
1103ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_DNC_GAIN] !=
1104ccae7af2SMauro Carvalho Chehab 		    val)
1105ccae7af2SMauro Carvalho Chehab 			status |=
1106ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state,
1107ccae7af2SMauro Carvalho Chehab 					  MT2063_REG_DNC_GAIN,
1108ccae7af2SMauro Carvalho Chehab 					  val);
1109ccae7af2SMauro Carvalho Chehab 
1110ccae7af2SMauro Carvalho Chehab 		val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03);	/* Set DNC2GC=x */
1111ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_VGA_GAIN] !=
1112ccae7af2SMauro Carvalho Chehab 		    val)
1113ccae7af2SMauro Carvalho Chehab 			status |=
1114ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state,
1115ccae7af2SMauro Carvalho Chehab 					  MT2063_REG_VGA_GAIN,
1116ccae7af2SMauro Carvalho Chehab 					  val);
1117ccae7af2SMauro Carvalho Chehab 
1118ccae7af2SMauro Carvalho Chehab 		val = (state->reg[MT2063_REG_RSVD_20] | 0x40);	/* Set PD2MUX=1 */
1119ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_RSVD_20] !=
1120ccae7af2SMauro Carvalho Chehab 		    val)
1121ccae7af2SMauro Carvalho Chehab 			status |=
1122ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state,
1123ccae7af2SMauro Carvalho Chehab 					  MT2063_REG_RSVD_20,
1124ccae7af2SMauro Carvalho Chehab 					  val);
1125ccae7af2SMauro Carvalho Chehab 
1126ccae7af2SMauro Carvalho Chehab 		break;
1127ccae7af2SMauro Carvalho Chehab 	case MT2063_DNC_BOTH:
1128ccae7af2SMauro Carvalho Chehab 		val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03);	/* Set DNC1GC=x */
1129ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_DNC_GAIN] !=
1130ccae7af2SMauro Carvalho Chehab 		    val)
1131ccae7af2SMauro Carvalho Chehab 			status |=
1132ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state,
1133ccae7af2SMauro Carvalho Chehab 					  MT2063_REG_DNC_GAIN,
1134ccae7af2SMauro Carvalho Chehab 					  val);
1135ccae7af2SMauro Carvalho Chehab 
1136ccae7af2SMauro Carvalho Chehab 		val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03);	/* Set DNC2GC=x */
1137ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_VGA_GAIN] !=
1138ccae7af2SMauro Carvalho Chehab 		    val)
1139ccae7af2SMauro Carvalho Chehab 			status |=
1140ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state,
1141ccae7af2SMauro Carvalho Chehab 					  MT2063_REG_VGA_GAIN,
1142ccae7af2SMauro Carvalho Chehab 					  val);
1143ccae7af2SMauro Carvalho Chehab 
1144ccae7af2SMauro Carvalho Chehab 		val = (state->reg[MT2063_REG_RSVD_20] | 0x40);	/* Set PD2MUX=1 */
1145ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_RSVD_20] !=
1146ccae7af2SMauro Carvalho Chehab 		    val)
1147ccae7af2SMauro Carvalho Chehab 			status |=
1148ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state,
1149ccae7af2SMauro Carvalho Chehab 					  MT2063_REG_RSVD_20,
1150ccae7af2SMauro Carvalho Chehab 					  val);
1151ccae7af2SMauro Carvalho Chehab 
1152ccae7af2SMauro Carvalho Chehab 		break;
1153ccae7af2SMauro Carvalho Chehab 	default:
1154ccae7af2SMauro Carvalho Chehab 		break;
1155ccae7af2SMauro Carvalho Chehab 	}
1156ccae7af2SMauro Carvalho Chehab 
1157ccae7af2SMauro Carvalho Chehab 	return status;
1158ccae7af2SMauro Carvalho Chehab }
1159ccae7af2SMauro Carvalho Chehab 
1160ccae7af2SMauro Carvalho Chehab /*
1161ccae7af2SMauro Carvalho Chehab  * MT2063_SetReceiverMode() - Set the MT2063 receiver mode, according with
1162ccae7af2SMauro Carvalho Chehab  *			      the selected enum mt2063_delivery_sys type.
1163ccae7af2SMauro Carvalho Chehab  *
1164ccae7af2SMauro Carvalho Chehab  *  (DNC1GC & DNC2GC are the values, which are used, when the specific
1165ccae7af2SMauro Carvalho Chehab  *   DNC Output is selected, the other is always off)
1166ccae7af2SMauro Carvalho Chehab  *
1167ccae7af2SMauro Carvalho Chehab  * @state:	ptr to mt2063_state structure
116839c1cb2bSJonathan McCrohan  * @Mode:	desired receiver delivery system
1169ccae7af2SMauro Carvalho Chehab  *
1170ccae7af2SMauro Carvalho Chehab  * Note: Register cache must be valid for it to work
1171ccae7af2SMauro Carvalho Chehab  */
1172ccae7af2SMauro Carvalho Chehab 
MT2063_SetReceiverMode(struct mt2063_state * state,enum mt2063_delivery_sys Mode)1173ccae7af2SMauro Carvalho Chehab static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
1174ccae7af2SMauro Carvalho Chehab 				  enum mt2063_delivery_sys Mode)
1175ccae7af2SMauro Carvalho Chehab {
117620eb13a7SMauro Carvalho Chehab 	int status = 0;	/* Status to be returned        */
1177ccae7af2SMauro Carvalho Chehab 	u8 val;
1178ccae7af2SMauro Carvalho Chehab 	u32 longval;
1179ccae7af2SMauro Carvalho Chehab 
1180ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
1181ccae7af2SMauro Carvalho Chehab 
1182ccae7af2SMauro Carvalho Chehab 	if (Mode >= MT2063_NUM_RCVR_MODES)
1183ccae7af2SMauro Carvalho Chehab 		status = -ERANGE;
1184ccae7af2SMauro Carvalho Chehab 
1185ccae7af2SMauro Carvalho Chehab 	/* RFAGCen */
1186ccae7af2SMauro Carvalho Chehab 	if (status >= 0) {
1187ccae7af2SMauro Carvalho Chehab 		val =
1188ccae7af2SMauro Carvalho Chehab 		    (state->
1189fe10b84eSHans Verkuil 		     reg[MT2063_REG_PD1_TGT] & ~0x40) | (RFAGCEN[Mode]
1190ccae7af2SMauro Carvalho Chehab 								   ? 0x40 :
1191ccae7af2SMauro Carvalho Chehab 								   0x00);
1192ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_PD1_TGT] != val)
1193ccae7af2SMauro Carvalho Chehab 			status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
1194ccae7af2SMauro Carvalho Chehab 	}
1195ccae7af2SMauro Carvalho Chehab 
1196ccae7af2SMauro Carvalho Chehab 	/* LNARin */
1197ccae7af2SMauro Carvalho Chehab 	if (status >= 0) {
1198fe10b84eSHans Verkuil 		u8 val = (state->reg[MT2063_REG_CTRL_2C] & ~0x03) |
1199ccae7af2SMauro Carvalho Chehab 			 (LNARIN[Mode] & 0x03);
1200ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_CTRL_2C] != val)
1201ccae7af2SMauro Carvalho Chehab 			status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val);
1202ccae7af2SMauro Carvalho Chehab 	}
1203ccae7af2SMauro Carvalho Chehab 
1204ccae7af2SMauro Carvalho Chehab 	/* FIFFQEN and FIFFQ */
1205ccae7af2SMauro Carvalho Chehab 	if (status >= 0) {
1206ccae7af2SMauro Carvalho Chehab 		val =
1207ccae7af2SMauro Carvalho Chehab 		    (state->
1208fe10b84eSHans Verkuil 		     reg[MT2063_REG_FIFF_CTRL2] & ~0xF0) |
1209ccae7af2SMauro Carvalho Chehab 		    (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
1210ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_FIFF_CTRL2] != val) {
1211ccae7af2SMauro Carvalho Chehab 			status |=
1212ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val);
1213ccae7af2SMauro Carvalho Chehab 			/* trigger FIFF calibration, needed after changing FIFFQ */
1214ccae7af2SMauro Carvalho Chehab 			val =
1215fe10b84eSHans Verkuil 			    (state->reg[MT2063_REG_FIFF_CTRL] | 0x01);
1216ccae7af2SMauro Carvalho Chehab 			status |=
1217ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
1218ccae7af2SMauro Carvalho Chehab 			val =
1219ccae7af2SMauro Carvalho Chehab 			    (state->
1220fe10b84eSHans Verkuil 			     reg[MT2063_REG_FIFF_CTRL] & ~0x01);
1221ccae7af2SMauro Carvalho Chehab 			status |=
1222ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
1223ccae7af2SMauro Carvalho Chehab 		}
1224ccae7af2SMauro Carvalho Chehab 	}
1225ccae7af2SMauro Carvalho Chehab 
1226ccae7af2SMauro Carvalho Chehab 	/* DNC1GC & DNC2GC */
1227ccae7af2SMauro Carvalho Chehab 	status |= mt2063_get_dnc_output_enable(state, &longval);
1228ccae7af2SMauro Carvalho Chehab 	status |= mt2063_set_dnc_output_enable(state, longval);
1229ccae7af2SMauro Carvalho Chehab 
1230ccae7af2SMauro Carvalho Chehab 	/* acLNAmax */
1231ccae7af2SMauro Carvalho Chehab 	if (status >= 0) {
1232fe10b84eSHans Verkuil 		u8 val = (state->reg[MT2063_REG_LNA_OV] & ~0x1F) |
1233ccae7af2SMauro Carvalho Chehab 			 (ACLNAMAX[Mode] & 0x1F);
1234ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_LNA_OV] != val)
1235ccae7af2SMauro Carvalho Chehab 			status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val);
1236ccae7af2SMauro Carvalho Chehab 	}
1237ccae7af2SMauro Carvalho Chehab 
1238ccae7af2SMauro Carvalho Chehab 	/* LNATGT */
1239ccae7af2SMauro Carvalho Chehab 	if (status >= 0) {
1240fe10b84eSHans Verkuil 		u8 val = (state->reg[MT2063_REG_LNA_TGT] & ~0x3F) |
1241ccae7af2SMauro Carvalho Chehab 			 (LNATGT[Mode] & 0x3F);
1242ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_LNA_TGT] != val)
1243ccae7af2SMauro Carvalho Chehab 			status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
1244ccae7af2SMauro Carvalho Chehab 	}
1245ccae7af2SMauro Carvalho Chehab 
1246ccae7af2SMauro Carvalho Chehab 	/* ACRF */
1247ccae7af2SMauro Carvalho Chehab 	if (status >= 0) {
1248fe10b84eSHans Verkuil 		u8 val = (state->reg[MT2063_REG_RF_OV] & ~0x1F) |
1249ccae7af2SMauro Carvalho Chehab 			 (ACRFMAX[Mode] & 0x1F);
1250ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_RF_OV] != val)
1251ccae7af2SMauro Carvalho Chehab 			status |= mt2063_setreg(state, MT2063_REG_RF_OV, val);
1252ccae7af2SMauro Carvalho Chehab 	}
1253ccae7af2SMauro Carvalho Chehab 
1254ccae7af2SMauro Carvalho Chehab 	/* PD1TGT */
1255ccae7af2SMauro Carvalho Chehab 	if (status >= 0) {
1256fe10b84eSHans Verkuil 		u8 val = (state->reg[MT2063_REG_PD1_TGT] & ~0x3F) |
1257ccae7af2SMauro Carvalho Chehab 			 (PD1TGT[Mode] & 0x3F);
1258ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_PD1_TGT] != val)
1259ccae7af2SMauro Carvalho Chehab 			status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
1260ccae7af2SMauro Carvalho Chehab 	}
1261ccae7af2SMauro Carvalho Chehab 
1262ccae7af2SMauro Carvalho Chehab 	/* FIFATN */
1263ccae7af2SMauro Carvalho Chehab 	if (status >= 0) {
1264ccae7af2SMauro Carvalho Chehab 		u8 val = ACFIFMAX[Mode];
1265ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5)
1266ccae7af2SMauro Carvalho Chehab 			val = 5;
1267fe10b84eSHans Verkuil 		val = (state->reg[MT2063_REG_FIF_OV] & ~0x1F) |
1268ccae7af2SMauro Carvalho Chehab 		      (val & 0x1F);
1269ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_FIF_OV] != val)
1270ccae7af2SMauro Carvalho Chehab 			status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val);
1271ccae7af2SMauro Carvalho Chehab 	}
1272ccae7af2SMauro Carvalho Chehab 
1273ccae7af2SMauro Carvalho Chehab 	/* PD2TGT */
1274ccae7af2SMauro Carvalho Chehab 	if (status >= 0) {
1275fe10b84eSHans Verkuil 		u8 val = (state->reg[MT2063_REG_PD2_TGT] & ~0x3F) |
1276ccae7af2SMauro Carvalho Chehab 		    (PD2TGT[Mode] & 0x3F);
1277ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_PD2_TGT] != val)
1278ccae7af2SMauro Carvalho Chehab 			status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val);
1279ccae7af2SMauro Carvalho Chehab 	}
1280ccae7af2SMauro Carvalho Chehab 
1281ccae7af2SMauro Carvalho Chehab 	/* Ignore ATN Overload */
1282ccae7af2SMauro Carvalho Chehab 	if (status >= 0) {
1283fe10b84eSHans Verkuil 		val = (state->reg[MT2063_REG_LNA_TGT] & ~0x80) |
1284ccae7af2SMauro Carvalho Chehab 		      (RFOVDIS[Mode] ? 0x80 : 0x00);
1285ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_LNA_TGT] != val)
1286ccae7af2SMauro Carvalho Chehab 			status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
1287ccae7af2SMauro Carvalho Chehab 	}
1288ccae7af2SMauro Carvalho Chehab 
1289ccae7af2SMauro Carvalho Chehab 	/* Ignore FIF Overload */
1290ccae7af2SMauro Carvalho Chehab 	if (status >= 0) {
1291fe10b84eSHans Verkuil 		val = (state->reg[MT2063_REG_PD1_TGT] & ~0x80) |
1292ccae7af2SMauro Carvalho Chehab 		      (FIFOVDIS[Mode] ? 0x80 : 0x00);
1293ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_PD1_TGT] != val)
1294ccae7af2SMauro Carvalho Chehab 			status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
1295ccae7af2SMauro Carvalho Chehab 	}
1296ccae7af2SMauro Carvalho Chehab 
1297ccae7af2SMauro Carvalho Chehab 	if (status >= 0) {
1298ccae7af2SMauro Carvalho Chehab 		state->rcvr_mode = Mode;
1299ccae7af2SMauro Carvalho Chehab 		dprintk(1, "mt2063 mode changed to %s\n",
1300ccae7af2SMauro Carvalho Chehab 			mt2063_mode_name[state->rcvr_mode]);
1301ccae7af2SMauro Carvalho Chehab 	}
1302ccae7af2SMauro Carvalho Chehab 
1303ccae7af2SMauro Carvalho Chehab 	return status;
1304ccae7af2SMauro Carvalho Chehab }
1305ccae7af2SMauro Carvalho Chehab 
1306ccae7af2SMauro Carvalho Chehab /*
1307ccae7af2SMauro Carvalho Chehab  * MT2063_ClearPowerMaskBits () - Clears the power-down mask bits for various
1308ccae7af2SMauro Carvalho Chehab  *				  sections of the MT2063
1309ccae7af2SMauro Carvalho Chehab  *
1310ccae7af2SMauro Carvalho Chehab  * @Bits:		Mask bits to be cleared.
1311ccae7af2SMauro Carvalho Chehab  *
1312ccae7af2SMauro Carvalho Chehab  * See definition of MT2063_Mask_Bits type for description
1313ccae7af2SMauro Carvalho Chehab  * of each of the power bits.
1314ccae7af2SMauro Carvalho Chehab  */
MT2063_ClearPowerMaskBits(struct mt2063_state * state,enum MT2063_Mask_Bits Bits)1315ccae7af2SMauro Carvalho Chehab static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state,
1316ccae7af2SMauro Carvalho Chehab 				     enum MT2063_Mask_Bits Bits)
1317ccae7af2SMauro Carvalho Chehab {
131820eb13a7SMauro Carvalho Chehab 	int status = 0;
1319ccae7af2SMauro Carvalho Chehab 
1320ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
1321ccae7af2SMauro Carvalho Chehab 	Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD);	/* Only valid bits for this tuner */
1322ccae7af2SMauro Carvalho Chehab 	if ((Bits & 0xFF00) != 0) {
1323ccae7af2SMauro Carvalho Chehab 		state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8);
1324ccae7af2SMauro Carvalho Chehab 		status |=
1325ccae7af2SMauro Carvalho Chehab 		    mt2063_write(state,
1326ccae7af2SMauro Carvalho Chehab 				    MT2063_REG_PWR_2,
1327ccae7af2SMauro Carvalho Chehab 				    &state->reg[MT2063_REG_PWR_2], 1);
1328ccae7af2SMauro Carvalho Chehab 	}
1329ccae7af2SMauro Carvalho Chehab 	if ((Bits & 0xFF) != 0) {
1330ccae7af2SMauro Carvalho Chehab 		state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF);
1331ccae7af2SMauro Carvalho Chehab 		status |=
1332ccae7af2SMauro Carvalho Chehab 		    mt2063_write(state,
1333ccae7af2SMauro Carvalho Chehab 				    MT2063_REG_PWR_1,
1334ccae7af2SMauro Carvalho Chehab 				    &state->reg[MT2063_REG_PWR_1], 1);
1335ccae7af2SMauro Carvalho Chehab 	}
1336ccae7af2SMauro Carvalho Chehab 
1337ccae7af2SMauro Carvalho Chehab 	return status;
1338ccae7af2SMauro Carvalho Chehab }
1339ccae7af2SMauro Carvalho Chehab 
1340ccae7af2SMauro Carvalho Chehab /*
1341ccae7af2SMauro Carvalho Chehab  * MT2063_SoftwareShutdown() - Enables or disables software shutdown function.
1342ccae7af2SMauro Carvalho Chehab  *			       When Shutdown is 1, any section whose power
1343ccae7af2SMauro Carvalho Chehab  *			       mask is set will be shutdown.
1344ccae7af2SMauro Carvalho Chehab  */
MT2063_SoftwareShutdown(struct mt2063_state * state,u8 Shutdown)1345ccae7af2SMauro Carvalho Chehab static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown)
1346ccae7af2SMauro Carvalho Chehab {
134720eb13a7SMauro Carvalho Chehab 	int status;
1348ccae7af2SMauro Carvalho Chehab 
1349ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
1350ccae7af2SMauro Carvalho Chehab 	if (Shutdown == 1)
1351ccae7af2SMauro Carvalho Chehab 		state->reg[MT2063_REG_PWR_1] |= 0x04;
1352ccae7af2SMauro Carvalho Chehab 	else
1353ccae7af2SMauro Carvalho Chehab 		state->reg[MT2063_REG_PWR_1] &= ~0x04;
1354ccae7af2SMauro Carvalho Chehab 
1355ccae7af2SMauro Carvalho Chehab 	status = mt2063_write(state,
1356ccae7af2SMauro Carvalho Chehab 			    MT2063_REG_PWR_1,
1357ccae7af2SMauro Carvalho Chehab 			    &state->reg[MT2063_REG_PWR_1], 1);
1358ccae7af2SMauro Carvalho Chehab 
1359ccae7af2SMauro Carvalho Chehab 	if (Shutdown != 1) {
1360ccae7af2SMauro Carvalho Chehab 		state->reg[MT2063_REG_BYP_CTRL] =
1361ccae7af2SMauro Carvalho Chehab 		    (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40;
1362ccae7af2SMauro Carvalho Chehab 		status |=
1363ccae7af2SMauro Carvalho Chehab 		    mt2063_write(state,
1364ccae7af2SMauro Carvalho Chehab 				    MT2063_REG_BYP_CTRL,
1365ccae7af2SMauro Carvalho Chehab 				    &state->reg[MT2063_REG_BYP_CTRL],
1366ccae7af2SMauro Carvalho Chehab 				    1);
1367ccae7af2SMauro Carvalho Chehab 		state->reg[MT2063_REG_BYP_CTRL] =
1368ccae7af2SMauro Carvalho Chehab 		    (state->reg[MT2063_REG_BYP_CTRL] & 0x9F);
1369ccae7af2SMauro Carvalho Chehab 		status |=
1370ccae7af2SMauro Carvalho Chehab 		    mt2063_write(state,
1371ccae7af2SMauro Carvalho Chehab 				    MT2063_REG_BYP_CTRL,
1372ccae7af2SMauro Carvalho Chehab 				    &state->reg[MT2063_REG_BYP_CTRL],
1373ccae7af2SMauro Carvalho Chehab 				    1);
1374ccae7af2SMauro Carvalho Chehab 	}
1375ccae7af2SMauro Carvalho Chehab 
1376ccae7af2SMauro Carvalho Chehab 	return status;
1377ccae7af2SMauro Carvalho Chehab }
1378ccae7af2SMauro Carvalho Chehab 
MT2063_Round_fLO(u32 f_LO,u32 f_LO_Step,u32 f_ref)1379ccae7af2SMauro Carvalho Chehab static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref)
1380ccae7af2SMauro Carvalho Chehab {
1381ccae7af2SMauro Carvalho Chehab 	return f_ref * (f_LO / f_ref)
1382ccae7af2SMauro Carvalho Chehab 	    + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step);
1383ccae7af2SMauro Carvalho Chehab }
1384ccae7af2SMauro Carvalho Chehab 
1385ccae7af2SMauro Carvalho Chehab /**
1386*a4184b4fSHans Verkuil  * MT2063_fLO_FractionalTerm - Calculates the portion contributed by FracN / denom.
1387ccae7af2SMauro Carvalho Chehab  *                        This function preserves maximum precision without
1388ccae7af2SMauro Carvalho Chehab  *                        risk of overflow.  It accurately calculates
1389ccae7af2SMauro Carvalho Chehab  *                        f_ref * num / denom to within 1 HZ with fixed math.
1390ccae7af2SMauro Carvalho Chehab  *
139169a52ad3SMauro Carvalho Chehab  * @f_ref:	SRO frequency.
1392ccae7af2SMauro Carvalho Chehab  * @num:	Fractional portion of the multiplier
1393ccae7af2SMauro Carvalho Chehab  * @denom:	denominator portion of the ratio
1394ccae7af2SMauro Carvalho Chehab  *
1395ccae7af2SMauro Carvalho Chehab  * This calculation handles f_ref as two separate 14-bit fields.
1396ccae7af2SMauro Carvalho Chehab  * Therefore, a maximum value of 2^28-1 may safely be used for f_ref.
1397ccae7af2SMauro Carvalho Chehab  * This is the genesis of the magic number "14" and the magic mask value of
1398ccae7af2SMauro Carvalho Chehab  * 0x03FFF.
1399ccae7af2SMauro Carvalho Chehab  *
1400ccae7af2SMauro Carvalho Chehab  * This routine successfully handles denom values up to and including 2^18.
1401ccae7af2SMauro Carvalho Chehab  *  Returns:        f_ref * num / denom
1402ccae7af2SMauro Carvalho Chehab  */
MT2063_fLO_FractionalTerm(u32 f_ref,u32 num,u32 denom)1403ccae7af2SMauro Carvalho Chehab static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom)
1404ccae7af2SMauro Carvalho Chehab {
1405ccae7af2SMauro Carvalho Chehab 	u32 t1 = (f_ref >> 14) * num;
1406ccae7af2SMauro Carvalho Chehab 	u32 term1 = t1 / denom;
1407ccae7af2SMauro Carvalho Chehab 	u32 loss = t1 % denom;
1408ccae7af2SMauro Carvalho Chehab 	u32 term2 =
1409ccae7af2SMauro Carvalho Chehab 	    (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom;
1410ccae7af2SMauro Carvalho Chehab 	return (term1 << 14) + term2;
1411ccae7af2SMauro Carvalho Chehab }
1412ccae7af2SMauro Carvalho Chehab 
1413ccae7af2SMauro Carvalho Chehab /*
1414*a4184b4fSHans Verkuil  * MT2063_CalcLO1Mult - Calculates Integer divider value and the numerator
1415ccae7af2SMauro Carvalho Chehab  *                value for a FracN PLL.
1416ccae7af2SMauro Carvalho Chehab  *
1417ccae7af2SMauro Carvalho Chehab  *                This function assumes that the f_LO and f_Ref are
1418ccae7af2SMauro Carvalho Chehab  *                evenly divisible by f_LO_Step.
1419ccae7af2SMauro Carvalho Chehab  *
1420ccae7af2SMauro Carvalho Chehab  * @Div:	OUTPUT: Whole number portion of the multiplier
1421ccae7af2SMauro Carvalho Chehab  * @FracN:	OUTPUT: Fractional portion of the multiplier
1422ccae7af2SMauro Carvalho Chehab  * @f_LO:	desired LO frequency.
1423ccae7af2SMauro Carvalho Chehab  * @f_LO_Step:	Minimum step size for the LO (in Hz).
1424ccae7af2SMauro Carvalho Chehab  * @f_Ref:	SRO frequency.
1425ccae7af2SMauro Carvalho Chehab  * @f_Avoid:	Range of PLL frequencies to avoid near integer multiples
1426ccae7af2SMauro Carvalho Chehab  *		of f_Ref (in Hz).
1427ccae7af2SMauro Carvalho Chehab  *
1428ccae7af2SMauro Carvalho Chehab  * Returns:        Recalculated LO frequency.
1429ccae7af2SMauro Carvalho Chehab  */
MT2063_CalcLO1Mult(u32 * Div,u32 * FracN,u32 f_LO,u32 f_LO_Step,u32 f_Ref)1430ccae7af2SMauro Carvalho Chehab static u32 MT2063_CalcLO1Mult(u32 *Div,
1431ccae7af2SMauro Carvalho Chehab 			      u32 *FracN,
1432ccae7af2SMauro Carvalho Chehab 			      u32 f_LO,
1433ccae7af2SMauro Carvalho Chehab 			      u32 f_LO_Step, u32 f_Ref)
1434ccae7af2SMauro Carvalho Chehab {
1435ccae7af2SMauro Carvalho Chehab 	/*  Calculate the whole number portion of the divider */
1436ccae7af2SMauro Carvalho Chehab 	*Div = f_LO / f_Ref;
1437ccae7af2SMauro Carvalho Chehab 
1438ccae7af2SMauro Carvalho Chehab 	/*  Calculate the numerator value (round to nearest f_LO_Step) */
1439ccae7af2SMauro Carvalho Chehab 	*FracN =
1440ccae7af2SMauro Carvalho Chehab 	    (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
1441ccae7af2SMauro Carvalho Chehab 	     (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
1442ccae7af2SMauro Carvalho Chehab 
1443ccae7af2SMauro Carvalho Chehab 	return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64);
1444ccae7af2SMauro Carvalho Chehab }
1445ccae7af2SMauro Carvalho Chehab 
1446ccae7af2SMauro Carvalho Chehab /**
1447*a4184b4fSHans Verkuil  * MT2063_CalcLO2Mult - Calculates Integer divider value and the numerator
1448ccae7af2SMauro Carvalho Chehab  *                 value for a FracN PLL.
1449ccae7af2SMauro Carvalho Chehab  *
1450ccae7af2SMauro Carvalho Chehab  *                  This function assumes that the f_LO and f_Ref are
1451ccae7af2SMauro Carvalho Chehab  *                  evenly divisible by f_LO_Step.
1452ccae7af2SMauro Carvalho Chehab  *
1453ccae7af2SMauro Carvalho Chehab  * @Div:	OUTPUT: Whole number portion of the multiplier
1454ccae7af2SMauro Carvalho Chehab  * @FracN:	OUTPUT: Fractional portion of the multiplier
1455ccae7af2SMauro Carvalho Chehab  * @f_LO:	desired LO frequency.
1456ccae7af2SMauro Carvalho Chehab  * @f_LO_Step:	Minimum step size for the LO (in Hz).
1457ccae7af2SMauro Carvalho Chehab  * @f_Ref:	SRO frequency.
1458ccae7af2SMauro Carvalho Chehab  *
1459ccae7af2SMauro Carvalho Chehab  * Returns: Recalculated LO frequency.
1460ccae7af2SMauro Carvalho Chehab  */
MT2063_CalcLO2Mult(u32 * Div,u32 * FracN,u32 f_LO,u32 f_LO_Step,u32 f_Ref)1461ccae7af2SMauro Carvalho Chehab static u32 MT2063_CalcLO2Mult(u32 *Div,
1462ccae7af2SMauro Carvalho Chehab 			      u32 *FracN,
1463ccae7af2SMauro Carvalho Chehab 			      u32 f_LO,
1464ccae7af2SMauro Carvalho Chehab 			      u32 f_LO_Step, u32 f_Ref)
1465ccae7af2SMauro Carvalho Chehab {
1466ccae7af2SMauro Carvalho Chehab 	/*  Calculate the whole number portion of the divider */
1467ccae7af2SMauro Carvalho Chehab 	*Div = f_LO / f_Ref;
1468ccae7af2SMauro Carvalho Chehab 
1469ccae7af2SMauro Carvalho Chehab 	/*  Calculate the numerator value (round to nearest f_LO_Step) */
1470ccae7af2SMauro Carvalho Chehab 	*FracN =
1471ccae7af2SMauro Carvalho Chehab 	    (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
1472ccae7af2SMauro Carvalho Chehab 	     (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
1473ccae7af2SMauro Carvalho Chehab 
1474ccae7af2SMauro Carvalho Chehab 	return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN,
1475ccae7af2SMauro Carvalho Chehab 							    8191);
1476ccae7af2SMauro Carvalho Chehab }
1477ccae7af2SMauro Carvalho Chehab 
1478ccae7af2SMauro Carvalho Chehab /*
1479ccae7af2SMauro Carvalho Chehab  * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be
1480ccae7af2SMauro Carvalho Chehab  *			   used for a given input frequency.
1481ccae7af2SMauro Carvalho Chehab  *
1482ccae7af2SMauro Carvalho Chehab  * @state:	ptr to tuner data structure
1483ccae7af2SMauro Carvalho Chehab  * @f_in:	RF input center frequency (in Hz).
1484ccae7af2SMauro Carvalho Chehab  *
1485ccae7af2SMauro Carvalho Chehab  * Returns: ClearTune filter number (0-31)
1486ccae7af2SMauro Carvalho Chehab  */
FindClearTuneFilter(struct mt2063_state * state,u32 f_in)1487ccae7af2SMauro Carvalho Chehab static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in)
1488ccae7af2SMauro Carvalho Chehab {
1489ccae7af2SMauro Carvalho Chehab 	u32 RFBand;
1490ccae7af2SMauro Carvalho Chehab 	u32 idx;		/*  index loop                      */
1491ccae7af2SMauro Carvalho Chehab 
1492ccae7af2SMauro Carvalho Chehab 	/*
1493ccae7af2SMauro Carvalho Chehab 	 **  Find RF Band setting
1494ccae7af2SMauro Carvalho Chehab 	 */
1495ccae7af2SMauro Carvalho Chehab 	RFBand = 31;		/*  def when f_in > all    */
1496ccae7af2SMauro Carvalho Chehab 	for (idx = 0; idx < 31; ++idx) {
1497ccae7af2SMauro Carvalho Chehab 		if (state->CTFiltMax[idx] >= f_in) {
1498ccae7af2SMauro Carvalho Chehab 			RFBand = idx;
1499ccae7af2SMauro Carvalho Chehab 			break;
1500ccae7af2SMauro Carvalho Chehab 		}
1501ccae7af2SMauro Carvalho Chehab 	}
1502ccae7af2SMauro Carvalho Chehab 	return RFBand;
1503ccae7af2SMauro Carvalho Chehab }
1504ccae7af2SMauro Carvalho Chehab 
1505ccae7af2SMauro Carvalho Chehab /*
1506ccae7af2SMauro Carvalho Chehab  * MT2063_Tune() - Change the tuner's tuned frequency to RFin.
1507ccae7af2SMauro Carvalho Chehab  */
MT2063_Tune(struct mt2063_state * state,u32 f_in)1508ccae7af2SMauro Carvalho Chehab static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in)
1509ccae7af2SMauro Carvalho Chehab {				/* RF input center frequency   */
1510ccae7af2SMauro Carvalho Chehab 
151120eb13a7SMauro Carvalho Chehab 	int status = 0;
1512ccae7af2SMauro Carvalho Chehab 	u32 LO1;		/*  1st LO register value           */
1513ccae7af2SMauro Carvalho Chehab 	u32 Num1;		/*  Numerator for LO1 reg. value    */
1514ccae7af2SMauro Carvalho Chehab 	u32 f_IF1;		/*  1st IF requested                */
1515ccae7af2SMauro Carvalho Chehab 	u32 LO2;		/*  2nd LO register value           */
1516ccae7af2SMauro Carvalho Chehab 	u32 Num2;		/*  Numerator for LO2 reg. value    */
1517ccae7af2SMauro Carvalho Chehab 	u32 ofLO1, ofLO2;	/*  last time's LO frequencies      */
1518ccae7af2SMauro Carvalho Chehab 	u8 fiffc = 0x80;	/*  FIFF center freq from tuner     */
1519ccae7af2SMauro Carvalho Chehab 	u32 fiffof;		/*  Offset from FIFF center freq    */
1520ccae7af2SMauro Carvalho Chehab 	const u8 LO1LK = 0x80;	/*  Mask for LO1 Lock bit           */
1521ccae7af2SMauro Carvalho Chehab 	u8 LO2LK = 0x08;	/*  Mask for LO2 Lock bit           */
1522ccae7af2SMauro Carvalho Chehab 	u8 val;
1523ccae7af2SMauro Carvalho Chehab 	u32 RFBand;
1524ccae7af2SMauro Carvalho Chehab 
1525ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
1526ccae7af2SMauro Carvalho Chehab 	/*  Check the input and output frequency ranges                   */
1527ccae7af2SMauro Carvalho Chehab 	if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ))
1528ccae7af2SMauro Carvalho Chehab 		return -EINVAL;
1529ccae7af2SMauro Carvalho Chehab 
1530ccae7af2SMauro Carvalho Chehab 	if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ)
1531ccae7af2SMauro Carvalho Chehab 	    || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ))
1532ccae7af2SMauro Carvalho Chehab 		return -EINVAL;
1533ccae7af2SMauro Carvalho Chehab 
1534ccae7af2SMauro Carvalho Chehab 	/*
1535ccae7af2SMauro Carvalho Chehab 	 * Save original LO1 and LO2 register values
1536ccae7af2SMauro Carvalho Chehab 	 */
1537ccae7af2SMauro Carvalho Chehab 	ofLO1 = state->AS_Data.f_LO1;
1538ccae7af2SMauro Carvalho Chehab 	ofLO2 = state->AS_Data.f_LO2;
1539ccae7af2SMauro Carvalho Chehab 
1540ccae7af2SMauro Carvalho Chehab 	/*
1541ccae7af2SMauro Carvalho Chehab 	 * Find and set RF Band setting
1542ccae7af2SMauro Carvalho Chehab 	 */
1543ccae7af2SMauro Carvalho Chehab 	if (state->ctfilt_sw == 1) {
1544ccae7af2SMauro Carvalho Chehab 		val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08);
1545ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_CTUNE_CTRL] != val) {
1546ccae7af2SMauro Carvalho Chehab 			status |=
1547ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val);
1548ccae7af2SMauro Carvalho Chehab 		}
1549ccae7af2SMauro Carvalho Chehab 		val = state->reg[MT2063_REG_CTUNE_OV];
1550ccae7af2SMauro Carvalho Chehab 		RFBand = FindClearTuneFilter(state, f_in);
1551ccae7af2SMauro Carvalho Chehab 		state->reg[MT2063_REG_CTUNE_OV] =
1552ccae7af2SMauro Carvalho Chehab 		    (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F)
1553ccae7af2SMauro Carvalho Chehab 			      | RFBand);
1554ccae7af2SMauro Carvalho Chehab 		if (state->reg[MT2063_REG_CTUNE_OV] != val) {
1555ccae7af2SMauro Carvalho Chehab 			status |=
1556ccae7af2SMauro Carvalho Chehab 			    mt2063_setreg(state, MT2063_REG_CTUNE_OV, val);
1557ccae7af2SMauro Carvalho Chehab 		}
1558ccae7af2SMauro Carvalho Chehab 	}
1559ccae7af2SMauro Carvalho Chehab 
1560ccae7af2SMauro Carvalho Chehab 	/*
1561ccae7af2SMauro Carvalho Chehab 	 * Read the FIFF Center Frequency from the tuner
1562ccae7af2SMauro Carvalho Chehab 	 */
1563ccae7af2SMauro Carvalho Chehab 	if (status >= 0) {
1564ccae7af2SMauro Carvalho Chehab 		status |=
1565ccae7af2SMauro Carvalho Chehab 		    mt2063_read(state,
1566ccae7af2SMauro Carvalho Chehab 				   MT2063_REG_FIFFC,
1567ccae7af2SMauro Carvalho Chehab 				   &state->reg[MT2063_REG_FIFFC], 1);
1568ccae7af2SMauro Carvalho Chehab 		fiffc = state->reg[MT2063_REG_FIFFC];
1569ccae7af2SMauro Carvalho Chehab 	}
1570ccae7af2SMauro Carvalho Chehab 	/*
1571ccae7af2SMauro Carvalho Chehab 	 * Assign in the requested values
1572ccae7af2SMauro Carvalho Chehab 	 */
1573ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_in = f_in;
1574ccae7af2SMauro Carvalho Chehab 	/*  Request a 1st IF such that LO1 is on a step size */
1575ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_if1_Request =
1576ccae7af2SMauro Carvalho Chehab 	    MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in,
1577ccae7af2SMauro Carvalho Chehab 			     state->AS_Data.f_LO1_Step,
1578ccae7af2SMauro Carvalho Chehab 			     state->AS_Data.f_ref) - f_in;
1579ccae7af2SMauro Carvalho Chehab 
1580ccae7af2SMauro Carvalho Chehab 	/*
1581ccae7af2SMauro Carvalho Chehab 	 * Calculate frequency settings.  f_IF1_FREQ + f_in is the
1582ccae7af2SMauro Carvalho Chehab 	 * desired LO1 frequency
1583ccae7af2SMauro Carvalho Chehab 	 */
1584ccae7af2SMauro Carvalho Chehab 	MT2063_ResetExclZones(&state->AS_Data);
1585ccae7af2SMauro Carvalho Chehab 
1586ccae7af2SMauro Carvalho Chehab 	f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data);
1587ccae7af2SMauro Carvalho Chehab 
1588ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_LO1 =
1589ccae7af2SMauro Carvalho Chehab 	    MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step,
1590ccae7af2SMauro Carvalho Chehab 			     state->AS_Data.f_ref);
1591ccae7af2SMauro Carvalho Chehab 
1592ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_LO2 =
1593ccae7af2SMauro Carvalho Chehab 	    MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
1594ccae7af2SMauro Carvalho Chehab 			     state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
1595ccae7af2SMauro Carvalho Chehab 
1596ccae7af2SMauro Carvalho Chehab 	/*
1597ccae7af2SMauro Carvalho Chehab 	 * Check for any LO spurs in the output bandwidth and adjust
1598ccae7af2SMauro Carvalho Chehab 	 * the LO settings to avoid them if needed
1599ccae7af2SMauro Carvalho Chehab 	 */
1600ccae7af2SMauro Carvalho Chehab 	status |= MT2063_AvoidSpurs(&state->AS_Data);
1601ccae7af2SMauro Carvalho Chehab 	/*
1602ccae7af2SMauro Carvalho Chehab 	 * MT_AvoidSpurs spurs may have changed the LO1 & LO2 values.
1603ccae7af2SMauro Carvalho Chehab 	 * Recalculate the LO frequencies and the values to be placed
1604ccae7af2SMauro Carvalho Chehab 	 * in the tuning registers.
1605ccae7af2SMauro Carvalho Chehab 	 */
1606ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_LO1 =
1607ccae7af2SMauro Carvalho Chehab 	    MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1,
1608ccae7af2SMauro Carvalho Chehab 			       state->AS_Data.f_LO1_Step, state->AS_Data.f_ref);
1609ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_LO2 =
1610ccae7af2SMauro Carvalho Chehab 	    MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
1611ccae7af2SMauro Carvalho Chehab 			     state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
1612ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_LO2 =
1613ccae7af2SMauro Carvalho Chehab 	    MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2,
1614ccae7af2SMauro Carvalho Chehab 			       state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
1615ccae7af2SMauro Carvalho Chehab 
1616ccae7af2SMauro Carvalho Chehab 	/*
1617ccae7af2SMauro Carvalho Chehab 	 *  Check the upconverter and downconverter frequency ranges
1618ccae7af2SMauro Carvalho Chehab 	 */
1619ccae7af2SMauro Carvalho Chehab 	if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ)
1620ccae7af2SMauro Carvalho Chehab 	    || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ))
1621ccae7af2SMauro Carvalho Chehab 		status |= MT2063_UPC_RANGE;
1622ccae7af2SMauro Carvalho Chehab 	if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ)
1623ccae7af2SMauro Carvalho Chehab 	    || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ))
1624ccae7af2SMauro Carvalho Chehab 		status |= MT2063_DNC_RANGE;
1625ccae7af2SMauro Carvalho Chehab 	/*  LO2 Lock bit was in a different place for B0 version  */
1626ccae7af2SMauro Carvalho Chehab 	if (state->tuner_id == MT2063_B0)
1627ccae7af2SMauro Carvalho Chehab 		LO2LK = 0x40;
1628ccae7af2SMauro Carvalho Chehab 
1629ccae7af2SMauro Carvalho Chehab 	/*
1630ccae7af2SMauro Carvalho Chehab 	 *  If we have the same LO frequencies and we're already locked,
1631ccae7af2SMauro Carvalho Chehab 	 *  then skip re-programming the LO registers.
1632ccae7af2SMauro Carvalho Chehab 	 */
1633ccae7af2SMauro Carvalho Chehab 	if ((ofLO1 != state->AS_Data.f_LO1)
1634ccae7af2SMauro Carvalho Chehab 	    || (ofLO2 != state->AS_Data.f_LO2)
1635ccae7af2SMauro Carvalho Chehab 	    || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) !=
1636ccae7af2SMauro Carvalho Chehab 		(LO1LK | LO2LK))) {
1637ccae7af2SMauro Carvalho Chehab 		/*
1638ccae7af2SMauro Carvalho Chehab 		 * Calculate the FIFFOF register value
1639ccae7af2SMauro Carvalho Chehab 		 *
1640ccae7af2SMauro Carvalho Chehab 		 *           IF1_Actual
1641ccae7af2SMauro Carvalho Chehab 		 * FIFFOF = ------------ - 8 * FIFFC - 4992
1642ccae7af2SMauro Carvalho Chehab 		 *            f_ref/64
1643ccae7af2SMauro Carvalho Chehab 		 */
1644ccae7af2SMauro Carvalho Chehab 		fiffof =
1645ccae7af2SMauro Carvalho Chehab 		    (state->AS_Data.f_LO1 -
1646ccae7af2SMauro Carvalho Chehab 		     f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc -
1647ccae7af2SMauro Carvalho Chehab 		    4992;
1648ccae7af2SMauro Carvalho Chehab 		if (fiffof > 0xFF)
1649ccae7af2SMauro Carvalho Chehab 			fiffof = 0xFF;
1650ccae7af2SMauro Carvalho Chehab 
1651ccae7af2SMauro Carvalho Chehab 		/*
1652ccae7af2SMauro Carvalho Chehab 		 * Place all of the calculated values into the local tuner
1653ccae7af2SMauro Carvalho Chehab 		 * register fields.
1654ccae7af2SMauro Carvalho Chehab 		 */
1655ccae7af2SMauro Carvalho Chehab 		if (status >= 0) {
1656ccae7af2SMauro Carvalho Chehab 			state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF);	/* DIV1q */
1657ccae7af2SMauro Carvalho Chehab 			state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F);	/* NUM1q */
1658ccae7af2SMauro Carvalho Chehab 			state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1)	/* DIV2q */
1659ccae7af2SMauro Carvalho Chehab 								   |(Num2 >> 12));	/* NUM2q (hi) */
1660ccae7af2SMauro Carvalho Chehab 			state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4);	/* NUM2q (mid) */
1661ccae7af2SMauro Carvalho Chehab 			state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F));	/* NUM2q (lo) */
1662ccae7af2SMauro Carvalho Chehab 
1663ccae7af2SMauro Carvalho Chehab 			/*
1664ccae7af2SMauro Carvalho Chehab 			 * Now write out the computed register values
1665ccae7af2SMauro Carvalho Chehab 			 * IMPORTANT: There is a required order for writing
1666ccae7af2SMauro Carvalho Chehab 			 *            (0x05 must follow all the others).
1667ccae7af2SMauro Carvalho Chehab 			 */
1668ccae7af2SMauro Carvalho Chehab 			status |= mt2063_write(state, MT2063_REG_LO1CQ_1, &state->reg[MT2063_REG_LO1CQ_1], 5);	/* 0x01 - 0x05 */
1669ccae7af2SMauro Carvalho Chehab 			if (state->tuner_id == MT2063_B0) {
1670ccae7af2SMauro Carvalho Chehab 				/* Re-write the one-shot bits to trigger the tune operation */
1671ccae7af2SMauro Carvalho Chehab 				status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1);	/* 0x05 */
1672ccae7af2SMauro Carvalho Chehab 			}
1673ccae7af2SMauro Carvalho Chehab 			/* Write out the FIFF offset only if it's changing */
1674ccae7af2SMauro Carvalho Chehab 			if (state->reg[MT2063_REG_FIFF_OFFSET] !=
1675ccae7af2SMauro Carvalho Chehab 			    (u8) fiffof) {
1676ccae7af2SMauro Carvalho Chehab 				state->reg[MT2063_REG_FIFF_OFFSET] =
1677ccae7af2SMauro Carvalho Chehab 				    (u8) fiffof;
1678ccae7af2SMauro Carvalho Chehab 				status |=
1679ccae7af2SMauro Carvalho Chehab 				    mt2063_write(state,
1680ccae7af2SMauro Carvalho Chehab 						    MT2063_REG_FIFF_OFFSET,
1681ccae7af2SMauro Carvalho Chehab 						    &state->
1682ccae7af2SMauro Carvalho Chehab 						    reg[MT2063_REG_FIFF_OFFSET],
1683ccae7af2SMauro Carvalho Chehab 						    1);
1684ccae7af2SMauro Carvalho Chehab 			}
1685ccae7af2SMauro Carvalho Chehab 		}
1686ccae7af2SMauro Carvalho Chehab 
1687ccae7af2SMauro Carvalho Chehab 		/*
1688ccae7af2SMauro Carvalho Chehab 		 * Check for LO's locking
1689ccae7af2SMauro Carvalho Chehab 		 */
1690ccae7af2SMauro Carvalho Chehab 
1691ccae7af2SMauro Carvalho Chehab 		if (status < 0)
1692ccae7af2SMauro Carvalho Chehab 			return status;
1693ccae7af2SMauro Carvalho Chehab 
1694ccae7af2SMauro Carvalho Chehab 		status = mt2063_lockStatus(state);
1695ccae7af2SMauro Carvalho Chehab 		if (status < 0)
1696ccae7af2SMauro Carvalho Chehab 			return status;
1697ccae7af2SMauro Carvalho Chehab 		if (!status)
1698ccae7af2SMauro Carvalho Chehab 			return -EINVAL;		/* Couldn't lock */
1699ccae7af2SMauro Carvalho Chehab 
1700ccae7af2SMauro Carvalho Chehab 		/*
1701ccae7af2SMauro Carvalho Chehab 		 * If we locked OK, assign calculated data to mt2063_state structure
1702ccae7af2SMauro Carvalho Chehab 		 */
1703ccae7af2SMauro Carvalho Chehab 		state->f_IF1_actual = state->AS_Data.f_LO1 - f_in;
1704ccae7af2SMauro Carvalho Chehab 	}
1705ccae7af2SMauro Carvalho Chehab 
1706ccae7af2SMauro Carvalho Chehab 	return status;
1707ccae7af2SMauro Carvalho Chehab }
1708ccae7af2SMauro Carvalho Chehab 
1709ccae7af2SMauro Carvalho Chehab static const u8 MT2063B0_defaults[] = {
1710ccae7af2SMauro Carvalho Chehab 	/* Reg,  Value */
1711ccae7af2SMauro Carvalho Chehab 	0x19, 0x05,
1712ccae7af2SMauro Carvalho Chehab 	0x1B, 0x1D,
1713ccae7af2SMauro Carvalho Chehab 	0x1C, 0x1F,
1714ccae7af2SMauro Carvalho Chehab 	0x1D, 0x0F,
1715ccae7af2SMauro Carvalho Chehab 	0x1E, 0x3F,
1716ccae7af2SMauro Carvalho Chehab 	0x1F, 0x0F,
1717ccae7af2SMauro Carvalho Chehab 	0x20, 0x3F,
1718ccae7af2SMauro Carvalho Chehab 	0x22, 0x21,
1719ccae7af2SMauro Carvalho Chehab 	0x23, 0x3F,
1720ccae7af2SMauro Carvalho Chehab 	0x24, 0x20,
1721ccae7af2SMauro Carvalho Chehab 	0x25, 0x3F,
1722ccae7af2SMauro Carvalho Chehab 	0x27, 0xEE,
1723ccae7af2SMauro Carvalho Chehab 	0x2C, 0x27,	/*  bit at 0x20 is cleared below  */
1724ccae7af2SMauro Carvalho Chehab 	0x30, 0x03,
1725ccae7af2SMauro Carvalho Chehab 	0x2C, 0x07,	/*  bit at 0x20 is cleared here   */
1726ccae7af2SMauro Carvalho Chehab 	0x2D, 0x87,
1727ccae7af2SMauro Carvalho Chehab 	0x2E, 0xAA,
1728ccae7af2SMauro Carvalho Chehab 	0x28, 0xE1,	/*  Set the FIFCrst bit here      */
1729ccae7af2SMauro Carvalho Chehab 	0x28, 0xE0,	/*  Clear the FIFCrst bit here    */
1730ccae7af2SMauro Carvalho Chehab 	0x00
1731ccae7af2SMauro Carvalho Chehab };
1732ccae7af2SMauro Carvalho Chehab 
1733ccae7af2SMauro Carvalho Chehab /* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
1734ccae7af2SMauro Carvalho Chehab static const u8 MT2063B1_defaults[] = {
1735ccae7af2SMauro Carvalho Chehab 	/* Reg,  Value */
1736ccae7af2SMauro Carvalho Chehab 	0x05, 0xF0,
1737ccae7af2SMauro Carvalho Chehab 	0x11, 0x10,	/* New Enable AFCsd */
1738ccae7af2SMauro Carvalho Chehab 	0x19, 0x05,
1739ccae7af2SMauro Carvalho Chehab 	0x1A, 0x6C,
1740ccae7af2SMauro Carvalho Chehab 	0x1B, 0x24,
1741ccae7af2SMauro Carvalho Chehab 	0x1C, 0x28,
1742ccae7af2SMauro Carvalho Chehab 	0x1D, 0x8F,
1743ccae7af2SMauro Carvalho Chehab 	0x1E, 0x14,
1744ccae7af2SMauro Carvalho Chehab 	0x1F, 0x8F,
1745ccae7af2SMauro Carvalho Chehab 	0x20, 0x57,
1746ccae7af2SMauro Carvalho Chehab 	0x22, 0x21,	/* New - ver 1.03 */
1747ccae7af2SMauro Carvalho Chehab 	0x23, 0x3C,	/* New - ver 1.10 */
1748ccae7af2SMauro Carvalho Chehab 	0x24, 0x20,	/* New - ver 1.03 */
1749ccae7af2SMauro Carvalho Chehab 	0x2C, 0x24,	/*  bit at 0x20 is cleared below  */
1750ccae7af2SMauro Carvalho Chehab 	0x2D, 0x87,	/*  FIFFQ=0  */
1751ccae7af2SMauro Carvalho Chehab 	0x2F, 0xF3,
1752ccae7af2SMauro Carvalho Chehab 	0x30, 0x0C,	/* New - ver 1.11 */
1753ccae7af2SMauro Carvalho Chehab 	0x31, 0x1B,	/* New - ver 1.11 */
1754ccae7af2SMauro Carvalho Chehab 	0x2C, 0x04,	/*  bit at 0x20 is cleared here  */
1755ccae7af2SMauro Carvalho Chehab 	0x28, 0xE1,	/*  Set the FIFCrst bit here      */
1756ccae7af2SMauro Carvalho Chehab 	0x28, 0xE0,	/*  Clear the FIFCrst bit here    */
1757ccae7af2SMauro Carvalho Chehab 	0x00
1758ccae7af2SMauro Carvalho Chehab };
1759ccae7af2SMauro Carvalho Chehab 
1760ccae7af2SMauro Carvalho Chehab /* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
1761ccae7af2SMauro Carvalho Chehab static const u8 MT2063B3_defaults[] = {
1762ccae7af2SMauro Carvalho Chehab 	/* Reg,  Value */
1763ccae7af2SMauro Carvalho Chehab 	0x05, 0xF0,
1764ccae7af2SMauro Carvalho Chehab 	0x19, 0x3D,
1765ccae7af2SMauro Carvalho Chehab 	0x2C, 0x24,	/*  bit at 0x20 is cleared below  */
1766ccae7af2SMauro Carvalho Chehab 	0x2C, 0x04,	/*  bit at 0x20 is cleared here  */
1767ccae7af2SMauro Carvalho Chehab 	0x28, 0xE1,	/*  Set the FIFCrst bit here      */
1768ccae7af2SMauro Carvalho Chehab 	0x28, 0xE0,	/*  Clear the FIFCrst bit here    */
1769ccae7af2SMauro Carvalho Chehab 	0x00
1770ccae7af2SMauro Carvalho Chehab };
1771ccae7af2SMauro Carvalho Chehab 
mt2063_init(struct dvb_frontend * fe)1772ccae7af2SMauro Carvalho Chehab static int mt2063_init(struct dvb_frontend *fe)
1773ccae7af2SMauro Carvalho Chehab {
177420eb13a7SMauro Carvalho Chehab 	int status;
1775ccae7af2SMauro Carvalho Chehab 	struct mt2063_state *state = fe->tuner_priv;
1776ccae7af2SMauro Carvalho Chehab 	u8 all_resets = 0xF0;	/* reset/load bits */
1777ccae7af2SMauro Carvalho Chehab 	const u8 *def = NULL;
1778ccae7af2SMauro Carvalho Chehab 	char *step;
1779ccae7af2SMauro Carvalho Chehab 	u32 FCRUN;
1780ccae7af2SMauro Carvalho Chehab 	s32 maxReads;
1781ccae7af2SMauro Carvalho Chehab 	u32 fcu_osc;
1782ccae7af2SMauro Carvalho Chehab 	u32 i;
1783ccae7af2SMauro Carvalho Chehab 
1784ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
1785ccae7af2SMauro Carvalho Chehab 
1786ccae7af2SMauro Carvalho Chehab 	state->rcvr_mode = MT2063_CABLE_QAM;
1787ccae7af2SMauro Carvalho Chehab 
1788ccae7af2SMauro Carvalho Chehab 	/*  Read the Part/Rev code from the tuner */
1789ccae7af2SMauro Carvalho Chehab 	status = mt2063_read(state, MT2063_REG_PART_REV,
1790ccae7af2SMauro Carvalho Chehab 			     &state->reg[MT2063_REG_PART_REV], 1);
1791ccae7af2SMauro Carvalho Chehab 	if (status < 0) {
1792ccae7af2SMauro Carvalho Chehab 		printk(KERN_ERR "Can't read mt2063 part ID\n");
1793ccae7af2SMauro Carvalho Chehab 		return status;
1794ccae7af2SMauro Carvalho Chehab 	}
1795ccae7af2SMauro Carvalho Chehab 
1796ccae7af2SMauro Carvalho Chehab 	/* Check the part/rev code */
1797ccae7af2SMauro Carvalho Chehab 	switch (state->reg[MT2063_REG_PART_REV]) {
1798ccae7af2SMauro Carvalho Chehab 	case MT2063_B0:
1799ccae7af2SMauro Carvalho Chehab 		step = "B0";
1800ccae7af2SMauro Carvalho Chehab 		break;
1801ccae7af2SMauro Carvalho Chehab 	case MT2063_B1:
1802ccae7af2SMauro Carvalho Chehab 		step = "B1";
1803ccae7af2SMauro Carvalho Chehab 		break;
1804ccae7af2SMauro Carvalho Chehab 	case MT2063_B2:
1805ccae7af2SMauro Carvalho Chehab 		step = "B2";
1806ccae7af2SMauro Carvalho Chehab 		break;
1807ccae7af2SMauro Carvalho Chehab 	case MT2063_B3:
1808ccae7af2SMauro Carvalho Chehab 		step = "B3";
1809ccae7af2SMauro Carvalho Chehab 		break;
1810ccae7af2SMauro Carvalho Chehab 	default:
1811ccae7af2SMauro Carvalho Chehab 		printk(KERN_ERR "mt2063: Unknown mt2063 device ID (0x%02x)\n",
1812ccae7af2SMauro Carvalho Chehab 		       state->reg[MT2063_REG_PART_REV]);
1813ccae7af2SMauro Carvalho Chehab 		return -ENODEV;	/*  Wrong tuner Part/Rev code */
1814ccae7af2SMauro Carvalho Chehab 	}
1815ccae7af2SMauro Carvalho Chehab 
1816ccae7af2SMauro Carvalho Chehab 	/*  Check the 2nd byte of the Part/Rev code from the tuner */
1817ccae7af2SMauro Carvalho Chehab 	status = mt2063_read(state, MT2063_REG_RSVD_3B,
1818ccae7af2SMauro Carvalho Chehab 			     &state->reg[MT2063_REG_RSVD_3B], 1);
1819ccae7af2SMauro Carvalho Chehab 
1820ccae7af2SMauro Carvalho Chehab 	/* b7 != 0 ==> NOT MT2063 */
1821ccae7af2SMauro Carvalho Chehab 	if (status < 0 || ((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) {
1822ccae7af2SMauro Carvalho Chehab 		printk(KERN_ERR "mt2063: Unknown part ID (0x%02x%02x)\n",
1823ccae7af2SMauro Carvalho Chehab 		       state->reg[MT2063_REG_PART_REV],
1824ccae7af2SMauro Carvalho Chehab 		       state->reg[MT2063_REG_RSVD_3B]);
1825ccae7af2SMauro Carvalho Chehab 		return -ENODEV;	/*  Wrong tuner Part/Rev code */
1826ccae7af2SMauro Carvalho Chehab 	}
1827ccae7af2SMauro Carvalho Chehab 
1828ccae7af2SMauro Carvalho Chehab 	printk(KERN_INFO "mt2063: detected a mt2063 %s\n", step);
1829ccae7af2SMauro Carvalho Chehab 
1830ccae7af2SMauro Carvalho Chehab 	/*  Reset the tuner  */
1831ccae7af2SMauro Carvalho Chehab 	status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1);
1832ccae7af2SMauro Carvalho Chehab 	if (status < 0)
1833ccae7af2SMauro Carvalho Chehab 		return status;
1834ccae7af2SMauro Carvalho Chehab 
1835ccae7af2SMauro Carvalho Chehab 	/* change all of the default values that vary from the HW reset values */
1836ccae7af2SMauro Carvalho Chehab 	/*  def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */
1837ccae7af2SMauro Carvalho Chehab 	switch (state->reg[MT2063_REG_PART_REV]) {
1838ccae7af2SMauro Carvalho Chehab 	case MT2063_B3:
1839ccae7af2SMauro Carvalho Chehab 		def = MT2063B3_defaults;
1840ccae7af2SMauro Carvalho Chehab 		break;
1841ccae7af2SMauro Carvalho Chehab 
1842ccae7af2SMauro Carvalho Chehab 	case MT2063_B1:
1843ccae7af2SMauro Carvalho Chehab 		def = MT2063B1_defaults;
1844ccae7af2SMauro Carvalho Chehab 		break;
1845ccae7af2SMauro Carvalho Chehab 
1846ccae7af2SMauro Carvalho Chehab 	case MT2063_B0:
1847ccae7af2SMauro Carvalho Chehab 		def = MT2063B0_defaults;
1848ccae7af2SMauro Carvalho Chehab 		break;
1849ccae7af2SMauro Carvalho Chehab 
1850ccae7af2SMauro Carvalho Chehab 	default:
1851ccae7af2SMauro Carvalho Chehab 		return -ENODEV;
1852ccae7af2SMauro Carvalho Chehab 	}
1853ccae7af2SMauro Carvalho Chehab 
1854ccae7af2SMauro Carvalho Chehab 	while (status >= 0 && *def) {
1855ccae7af2SMauro Carvalho Chehab 		u8 reg = *def++;
1856ccae7af2SMauro Carvalho Chehab 		u8 val = *def++;
1857ccae7af2SMauro Carvalho Chehab 		status = mt2063_write(state, reg, &val, 1);
1858ccae7af2SMauro Carvalho Chehab 	}
1859ccae7af2SMauro Carvalho Chehab 	if (status < 0)
1860ccae7af2SMauro Carvalho Chehab 		return status;
1861ccae7af2SMauro Carvalho Chehab 
1862ccae7af2SMauro Carvalho Chehab 	/*  Wait for FIFF location to complete.  */
1863ccae7af2SMauro Carvalho Chehab 	FCRUN = 1;
1864ccae7af2SMauro Carvalho Chehab 	maxReads = 10;
1865ccae7af2SMauro Carvalho Chehab 	while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) {
1866ccae7af2SMauro Carvalho Chehab 		msleep(2);
1867ccae7af2SMauro Carvalho Chehab 		status = mt2063_read(state,
1868ccae7af2SMauro Carvalho Chehab 					 MT2063_REG_XO_STATUS,
1869ccae7af2SMauro Carvalho Chehab 					 &state->
1870ccae7af2SMauro Carvalho Chehab 					 reg[MT2063_REG_XO_STATUS], 1);
1871ccae7af2SMauro Carvalho Chehab 		FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6;
1872ccae7af2SMauro Carvalho Chehab 	}
1873ccae7af2SMauro Carvalho Chehab 
1874ccae7af2SMauro Carvalho Chehab 	if (FCRUN != 0 || status < 0)
1875ccae7af2SMauro Carvalho Chehab 		return -ENODEV;
1876ccae7af2SMauro Carvalho Chehab 
1877ccae7af2SMauro Carvalho Chehab 	status = mt2063_read(state,
1878ccae7af2SMauro Carvalho Chehab 			   MT2063_REG_FIFFC,
1879ccae7af2SMauro Carvalho Chehab 			   &state->reg[MT2063_REG_FIFFC], 1);
1880ccae7af2SMauro Carvalho Chehab 	if (status < 0)
1881ccae7af2SMauro Carvalho Chehab 		return status;
1882ccae7af2SMauro Carvalho Chehab 
1883ccae7af2SMauro Carvalho Chehab 	/* Read back all the registers from the tuner */
1884ccae7af2SMauro Carvalho Chehab 	status = mt2063_read(state,
1885ccae7af2SMauro Carvalho Chehab 				MT2063_REG_PART_REV,
1886ccae7af2SMauro Carvalho Chehab 				state->reg, MT2063_REG_END_REGS);
1887ccae7af2SMauro Carvalho Chehab 	if (status < 0)
1888ccae7af2SMauro Carvalho Chehab 		return status;
1889ccae7af2SMauro Carvalho Chehab 
1890ccae7af2SMauro Carvalho Chehab 	/*  Initialize the tuner state.  */
1891ccae7af2SMauro Carvalho Chehab 	state->tuner_id = state->reg[MT2063_REG_PART_REV];
1892ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_ref = MT2063_REF_FREQ;
1893ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) *
1894ccae7af2SMauro Carvalho Chehab 				      ((u32) state->reg[MT2063_REG_FIFFC] + 640);
1895ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_if1_bw = MT2063_IF1_BW;
1896ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_out = 43750000UL;
1897ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_out_bw = 6750000UL;
1898ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_zif_bw = MT2063_ZIF_BW;
1899ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64;
1900ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE;
1901ccae7af2SMauro Carvalho Chehab 	state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1;
1902ccae7af2SMauro Carvalho Chehab 	state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2;
1903ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP;
1904ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center;
1905ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_LO1 = 2181000000UL;
1906ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_LO2 = 1486249786UL;
1907ccae7af2SMauro Carvalho Chehab 	state->f_IF1_actual = state->AS_Data.f_if1_Center;
1908ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual;
1909ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID;
1910ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID;
1911ccae7af2SMauro Carvalho Chehab 	state->num_regs = MT2063_REG_END_REGS;
1912ccae7af2SMauro Carvalho Chehab 	state->AS_Data.avoidDECT = MT2063_AVOID_BOTH;
1913ccae7af2SMauro Carvalho Chehab 	state->ctfilt_sw = 0;
1914ccae7af2SMauro Carvalho Chehab 
1915ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[0] = 69230000;
1916ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[1] = 105770000;
1917ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[2] = 140350000;
1918ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[3] = 177110000;
1919ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[4] = 212860000;
1920ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[5] = 241130000;
1921ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[6] = 274370000;
1922ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[7] = 309820000;
1923ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[8] = 342450000;
1924ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[9] = 378870000;
1925ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[10] = 416210000;
1926ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[11] = 456500000;
1927ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[12] = 495790000;
1928ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[13] = 534530000;
1929ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[14] = 572610000;
1930ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[15] = 598970000;
1931ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[16] = 635910000;
1932ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[17] = 672130000;
1933ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[18] = 714840000;
1934ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[19] = 739660000;
1935ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[20] = 770410000;
1936ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[21] = 814660000;
1937ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[22] = 846950000;
1938ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[23] = 867820000;
1939ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[24] = 915980000;
1940ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[25] = 947450000;
1941ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[26] = 983110000;
1942ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[27] = 1021630000;
1943ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[28] = 1061870000;
1944ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[29] = 1098330000;
1945ccae7af2SMauro Carvalho Chehab 	state->CTFiltMax[30] = 1138990000;
1946ccae7af2SMauro Carvalho Chehab 
1947ccae7af2SMauro Carvalho Chehab 	/*
1948ccae7af2SMauro Carvalho Chehab 	 **   Fetch the FCU osc value and use it and the fRef value to
1949ccae7af2SMauro Carvalho Chehab 	 **   scale all of the Band Max values
1950ccae7af2SMauro Carvalho Chehab 	 */
1951ccae7af2SMauro Carvalho Chehab 
1952ccae7af2SMauro Carvalho Chehab 	state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A;
1953ccae7af2SMauro Carvalho Chehab 	status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
1954ccae7af2SMauro Carvalho Chehab 			      &state->reg[MT2063_REG_CTUNE_CTRL], 1);
1955ccae7af2SMauro Carvalho Chehab 	if (status < 0)
1956ccae7af2SMauro Carvalho Chehab 		return status;
1957ccae7af2SMauro Carvalho Chehab 
1958ccae7af2SMauro Carvalho Chehab 	/*  Read the ClearTune filter calibration value  */
1959ccae7af2SMauro Carvalho Chehab 	status = mt2063_read(state, MT2063_REG_FIFFC,
1960ccae7af2SMauro Carvalho Chehab 			     &state->reg[MT2063_REG_FIFFC], 1);
1961ccae7af2SMauro Carvalho Chehab 	if (status < 0)
1962ccae7af2SMauro Carvalho Chehab 		return status;
1963ccae7af2SMauro Carvalho Chehab 
1964ccae7af2SMauro Carvalho Chehab 	fcu_osc = state->reg[MT2063_REG_FIFFC];
1965ccae7af2SMauro Carvalho Chehab 
1966ccae7af2SMauro Carvalho Chehab 	state->reg[MT2063_REG_CTUNE_CTRL] = 0x00;
1967ccae7af2SMauro Carvalho Chehab 	status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
1968ccae7af2SMauro Carvalho Chehab 			      &state->reg[MT2063_REG_CTUNE_CTRL], 1);
1969ccae7af2SMauro Carvalho Chehab 	if (status < 0)
1970ccae7af2SMauro Carvalho Chehab 		return status;
1971ccae7af2SMauro Carvalho Chehab 
1972ccae7af2SMauro Carvalho Chehab 	/*  Adjust each of the values in the ClearTune filter cross-over table  */
1973ccae7af2SMauro Carvalho Chehab 	for (i = 0; i < 31; i++)
1974ccae7af2SMauro Carvalho Chehab 		state->CTFiltMax[i] = (state->CTFiltMax[i] / 768) * (fcu_osc + 640);
1975ccae7af2SMauro Carvalho Chehab 
1976ccae7af2SMauro Carvalho Chehab 	status = MT2063_SoftwareShutdown(state, 1);
1977ccae7af2SMauro Carvalho Chehab 	if (status < 0)
1978ccae7af2SMauro Carvalho Chehab 		return status;
1979ccae7af2SMauro Carvalho Chehab 	status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
1980ccae7af2SMauro Carvalho Chehab 	if (status < 0)
1981ccae7af2SMauro Carvalho Chehab 		return status;
1982ccae7af2SMauro Carvalho Chehab 
1983ccae7af2SMauro Carvalho Chehab 	state->init = true;
1984ccae7af2SMauro Carvalho Chehab 
1985ccae7af2SMauro Carvalho Chehab 	return 0;
1986ccae7af2SMauro Carvalho Chehab }
1987ccae7af2SMauro Carvalho Chehab 
mt2063_get_status(struct dvb_frontend * fe,u32 * tuner_status)1988ccae7af2SMauro Carvalho Chehab static int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status)
1989ccae7af2SMauro Carvalho Chehab {
1990ccae7af2SMauro Carvalho Chehab 	struct mt2063_state *state = fe->tuner_priv;
1991ccae7af2SMauro Carvalho Chehab 	int status;
1992ccae7af2SMauro Carvalho Chehab 
1993ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
1994ccae7af2SMauro Carvalho Chehab 
1995ccae7af2SMauro Carvalho Chehab 	if (!state->init)
1996ccae7af2SMauro Carvalho Chehab 		return -ENODEV;
1997ccae7af2SMauro Carvalho Chehab 
1998ccae7af2SMauro Carvalho Chehab 	*tuner_status = 0;
1999ccae7af2SMauro Carvalho Chehab 	status = mt2063_lockStatus(state);
2000ccae7af2SMauro Carvalho Chehab 	if (status < 0)
2001ccae7af2SMauro Carvalho Chehab 		return status;
2002ccae7af2SMauro Carvalho Chehab 	if (status)
2003ccae7af2SMauro Carvalho Chehab 		*tuner_status = TUNER_STATUS_LOCKED;
2004ccae7af2SMauro Carvalho Chehab 
2005ccae7af2SMauro Carvalho Chehab 	dprintk(1, "Tuner status: %d", *tuner_status);
2006ccae7af2SMauro Carvalho Chehab 
2007ccae7af2SMauro Carvalho Chehab 	return 0;
2008ccae7af2SMauro Carvalho Chehab }
2009ccae7af2SMauro Carvalho Chehab 
mt2063_release(struct dvb_frontend * fe)2010194ced7aSMax Kellermann static void mt2063_release(struct dvb_frontend *fe)
2011ccae7af2SMauro Carvalho Chehab {
2012ccae7af2SMauro Carvalho Chehab 	struct mt2063_state *state = fe->tuner_priv;
2013ccae7af2SMauro Carvalho Chehab 
2014ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
2015ccae7af2SMauro Carvalho Chehab 
2016ccae7af2SMauro Carvalho Chehab 	fe->tuner_priv = NULL;
2017ccae7af2SMauro Carvalho Chehab 	kfree(state);
2018ccae7af2SMauro Carvalho Chehab }
2019ccae7af2SMauro Carvalho Chehab 
mt2063_set_analog_params(struct dvb_frontend * fe,struct analog_parameters * params)2020ccae7af2SMauro Carvalho Chehab static int mt2063_set_analog_params(struct dvb_frontend *fe,
2021ccae7af2SMauro Carvalho Chehab 				    struct analog_parameters *params)
2022ccae7af2SMauro Carvalho Chehab {
2023ccae7af2SMauro Carvalho Chehab 	struct mt2063_state *state = fe->tuner_priv;
2024ccae7af2SMauro Carvalho Chehab 	s32 pict_car;
2025ccae7af2SMauro Carvalho Chehab 	s32 pict2chanb_vsb;
2026ccae7af2SMauro Carvalho Chehab 	s32 ch_bw;
2027ccae7af2SMauro Carvalho Chehab 	s32 if_mid;
2028ccae7af2SMauro Carvalho Chehab 	s32 rcvr_mode;
2029ccae7af2SMauro Carvalho Chehab 	int status;
2030ccae7af2SMauro Carvalho Chehab 
2031ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
2032ccae7af2SMauro Carvalho Chehab 
2033ccae7af2SMauro Carvalho Chehab 	if (!state->init) {
2034ccae7af2SMauro Carvalho Chehab 		status = mt2063_init(fe);
2035ccae7af2SMauro Carvalho Chehab 		if (status < 0)
2036ccae7af2SMauro Carvalho Chehab 			return status;
2037ccae7af2SMauro Carvalho Chehab 	}
2038ccae7af2SMauro Carvalho Chehab 
2039ccae7af2SMauro Carvalho Chehab 	switch (params->mode) {
2040ccae7af2SMauro Carvalho Chehab 	case V4L2_TUNER_RADIO:
2041ccae7af2SMauro Carvalho Chehab 		pict_car = 38900000;
2042ccae7af2SMauro Carvalho Chehab 		ch_bw = 8000000;
2043ccae7af2SMauro Carvalho Chehab 		pict2chanb_vsb = -(ch_bw / 2);
2044ccae7af2SMauro Carvalho Chehab 		rcvr_mode = MT2063_OFFAIR_ANALOG;
2045ccae7af2SMauro Carvalho Chehab 		break;
2046ccae7af2SMauro Carvalho Chehab 	case V4L2_TUNER_ANALOG_TV:
2047ccae7af2SMauro Carvalho Chehab 		rcvr_mode = MT2063_CABLE_ANALOG;
2048ccae7af2SMauro Carvalho Chehab 		if (params->std & ~V4L2_STD_MN) {
2049ccae7af2SMauro Carvalho Chehab 			pict_car = 38900000;
2050ccae7af2SMauro Carvalho Chehab 			ch_bw = 6000000;
2051ccae7af2SMauro Carvalho Chehab 			pict2chanb_vsb = -1250000;
2052ccae7af2SMauro Carvalho Chehab 		} else if (params->std & V4L2_STD_PAL_G) {
2053ccae7af2SMauro Carvalho Chehab 			pict_car = 38900000;
2054ccae7af2SMauro Carvalho Chehab 			ch_bw = 7000000;
2055ccae7af2SMauro Carvalho Chehab 			pict2chanb_vsb = -1250000;
2056ccae7af2SMauro Carvalho Chehab 		} else {		/* PAL/SECAM standards */
2057ccae7af2SMauro Carvalho Chehab 			pict_car = 38900000;
2058ccae7af2SMauro Carvalho Chehab 			ch_bw = 8000000;
2059ccae7af2SMauro Carvalho Chehab 			pict2chanb_vsb = -1250000;
2060ccae7af2SMauro Carvalho Chehab 		}
2061ccae7af2SMauro Carvalho Chehab 		break;
2062ccae7af2SMauro Carvalho Chehab 	default:
2063ccae7af2SMauro Carvalho Chehab 		return -EINVAL;
2064ccae7af2SMauro Carvalho Chehab 	}
2065ccae7af2SMauro Carvalho Chehab 	if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
2066ccae7af2SMauro Carvalho Chehab 
2067ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_LO2_Step = 125000;	/* FIXME: probably 5000 for FM */
2068ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_out = if_mid;
2069ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_out_bw = ch_bw + 750000;
2070ccae7af2SMauro Carvalho Chehab 	status = MT2063_SetReceiverMode(state, rcvr_mode);
2071ccae7af2SMauro Carvalho Chehab 	if (status < 0)
2072ccae7af2SMauro Carvalho Chehab 		return status;
2073ccae7af2SMauro Carvalho Chehab 
2074ccae7af2SMauro Carvalho Chehab 	dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n",
2075ccae7af2SMauro Carvalho Chehab 		params->frequency, ch_bw, pict2chanb_vsb);
2076ccae7af2SMauro Carvalho Chehab 
2077ccae7af2SMauro Carvalho Chehab 	status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2))));
2078ccae7af2SMauro Carvalho Chehab 	if (status < 0)
2079ccae7af2SMauro Carvalho Chehab 		return status;
2080ccae7af2SMauro Carvalho Chehab 
2081ccae7af2SMauro Carvalho Chehab 	state->frequency = params->frequency;
2082ccae7af2SMauro Carvalho Chehab 	return 0;
2083ccae7af2SMauro Carvalho Chehab }
2084ccae7af2SMauro Carvalho Chehab 
2085ccae7af2SMauro Carvalho Chehab /*
2086ccae7af2SMauro Carvalho Chehab  * As defined on EN 300 429, the DVB-C roll-off factor is 0.15.
208739c1cb2bSJonathan McCrohan  * So, the amount of the needed bandwidth is given by:
2088ccae7af2SMauro Carvalho Chehab  *	Bw = Symbol_rate * (1 + 0.15)
2089ccae7af2SMauro Carvalho Chehab  * As such, the maximum symbol rate supported by 6 MHz is given by:
2090ccae7af2SMauro Carvalho Chehab  *	max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
2091ccae7af2SMauro Carvalho Chehab  */
2092ccae7af2SMauro Carvalho Chehab #define MAX_SYMBOL_RATE_6MHz	5217391
2093ccae7af2SMauro Carvalho Chehab 
mt2063_set_params(struct dvb_frontend * fe)2094ccae7af2SMauro Carvalho Chehab static int mt2063_set_params(struct dvb_frontend *fe)
2095ccae7af2SMauro Carvalho Chehab {
2096ccae7af2SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
2097ccae7af2SMauro Carvalho Chehab 	struct mt2063_state *state = fe->tuner_priv;
2098ccae7af2SMauro Carvalho Chehab 	int status;
2099ccae7af2SMauro Carvalho Chehab 	s32 pict_car;
2100ccae7af2SMauro Carvalho Chehab 	s32 pict2chanb_vsb;
2101ccae7af2SMauro Carvalho Chehab 	s32 ch_bw;
2102ccae7af2SMauro Carvalho Chehab 	s32 if_mid;
2103ccae7af2SMauro Carvalho Chehab 	s32 rcvr_mode;
2104ccae7af2SMauro Carvalho Chehab 
2105ccae7af2SMauro Carvalho Chehab 	if (!state->init) {
2106ccae7af2SMauro Carvalho Chehab 		status = mt2063_init(fe);
2107ccae7af2SMauro Carvalho Chehab 		if (status < 0)
2108ccae7af2SMauro Carvalho Chehab 			return status;
2109ccae7af2SMauro Carvalho Chehab 	}
2110ccae7af2SMauro Carvalho Chehab 
2111ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
2112ccae7af2SMauro Carvalho Chehab 
2113ccae7af2SMauro Carvalho Chehab 	if (c->bandwidth_hz == 0)
2114ccae7af2SMauro Carvalho Chehab 		return -EINVAL;
2115ccae7af2SMauro Carvalho Chehab 	if (c->bandwidth_hz <= 6000000)
2116ccae7af2SMauro Carvalho Chehab 		ch_bw = 6000000;
2117ccae7af2SMauro Carvalho Chehab 	else if (c->bandwidth_hz <= 7000000)
2118ccae7af2SMauro Carvalho Chehab 		ch_bw = 7000000;
2119ccae7af2SMauro Carvalho Chehab 	else
2120ccae7af2SMauro Carvalho Chehab 		ch_bw = 8000000;
2121ccae7af2SMauro Carvalho Chehab 
2122ccae7af2SMauro Carvalho Chehab 	switch (c->delivery_system) {
2123ccae7af2SMauro Carvalho Chehab 	case SYS_DVBT:
2124ccae7af2SMauro Carvalho Chehab 		rcvr_mode = MT2063_OFFAIR_COFDM;
2125ccae7af2SMauro Carvalho Chehab 		pict_car = 36125000;
2126ccae7af2SMauro Carvalho Chehab 		pict2chanb_vsb = -(ch_bw / 2);
2127ccae7af2SMauro Carvalho Chehab 		break;
2128ccae7af2SMauro Carvalho Chehab 	case SYS_DVBC_ANNEX_A:
2129ccae7af2SMauro Carvalho Chehab 	case SYS_DVBC_ANNEX_C:
2130ccae7af2SMauro Carvalho Chehab 		rcvr_mode = MT2063_CABLE_QAM;
2131ccae7af2SMauro Carvalho Chehab 		pict_car = 36125000;
2132ccae7af2SMauro Carvalho Chehab 		pict2chanb_vsb = -(ch_bw / 2);
2133ccae7af2SMauro Carvalho Chehab 		break;
2134ccae7af2SMauro Carvalho Chehab 	default:
2135ccae7af2SMauro Carvalho Chehab 		return -EINVAL;
2136ccae7af2SMauro Carvalho Chehab 	}
2137ccae7af2SMauro Carvalho Chehab 	if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
2138ccae7af2SMauro Carvalho Chehab 
2139ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_LO2_Step = 125000;	/* FIXME: probably 5000 for FM */
2140ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_out = if_mid;
2141ccae7af2SMauro Carvalho Chehab 	state->AS_Data.f_out_bw = ch_bw + 750000;
2142ccae7af2SMauro Carvalho Chehab 	status = MT2063_SetReceiverMode(state, rcvr_mode);
2143ccae7af2SMauro Carvalho Chehab 	if (status < 0)
2144ccae7af2SMauro Carvalho Chehab 		return status;
2145ccae7af2SMauro Carvalho Chehab 
2146ccae7af2SMauro Carvalho Chehab 	dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n",
2147ccae7af2SMauro Carvalho Chehab 		c->frequency, ch_bw, pict2chanb_vsb);
2148ccae7af2SMauro Carvalho Chehab 
2149ccae7af2SMauro Carvalho Chehab 	status = MT2063_Tune(state, (c->frequency + (pict2chanb_vsb + (ch_bw / 2))));
2150ccae7af2SMauro Carvalho Chehab 
2151ccae7af2SMauro Carvalho Chehab 	if (status < 0)
2152ccae7af2SMauro Carvalho Chehab 		return status;
2153ccae7af2SMauro Carvalho Chehab 
2154ccae7af2SMauro Carvalho Chehab 	state->frequency = c->frequency;
2155ccae7af2SMauro Carvalho Chehab 	return 0;
2156ccae7af2SMauro Carvalho Chehab }
2157ccae7af2SMauro Carvalho Chehab 
mt2063_get_if_frequency(struct dvb_frontend * fe,u32 * freq)2158ccae7af2SMauro Carvalho Chehab static int mt2063_get_if_frequency(struct dvb_frontend *fe, u32 *freq)
2159ccae7af2SMauro Carvalho Chehab {
2160ccae7af2SMauro Carvalho Chehab 	struct mt2063_state *state = fe->tuner_priv;
2161ccae7af2SMauro Carvalho Chehab 
2162ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
2163ccae7af2SMauro Carvalho Chehab 
2164ccae7af2SMauro Carvalho Chehab 	if (!state->init)
2165ccae7af2SMauro Carvalho Chehab 		return -ENODEV;
2166ccae7af2SMauro Carvalho Chehab 
2167ccae7af2SMauro Carvalho Chehab 	*freq = state->AS_Data.f_out;
2168ccae7af2SMauro Carvalho Chehab 
2169ccae7af2SMauro Carvalho Chehab 	dprintk(1, "IF frequency: %d\n", *freq);
2170ccae7af2SMauro Carvalho Chehab 
2171ccae7af2SMauro Carvalho Chehab 	return 0;
2172ccae7af2SMauro Carvalho Chehab }
2173ccae7af2SMauro Carvalho Chehab 
mt2063_get_bandwidth(struct dvb_frontend * fe,u32 * bw)2174ccae7af2SMauro Carvalho Chehab static int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
2175ccae7af2SMauro Carvalho Chehab {
2176ccae7af2SMauro Carvalho Chehab 	struct mt2063_state *state = fe->tuner_priv;
2177ccae7af2SMauro Carvalho Chehab 
2178ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
2179ccae7af2SMauro Carvalho Chehab 
2180ccae7af2SMauro Carvalho Chehab 	if (!state->init)
2181ccae7af2SMauro Carvalho Chehab 		return -ENODEV;
2182ccae7af2SMauro Carvalho Chehab 
2183ccae7af2SMauro Carvalho Chehab 	*bw = state->AS_Data.f_out_bw - 750000;
2184ccae7af2SMauro Carvalho Chehab 
2185ccae7af2SMauro Carvalho Chehab 	dprintk(1, "bandwidth: %d\n", *bw);
2186ccae7af2SMauro Carvalho Chehab 
2187ccae7af2SMauro Carvalho Chehab 	return 0;
2188ccae7af2SMauro Carvalho Chehab }
2189ccae7af2SMauro Carvalho Chehab 
219096105144SJulia Lawall static const struct dvb_tuner_ops mt2063_ops = {
2191ccae7af2SMauro Carvalho Chehab 	.info = {
2192ccae7af2SMauro Carvalho Chehab 		 .name = "MT2063 Silicon Tuner",
2193a3f90c75SMauro Carvalho Chehab 		 .frequency_min_hz  =  45 * MHz,
2194a3f90c75SMauro Carvalho Chehab 		 .frequency_max_hz  = 865 * MHz,
2195ccae7af2SMauro Carvalho Chehab 	 },
2196ccae7af2SMauro Carvalho Chehab 
2197ccae7af2SMauro Carvalho Chehab 	.init = mt2063_init,
2198ccae7af2SMauro Carvalho Chehab 	.sleep = MT2063_Sleep,
2199ccae7af2SMauro Carvalho Chehab 	.get_status = mt2063_get_status,
2200ccae7af2SMauro Carvalho Chehab 	.set_analog_params = mt2063_set_analog_params,
2201ccae7af2SMauro Carvalho Chehab 	.set_params    = mt2063_set_params,
2202ccae7af2SMauro Carvalho Chehab 	.get_if_frequency = mt2063_get_if_frequency,
2203ccae7af2SMauro Carvalho Chehab 	.get_bandwidth = mt2063_get_bandwidth,
2204ccae7af2SMauro Carvalho Chehab 	.release = mt2063_release,
2205ccae7af2SMauro Carvalho Chehab };
2206ccae7af2SMauro Carvalho Chehab 
mt2063_attach(struct dvb_frontend * fe,struct mt2063_config * config,struct i2c_adapter * i2c)2207ccae7af2SMauro Carvalho Chehab struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
2208ccae7af2SMauro Carvalho Chehab 				   struct mt2063_config *config,
2209ccae7af2SMauro Carvalho Chehab 				   struct i2c_adapter *i2c)
2210ccae7af2SMauro Carvalho Chehab {
2211ccae7af2SMauro Carvalho Chehab 	struct mt2063_state *state = NULL;
2212ccae7af2SMauro Carvalho Chehab 
2213ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
2214ccae7af2SMauro Carvalho Chehab 
2215ccae7af2SMauro Carvalho Chehab 	state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL);
22166f0fdc49SPeter Senna Tschudin 	if (!state)
22176f0fdc49SPeter Senna Tschudin 		return NULL;
2218ccae7af2SMauro Carvalho Chehab 
2219ccae7af2SMauro Carvalho Chehab 	state->config = config;
2220ccae7af2SMauro Carvalho Chehab 	state->i2c = i2c;
2221ccae7af2SMauro Carvalho Chehab 	state->frontend = fe;
2222ccae7af2SMauro Carvalho Chehab 	state->reference = config->refclock / 1000;	/* kHz */
2223ccae7af2SMauro Carvalho Chehab 	fe->tuner_priv = state;
2224ccae7af2SMauro Carvalho Chehab 	fe->ops.tuner_ops = mt2063_ops;
2225ccae7af2SMauro Carvalho Chehab 
2226ccae7af2SMauro Carvalho Chehab 	printk(KERN_INFO "%s: Attaching MT2063\n", __func__);
2227ccae7af2SMauro Carvalho Chehab 	return fe;
2228ccae7af2SMauro Carvalho Chehab }
2229ccae7af2SMauro Carvalho Chehab EXPORT_SYMBOL_GPL(mt2063_attach);
2230ccae7af2SMauro Carvalho Chehab 
223120eb13a7SMauro Carvalho Chehab #if 0
2232ccae7af2SMauro Carvalho Chehab /*
2233ccae7af2SMauro Carvalho Chehab  * Ancillary routines visible outside mt2063
2234ccae7af2SMauro Carvalho Chehab  * FIXME: Remove them in favor of using standard tuner callbacks
2235ccae7af2SMauro Carvalho Chehab  */
223620eb13a7SMauro Carvalho Chehab static int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe)
2237ccae7af2SMauro Carvalho Chehab {
2238ccae7af2SMauro Carvalho Chehab 	struct mt2063_state *state = fe->tuner_priv;
2239ccae7af2SMauro Carvalho Chehab 	int err = 0;
2240ccae7af2SMauro Carvalho Chehab 
2241ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
2242ccae7af2SMauro Carvalho Chehab 
2243ccae7af2SMauro Carvalho Chehab 	err = MT2063_SoftwareShutdown(state, 1);
2244ccae7af2SMauro Carvalho Chehab 	if (err < 0)
2245ccae7af2SMauro Carvalho Chehab 		printk(KERN_ERR "%s: Couldn't shutdown\n", __func__);
2246ccae7af2SMauro Carvalho Chehab 
2247ccae7af2SMauro Carvalho Chehab 	return err;
2248ccae7af2SMauro Carvalho Chehab }
2249ccae7af2SMauro Carvalho Chehab 
225020eb13a7SMauro Carvalho Chehab static int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe)
2251ccae7af2SMauro Carvalho Chehab {
2252ccae7af2SMauro Carvalho Chehab 	struct mt2063_state *state = fe->tuner_priv;
2253ccae7af2SMauro Carvalho Chehab 	int err = 0;
2254ccae7af2SMauro Carvalho Chehab 
2255ccae7af2SMauro Carvalho Chehab 	dprintk(2, "\n");
2256ccae7af2SMauro Carvalho Chehab 
2257ccae7af2SMauro Carvalho Chehab 	err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
2258ccae7af2SMauro Carvalho Chehab 	if (err < 0)
2259ccae7af2SMauro Carvalho Chehab 		printk(KERN_ERR "%s: Invalid parameter\n", __func__);
2260ccae7af2SMauro Carvalho Chehab 
2261ccae7af2SMauro Carvalho Chehab 	return err;
2262ccae7af2SMauro Carvalho Chehab }
226320eb13a7SMauro Carvalho Chehab #endif
2264ccae7af2SMauro Carvalho Chehab 
226537e59f87SMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab");
2266ccae7af2SMauro Carvalho Chehab MODULE_DESCRIPTION("MT2063 Silicon tuner");
2267ccae7af2SMauro Carvalho Chehab MODULE_LICENSE("GPL");
2268