blob: 0f4bf96b61eb5c6fa8b00611f763f309a54ccda6 [file] [log] [blame]
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001#include <linux/init.h>
2#include <linux/kernel.h>
3#include <linux/module.h>
4#include <linux/string.h>
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03005
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03006#include "mt2063.h"
7
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03008static unsigned int verbose;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03009module_param(verbose, int, 0644);
10
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -030011/* positive error codes used internally */
Mauro Carvalho Chehab29a0a4f2011-07-20 23:44:10 -030012
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -030013/* Info: Unavoidable LO-related spur may be present in the output */
Mauro Carvalho Chehab29a0a4f2011-07-20 23:44:10 -030014#define MT2063_SPUR_PRESENT_ERR (0x00800000)
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030015
16/* Info: Mask of bits used for # of LO-related spurs that were avoided during tuning */
17#define MT2063_SPUR_CNT_MASK (0x001f0000)
18#define MT2063_SPUR_SHIFT (16)
19
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030020/* Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */
21#define MT2063_UPC_RANGE (0x04000000)
22
23/* Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */
24#define MT2063_DNC_RANGE (0x08000000)
25
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030026/*
27 * Constant defining the version of the following structure
28 * and therefore the API for this code.
29 *
30 * When compiling the tuner driver, the preprocessor will
31 * check against this version number to make sure that
32 * it matches the version that the tuner driver knows about.
33 */
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030034
35/* DECT Frequency Avoidance */
36#define MT2063_DECT_AVOID_US_FREQS 0x00000001
37
38#define MT2063_DECT_AVOID_EURO_FREQS 0x00000002
39
40#define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0)
41
42#define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0)
43
44enum MT2063_DECT_Avoid_Type {
45 MT2063_NO_DECT_AVOIDANCE = 0, /* Do not create DECT exclusion zones. */
46 MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS, /* Avoid US DECT frequencies. */
47 MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS, /* Avoid European DECT frequencies. */
48 MT2063_AVOID_BOTH /* Avoid both regions. Not typically used. */
49};
50
51#define MT2063_MAX_ZONES 48
52
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030053struct MT2063_ExclZone_t {
54 u32 min_;
55 u32 max_;
56 struct MT2063_ExclZone_t *next_;
57};
58
59/*
60 * Structure of data needed for Spur Avoidance
61 */
62struct MT2063_AvoidSpursData_t {
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030063 u32 f_ref;
64 u32 f_in;
65 u32 f_LO1;
66 u32 f_if1_Center;
67 u32 f_if1_Request;
68 u32 f_if1_bw;
69 u32 f_LO2;
70 u32 f_out;
71 u32 f_out_bw;
72 u32 f_LO1_Step;
73 u32 f_LO2_Step;
74 u32 f_LO1_FracN_Avoid;
75 u32 f_LO2_FracN_Avoid;
76 u32 f_zif_bw;
77 u32 f_min_LO_Separation;
78 u32 maxH1;
79 u32 maxH2;
80 enum MT2063_DECT_Avoid_Type avoidDECT;
81 u32 bSpurPresent;
82 u32 bSpurAvoided;
83 u32 nSpursFound;
84 u32 nZones;
85 struct MT2063_ExclZone_t *freeZones;
86 struct MT2063_ExclZone_t *usedZones;
87 struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES];
88};
89
90/*
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030091 * Parameter for function MT2063_SetPowerMask that specifies the power down
92 * of various sections of the MT2063.
93 */
94enum MT2063_Mask_Bits {
95 MT2063_REG_SD = 0x0040, /* Shutdown regulator */
96 MT2063_SRO_SD = 0x0020, /* Shutdown SRO */
97 MT2063_AFC_SD = 0x0010, /* Shutdown AFC A/D */
98 MT2063_PD_SD = 0x0002, /* Enable power detector shutdown */
99 MT2063_PDADC_SD = 0x0001, /* Enable power detector A/D shutdown */
100 MT2063_VCO_SD = 0x8000, /* Enable VCO shutdown */
101 MT2063_LTX_SD = 0x4000, /* Enable LTX shutdown */
102 MT2063_LT1_SD = 0x2000, /* Enable LT1 shutdown */
103 MT2063_LNA_SD = 0x1000, /* Enable LNA shutdown */
104 MT2063_UPC_SD = 0x0800, /* Enable upconverter shutdown */
105 MT2063_DNC_SD = 0x0400, /* Enable downconverter shutdown */
106 MT2063_VGA_SD = 0x0200, /* Enable VGA shutdown */
107 MT2063_AMP_SD = 0x0100, /* Enable AMP shutdown */
108 MT2063_ALL_SD = 0xFF73, /* All shutdown bits for this tuner */
109 MT2063_NONE_SD = 0x0000 /* No shutdown bits */
110};
111
112/*
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300113 * Parameter for selecting tuner mode
114 */
115enum MT2063_RCVR_MODES {
116 MT2063_CABLE_QAM = 0, /* Digital cable */
117 MT2063_CABLE_ANALOG, /* Analog cable */
118 MT2063_OFFAIR_COFDM, /* Digital offair */
119 MT2063_OFFAIR_COFDM_SAWLESS, /* Digital offair without SAW */
120 MT2063_OFFAIR_ANALOG, /* Analog offair */
121 MT2063_OFFAIR_8VSB, /* Analog offair */
122 MT2063_NUM_RCVR_MODES
123};
124
125/*
126 * Possible values for MT2063_DNC_OUTPUT
127 */
128enum MT2063_DNC_Output_Enable {
129 MT2063_DNC_NONE = 0,
130 MT2063_DNC_1,
131 MT2063_DNC_2,
132 MT2063_DNC_BOTH
133};
134
135/*
136** Two-wire serial bus subaddresses of the tuner registers.
137** Also known as the tuner's register addresses.
138*/
139enum MT2063_Register_Offsets {
140 MT2063_REG_PART_REV = 0, /* 0x00: Part/Rev Code */
141 MT2063_REG_LO1CQ_1, /* 0x01: LO1C Queued Byte 1 */
142 MT2063_REG_LO1CQ_2, /* 0x02: LO1C Queued Byte 2 */
143 MT2063_REG_LO2CQ_1, /* 0x03: LO2C Queued Byte 1 */
144 MT2063_REG_LO2CQ_2, /* 0x04: LO2C Queued Byte 2 */
145 MT2063_REG_LO2CQ_3, /* 0x05: LO2C Queued Byte 3 */
146 MT2063_REG_RSVD_06, /* 0x06: Reserved */
147 MT2063_REG_LO_STATUS, /* 0x07: LO Status */
148 MT2063_REG_FIFFC, /* 0x08: FIFF Center */
149 MT2063_REG_CLEARTUNE, /* 0x09: ClearTune Filter */
150 MT2063_REG_ADC_OUT, /* 0x0A: ADC_OUT */
151 MT2063_REG_LO1C_1, /* 0x0B: LO1C Byte 1 */
152 MT2063_REG_LO1C_2, /* 0x0C: LO1C Byte 2 */
153 MT2063_REG_LO2C_1, /* 0x0D: LO2C Byte 1 */
154 MT2063_REG_LO2C_2, /* 0x0E: LO2C Byte 2 */
155 MT2063_REG_LO2C_3, /* 0x0F: LO2C Byte 3 */
156 MT2063_REG_RSVD_10, /* 0x10: Reserved */
157 MT2063_REG_PWR_1, /* 0x11: PWR Byte 1 */
158 MT2063_REG_PWR_2, /* 0x12: PWR Byte 2 */
159 MT2063_REG_TEMP_STATUS, /* 0x13: Temp Status */
160 MT2063_REG_XO_STATUS, /* 0x14: Crystal Status */
161 MT2063_REG_RF_STATUS, /* 0x15: RF Attn Status */
162 MT2063_REG_FIF_STATUS, /* 0x16: FIF Attn Status */
163 MT2063_REG_LNA_OV, /* 0x17: LNA Attn Override */
164 MT2063_REG_RF_OV, /* 0x18: RF Attn Override */
165 MT2063_REG_FIF_OV, /* 0x19: FIF Attn Override */
166 MT2063_REG_LNA_TGT, /* 0x1A: Reserved */
167 MT2063_REG_PD1_TGT, /* 0x1B: Pwr Det 1 Target */
168 MT2063_REG_PD2_TGT, /* 0x1C: Pwr Det 2 Target */
169 MT2063_REG_RSVD_1D, /* 0x1D: Reserved */
170 MT2063_REG_RSVD_1E, /* 0x1E: Reserved */
171 MT2063_REG_RSVD_1F, /* 0x1F: Reserved */
172 MT2063_REG_RSVD_20, /* 0x20: Reserved */
173 MT2063_REG_BYP_CTRL, /* 0x21: Bypass Control */
174 MT2063_REG_RSVD_22, /* 0x22: Reserved */
175 MT2063_REG_RSVD_23, /* 0x23: Reserved */
176 MT2063_REG_RSVD_24, /* 0x24: Reserved */
177 MT2063_REG_RSVD_25, /* 0x25: Reserved */
178 MT2063_REG_RSVD_26, /* 0x26: Reserved */
179 MT2063_REG_RSVD_27, /* 0x27: Reserved */
180 MT2063_REG_FIFF_CTRL, /* 0x28: FIFF Control */
181 MT2063_REG_FIFF_OFFSET, /* 0x29: FIFF Offset */
182 MT2063_REG_CTUNE_CTRL, /* 0x2A: Reserved */
183 MT2063_REG_CTUNE_OV, /* 0x2B: Reserved */
184 MT2063_REG_CTRL_2C, /* 0x2C: Reserved */
185 MT2063_REG_FIFF_CTRL2, /* 0x2D: Fiff Control */
186 MT2063_REG_RSVD_2E, /* 0x2E: Reserved */
187 MT2063_REG_DNC_GAIN, /* 0x2F: DNC Control */
188 MT2063_REG_VGA_GAIN, /* 0x30: VGA Gain Ctrl */
189 MT2063_REG_RSVD_31, /* 0x31: Reserved */
190 MT2063_REG_TEMP_SEL, /* 0x32: Temperature Selection */
191 MT2063_REG_RSVD_33, /* 0x33: Reserved */
192 MT2063_REG_RSVD_34, /* 0x34: Reserved */
193 MT2063_REG_RSVD_35, /* 0x35: Reserved */
194 MT2063_REG_RSVD_36, /* 0x36: Reserved */
195 MT2063_REG_RSVD_37, /* 0x37: Reserved */
196 MT2063_REG_RSVD_38, /* 0x38: Reserved */
197 MT2063_REG_RSVD_39, /* 0x39: Reserved */
198 MT2063_REG_RSVD_3A, /* 0x3A: Reserved */
199 MT2063_REG_RSVD_3B, /* 0x3B: Reserved */
200 MT2063_REG_RSVD_3C, /* 0x3C: Reserved */
201 MT2063_REG_END_REGS
202};
203
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300204enum MTTune_atv_standard {
205 MTTUNEA_UNKNOWN = 0,
206 MTTUNEA_PAL_B,
207 MTTUNEA_PAL_G,
208 MTTUNEA_PAL_I,
209 MTTUNEA_PAL_L,
210 MTTUNEA_PAL_MN,
211 MTTUNEA_PAL_DK,
212 MTTUNEA_DIGITAL,
213 MTTUNEA_FMRADIO,
214 MTTUNEA_DVBC,
215 MTTUNEA_DVBT
216};
217
218
219struct mt2063_state {
220 struct i2c_adapter *i2c;
221
222 const struct mt2063_config *config;
223 struct dvb_tuner_ops ops;
224 struct dvb_frontend *frontend;
225 struct tuner_state status;
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300226
227 enum MTTune_atv_standard tv_type;
228 u32 frequency;
229 u32 srate;
230 u32 bandwidth;
231 u32 reference;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300232
233 u32 tuner_id;
234 struct MT2063_AvoidSpursData_t AS_Data;
235 u32 f_IF1_actual;
236 u32 rcvr_mode;
237 u32 ctfilt_sw;
238 u32 CTFiltMax[31];
239 u32 num_regs;
240 u8 reg[MT2063_REG_END_REGS];
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300241};
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300242
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300243/*
244 * mt2063_write - Write data into the I2C bus
245 */
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300246static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300247{
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300248 struct dvb_frontend *fe = state->frontend;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300249 int ret;
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300250 u8 buf[60];
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300251 struct i2c_msg msg = {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300252 .addr = state->config->tuner_address,
253 .flags = 0,
254 .buf = buf,
255 .len = len + 1
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300256 };
257
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300258 msg.buf[0] = reg;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300259 memcpy(msg.buf + 1, data, len);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300260
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300261 fe->ops.i2c_gate_ctrl(fe, 1);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300262 ret = i2c_transfer(state->i2c, &msg, 1);
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300263 fe->ops.i2c_gate_ctrl(fe, 0);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300264
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300265 if (ret < 0)
266 printk("mt2063_writeregs error ret=%d\n", ret);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300267
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300268 return ret;
269}
270
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300271/*
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300272 * mt2063_write - Write register data into the I2C bus, caching the value
273 */
274static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val)
275{
276 u32 status;
277
278 if (reg >= MT2063_REG_END_REGS)
279 return -ERANGE;
280
281 status = mt2063_write(state, reg, &val, 1);
282 if (status < 0)
283 return status;
284
285 state->reg[reg] = val;
286
287 return 0;
288}
289
290
291/*
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300292 * mt2063_read - Read data from the I2C bus
293 */
294static u32 mt2063_read(struct mt2063_state *state,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300295 u8 subAddress, u8 *pData, u32 cnt)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300296{
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300297 u32 status = 0; /* Status to be returned */
298 struct dvb_frontend *fe = state->frontend;
299 u32 i = 0;
300
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300301 fe->ops.i2c_gate_ctrl(fe, 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300302
303 for (i = 0; i < cnt; i++) {
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300304 int ret;
305 u8 b0[] = { subAddress + i };
306 struct i2c_msg msg[] = {
307 {
308 .addr = state->config->tuner_address,
309 .flags = I2C_M_RD,
310 .buf = b0,
311 .len = 1
312 }, {
313 .addr = state->config->tuner_address,
314 .flags = I2C_M_RD,
315 .buf = pData + 1,
316 .len = 1
317 }
318 };
319
320 ret = i2c_transfer(state->i2c, msg, 2);
321 if (ret < 0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300322 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300323 }
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300324 fe->ops.i2c_gate_ctrl(fe, 0);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300325 return (status);
326}
327
Mauro Carvalho Chehabe930b3a2011-07-21 03:02:16 -0300328/*
329 * FIXME: Is this really needed?
330 */
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300331static int MT2063_Sleep(struct dvb_frontend *fe)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300332{
333 /*
334 ** ToDo: Add code here to implement a OS blocking
335 ** for a period of "nMinDelayTime" milliseconds.
336 */
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300337 msleep(10);
338
339 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300340}
341
Mauro Carvalho Chehabe930b3a2011-07-21 03:02:16 -0300342/*
343 * Microtune spur avoidance
344 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300345
346/* Implement ceiling, floor functions. */
347#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300348#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300349
350struct MT2063_FIFZone_t {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300351 s32 min_;
352 s32 max_;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300353};
354
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300355static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t
356 *pAS_Info,
357 struct MT2063_ExclZone_t *pPrevNode)
358{
359 struct MT2063_ExclZone_t *pNode;
360 /* Check for a node in the free list */
361 if (pAS_Info->freeZones != NULL) {
362 /* Use one from the free list */
363 pNode = pAS_Info->freeZones;
364 pAS_Info->freeZones = pNode->next_;
365 } else {
366 /* Grab a node from the array */
367 pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones];
368 }
369
370 if (pPrevNode != NULL) {
371 pNode->next_ = pPrevNode->next_;
372 pPrevNode->next_ = pNode;
373 } else { /* insert at the beginning of the list */
374
375 pNode->next_ = pAS_Info->usedZones;
376 pAS_Info->usedZones = pNode;
377 }
378
379 pAS_Info->nZones++;
380 return pNode;
381}
382
383static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t
384 *pAS_Info,
385 struct MT2063_ExclZone_t *pPrevNode,
386 struct MT2063_ExclZone_t
387 *pNodeToRemove)
388{
389 struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_;
390
391 /* Make previous node point to the subsequent node */
392 if (pPrevNode != NULL)
393 pPrevNode->next_ = pNext;
394
395 /* Add pNodeToRemove to the beginning of the freeZones */
396 pNodeToRemove->next_ = pAS_Info->freeZones;
397 pAS_Info->freeZones = pNodeToRemove;
398
399 /* Decrement node count */
400 pAS_Info->nZones--;
401
402 return pNext;
403}
404
405/*****************************************************************************
406**
407** Name: MT_AddExclZone
408**
409** Description: Add (and merge) an exclusion zone into the list.
410** If the range (f_min, f_max) is totally outside the
411** 1st IF BW, ignore the entry.
412** If the range (f_min, f_max) is negative, ignore the entry.
413**
414** Revision History:
415**
416** SCR Date Author Description
417** -------------------------------------------------------------------------
418** 103 01-31-2005 DAD Ver 1.14: In MT_AddExclZone(), if the range
419** (f_min, f_max) < 0, ignore the entry.
420**
421*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300422static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300423 u32 f_min, u32 f_max)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300424{
425 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
426 struct MT2063_ExclZone_t *pPrev = NULL;
427 struct MT2063_ExclZone_t *pNext = NULL;
428
429 /* Check to see if this overlaps the 1st IF filter */
430 if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2)))
431 && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2)))
432 && (f_min < f_max)) {
433 /*
434 ** 1 2 3 4 5 6
435 **
436 ** New entry: |---| |--| |--| |-| |---| |--|
437 ** or or or or or
438 ** Existing: |--| |--| |--| |---| |-| |--|
439 */
440
441 /* Check for our place in the list */
442 while ((pNode != NULL) && (pNode->max_ < f_min)) {
443 pPrev = pNode;
444 pNode = pNode->next_;
445 }
446
447 if ((pNode != NULL) && (pNode->min_ < f_max)) {
448 /* Combine me with pNode */
449 if (f_min < pNode->min_)
450 pNode->min_ = f_min;
451 if (f_max > pNode->max_)
452 pNode->max_ = f_max;
453 } else {
454 pNode = InsertNode(pAS_Info, pPrev);
455 pNode->min_ = f_min;
456 pNode->max_ = f_max;
457 }
458
459 /* Look for merging possibilities */
460 pNext = pNode->next_;
461 while ((pNext != NULL) && (pNext->min_ < pNode->max_)) {
462 if (pNext->max_ > pNode->max_)
463 pNode->max_ = pNext->max_;
464 pNext = RemoveNode(pAS_Info, pNode, pNext); /* Remove pNext, return ptr to pNext->next */
465 }
466 }
467}
468
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300469/*
470** Reset all exclusion zones.
471** Add zones to protect the PLL FracN regions near zero
472**
473** N/A I 06-17-2008 RSK Ver 1.19: Refactoring avoidance of DECT
474** frequencies into MT_ResetExclZones().
475*/
476static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info)
477{
478 u32 center;
479
480 pAS_Info->nZones = 0; /* this clears the used list */
481 pAS_Info->usedZones = NULL; /* reset ptr */
482 pAS_Info->freeZones = NULL; /* reset ptr */
483
484 center =
485 pAS_Info->f_ref *
486 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 +
487 pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in;
488 while (center <
489 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
490 pAS_Info->f_LO1_FracN_Avoid) {
491 /* Exclude LO1 FracN */
492 MT2063_AddExclZone(pAS_Info,
493 center - pAS_Info->f_LO1_FracN_Avoid,
494 center - 1);
495 MT2063_AddExclZone(pAS_Info, center + 1,
496 center + pAS_Info->f_LO1_FracN_Avoid);
497 center += pAS_Info->f_ref;
498 }
499
500 center =
501 pAS_Info->f_ref *
502 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 -
503 pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out;
504 while (center <
505 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
506 pAS_Info->f_LO2_FracN_Avoid) {
507 /* Exclude LO2 FracN */
508 MT2063_AddExclZone(pAS_Info,
509 center - pAS_Info->f_LO2_FracN_Avoid,
510 center - 1);
511 MT2063_AddExclZone(pAS_Info, center + 1,
512 center + pAS_Info->f_LO2_FracN_Avoid);
513 center += pAS_Info->f_ref;
514 }
515
516 if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
517 /* Exclude LO1 values that conflict with DECT channels */
518 MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */
519 MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */
520 MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */
521 MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */
522 MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */
523 }
524
525 if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
526 MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */
527 MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */
528 MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */
529 MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */
530 MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */
531 MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */
532 MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */
533 MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */
534 MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */
535 MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */
536 }
537}
538
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300539/*****************************************************************************
540**
541** Name: MT_ChooseFirstIF
542**
543** Description: Choose the best available 1st IF
544** If f_Desired is not excluded, choose that first.
545** Otherwise, return the value closest to f_Center that is
546** not excluded
547**
548** Revision History:
549**
550** SCR Date Author Description
551** -------------------------------------------------------------------------
552** 117 03-29-2007 RSK Ver 1.15: Re-wrote to match search order from
553** tuner DLL.
554** 147 07-27-2007 RSK Ver 1.17: Corrected calculation (-) to (+)
555** Added logic to force f_Center within 1/2 f_Step.
556**
557*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300558static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300559{
560 /*
561 ** Update "f_Desired" to be the nearest "combinational-multiple" of "f_LO1_Step".
562 ** The resulting number, F_LO1 must be a multiple of f_LO1_Step. And F_LO1 is the arithmetic sum
563 ** of f_in + f_Center. Neither f_in, nor f_Center must be a multiple of f_LO1_Step.
564 ** However, the sum must be.
565 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300566 const u32 f_Desired =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300567 pAS_Info->f_LO1_Step *
568 ((pAS_Info->f_if1_Request + pAS_Info->f_in +
569 pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) -
570 pAS_Info->f_in;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300571 const u32 f_Step =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300572 (pAS_Info->f_LO1_Step >
573 pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info->
574 f_LO2_Step;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300575 u32 f_Center;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300576
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300577 s32 i;
578 s32 j = 0;
579 u32 bDesiredExcluded = 0;
580 u32 bZeroExcluded = 0;
581 s32 tmpMin, tmpMax;
582 s32 bestDiff;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300583 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
584 struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES];
585
586 if (pAS_Info->nZones == 0)
587 return f_Desired;
588
589 /* f_Center needs to be an integer multiple of f_Step away from f_Desired */
590 if (pAS_Info->f_if1_Center > f_Desired)
591 f_Center =
592 f_Desired +
593 f_Step *
594 ((pAS_Info->f_if1_Center - f_Desired +
595 f_Step / 2) / f_Step);
596 else
597 f_Center =
598 f_Desired -
599 f_Step *
600 ((f_Desired - pAS_Info->f_if1_Center +
601 f_Step / 2) / f_Step);
602
603 //assert;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300604 //if (!abs((s32) f_Center - (s32) pAS_Info->f_if1_Center) <= (s32) (f_Step/2))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300605 // return 0;
606
607 /* Take MT_ExclZones, center around f_Center and change the resolution to f_Step */
608 while (pNode != NULL) {
609 /* floor function */
610 tmpMin =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300611 floor((s32) (pNode->min_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300612
613 /* ceil function */
614 tmpMax =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300615 ceil((s32) (pNode->max_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300616
617 if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired))
618 bDesiredExcluded = 1;
619
620 if ((tmpMin < 0) && (tmpMax > 0))
621 bZeroExcluded = 1;
622
623 /* See if this zone overlaps the previous */
624 if ((j > 0) && (tmpMin < zones[j - 1].max_))
625 zones[j - 1].max_ = tmpMax;
626 else {
627 /* Add new zone */
628 //assert(j<MT2063_MAX_ZONES);
629 //if (j>=MT2063_MAX_ZONES)
630 //break;
631
632 zones[j].min_ = tmpMin;
633 zones[j].max_ = tmpMax;
634 j++;
635 }
636 pNode = pNode->next_;
637 }
638
639 /*
640 ** If the desired is okay, return with it
641 */
642 if (bDesiredExcluded == 0)
643 return f_Desired;
644
645 /*
646 ** If the desired is excluded and the center is okay, return with it
647 */
648 if (bZeroExcluded == 0)
649 return f_Center;
650
651 /* Find the value closest to 0 (f_Center) */
652 bestDiff = zones[0].min_;
653 for (i = 0; i < j; i++) {
654 if (abs(zones[i].min_) < abs(bestDiff))
655 bestDiff = zones[i].min_;
656 if (abs(zones[i].max_) < abs(bestDiff))
657 bestDiff = zones[i].max_;
658 }
659
660 if (bestDiff < 0)
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300661 return f_Center - ((u32) (-bestDiff) * f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300662
663 return f_Center + (bestDiff * f_Step);
664}
665
666/****************************************************************************
667**
668** Name: gcd
669**
670** Description: Uses Euclid's algorithm
671**
672** Parameters: u, v - unsigned values whose GCD is desired.
673**
674** Global: None
675**
676** Returns: greatest common divisor of u and v, if either value
677** is 0, the other value is returned as the result.
678**
679** Dependencies: None.
680**
681** Revision History:
682**
683** SCR Date Author Description
684** -------------------------------------------------------------------------
685** N/A 06-01-2004 JWS Original
686** N/A 08-03-2004 DAD Changed to Euclid's since it can handle
687** unsigned numbers.
688**
689****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300690static u32 MT2063_gcd(u32 u, u32 v)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300691{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300692 u32 r;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300693
694 while (v != 0) {
695 r = u % v;
696 u = v;
697 v = r;
698 }
699
700 return u;
701}
702
703/****************************************************************************
704**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300705** Name: IsSpurInBand
706**
707** Description: Checks to see if a spur will be present within the IF's
708** bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW)
709**
710** ma mb mc md
711** <--+-+-+-------------------+-------------------+-+-+-->
712** | ^ 0 ^ |
713** ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^
714** a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2
715**
716** Note that some equations are doubled to prevent round-off
717** problems when calculating fIFBW/2
718**
719** Parameters: pAS_Info - Avoid Spurs information block
720** fm - If spur, amount f_IF1 has to move negative
721** fp - If spur, amount f_IF1 has to move positive
722**
723** Global: None
724**
725** Returns: 1 if an LO spur would be present, otherwise 0.
726**
727** Dependencies: None.
728**
729** Revision History:
730**
731** SCR Date Author Description
732** -------------------------------------------------------------------------
733** N/A 11-28-2002 DAD Implemented algorithm from applied patent
734**
735****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300736static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info,
737 u32 * fm, u32 * fp)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300738{
739 /*
740 ** Calculate LO frequency settings.
741 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300742 u32 n, n0;
743 const u32 f_LO1 = pAS_Info->f_LO1;
744 const u32 f_LO2 = pAS_Info->f_LO2;
745 const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2;
746 const u32 c = d - pAS_Info->f_out_bw;
747 const u32 f = pAS_Info->f_zif_bw / 2;
Mauro Carvalho Chehabd0dcc2d2011-07-21 02:30:19 -0300748 const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300749 s32 f_nsLO1, f_nsLO2;
750 s32 f_Spur;
751 u32 ma, mb, mc, md, me, mf;
752 u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300753 *fm = 0;
754
755 /*
756 ** For each edge (d, c & f), calculate a scale, based on the gcd
757 ** of f_LO1, f_LO2 and the edge value. Use the larger of this
758 ** gcd-based scale factor or f_Scale.
759 */
760 lo_gcd = MT2063_gcd(f_LO1, f_LO2);
Mauro Carvalho Chehabfd1126c2011-07-21 03:30:57 -0300761 gd_Scale = max((u32) MT2063_gcd(lo_gcd, d), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300762 hgds = gd_Scale / 2;
Mauro Carvalho Chehabfd1126c2011-07-21 03:30:57 -0300763 gc_Scale = max((u32) MT2063_gcd(lo_gcd, c), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300764 hgcs = gc_Scale / 2;
Mauro Carvalho Chehabfd1126c2011-07-21 03:30:57 -0300765 gf_Scale = max((u32) MT2063_gcd(lo_gcd, f), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300766 hgfs = gf_Scale / 2;
767
Mauro Carvalho Chehabe930b3a2011-07-21 03:02:16 -0300768 n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300769
770 /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */
771 for (n = n0; n <= pAS_Info->maxH1; ++n) {
772 md = (n * ((f_LO1 + hgds) / gd_Scale) -
773 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
774
775 /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */
776 if (md >= pAS_Info->maxH1)
777 break;
778
779 ma = (n * ((f_LO1 + hgds) / gd_Scale) +
780 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
781
782 /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */
783 if (md == ma)
784 continue;
785
786 mc = (n * ((f_LO1 + hgcs) / gc_Scale) -
787 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
788 if (mc != md) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300789 f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale));
790 f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale));
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300791 f_Spur =
792 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
793 n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale);
794
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300795 *fp = ((f_Spur - (s32) c) / (mc - n)) + 1;
796 *fm = (((s32) d - f_Spur) / (mc - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300797 return 1;
798 }
799
800 /* Location of Zero-IF-spur to be checked */
801 me = (n * ((f_LO1 + hgfs) / gf_Scale) +
802 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
803 mf = (n * ((f_LO1 + hgfs) / gf_Scale) -
804 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
805 if (me != mf) {
806 f_nsLO1 = n * (f_LO1 / gf_Scale);
807 f_nsLO2 = me * (f_LO2 / gf_Scale);
808 f_Spur =
809 (gf_Scale * (f_nsLO1 - f_nsLO2)) +
810 n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale);
811
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300812 *fp = ((f_Spur + (s32) f) / (me - n)) + 1;
813 *fm = (((s32) f - f_Spur) / (me - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300814 return 1;
815 }
816
817 mb = (n * ((f_LO1 + hgcs) / gc_Scale) +
818 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
819 if (ma != mb) {
820 f_nsLO1 = n * (f_LO1 / gc_Scale);
821 f_nsLO2 = ma * (f_LO2 / gc_Scale);
822 f_Spur =
823 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
824 n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale);
825
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300826 *fp = (((s32) d + f_Spur) / (ma - n)) + 1;
827 *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300828 return 1;
829 }
830 }
831
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300832 /* No spurs found */
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300833 return 0;
834}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300835
836/*****************************************************************************
837**
838** Name: MT_AvoidSpurs
839**
840** Description: Main entry point to avoid spurs.
841** Checks for existing spurs in present LO1, LO2 freqs
842** and if present, chooses spur-free LO1, LO2 combination
843** that tunes the same input/output frequencies.
844**
845** Revision History:
846**
847** SCR Date Author Description
848** -------------------------------------------------------------------------
849** 096 04-06-2005 DAD Ver 1.11: Fix divide by 0 error if maxH==0.
850**
851*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300852static u32 MT2063_AvoidSpurs(void *h, struct MT2063_AvoidSpursData_t * pAS_Info)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300853{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300854 u32 status = 0;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300855 u32 fm, fp; /* restricted range on LO's */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300856 pAS_Info->bSpurAvoided = 0;
857 pAS_Info->nSpursFound = 0;
858
859 if (pAS_Info->maxH1 == 0)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300860 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300861
862 /*
863 ** Avoid LO Generated Spurs
864 **
865 ** Make sure that have no LO-related spurs within the IF output
866 ** bandwidth.
867 **
868 ** If there is an LO spur in this band, start at the current IF1 frequency
869 ** and work out until we find a spur-free frequency or run up against the
870 ** 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they
871 ** will be unchanged if a spur-free setting is not found.
872 */
873 pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
874 if (pAS_Info->bSpurPresent) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300875 u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */
876 u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */
877 u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */
878 u32 delta_IF1;
879 u32 new_IF1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300880
881 /*
882 ** Spur was found, attempt to find a spur-free 1st IF
883 */
884 do {
885 pAS_Info->nSpursFound++;
886
887 /* Raise f_IF1_upper, if needed */
888 MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp);
889
890 /* Choose next IF1 that is closest to f_IF1_CENTER */
891 new_IF1 = MT2063_ChooseFirstIF(pAS_Info);
892
893 if (new_IF1 > zfIF1) {
894 pAS_Info->f_LO1 += (new_IF1 - zfIF1);
895 pAS_Info->f_LO2 += (new_IF1 - zfIF1);
896 } else {
897 pAS_Info->f_LO1 -= (zfIF1 - new_IF1);
898 pAS_Info->f_LO2 -= (zfIF1 - new_IF1);
899 }
900 zfIF1 = new_IF1;
901
902 if (zfIF1 > pAS_Info->f_if1_Center)
903 delta_IF1 = zfIF1 - pAS_Info->f_if1_Center;
904 else
905 delta_IF1 = pAS_Info->f_if1_Center - zfIF1;
906 }
907 /*
908 ** Continue while the new 1st IF is still within the 1st IF bandwidth
909 ** and there is a spur in the band (again)
910 */
911 while ((2 * delta_IF1 + pAS_Info->f_out_bw <=
912 pAS_Info->f_if1_bw)
913 && (pAS_Info->bSpurPresent =
914 IsSpurInBand(pAS_Info, &fm, &fp)));
915
916 /*
917 ** Use the LO-spur free values found. If the search went all the way to
918 ** the 1st IF band edge and always found spurs, just leave the original
919 ** choice. It's as "good" as any other.
920 */
921 if (pAS_Info->bSpurPresent == 1) {
922 status |= MT2063_SPUR_PRESENT_ERR;
923 pAS_Info->f_LO1 = zfLO1;
924 pAS_Info->f_LO2 = zfLO2;
925 } else
926 pAS_Info->bSpurAvoided = 1;
927 }
928
929 status |=
930 ((pAS_Info->
931 nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK);
932
933 return (status);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300934}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300935
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300936/*
937** The expected version of MT_AvoidSpursData_t
938** If the version is different, an updated file is needed from Microtune
939*/
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300940
941typedef enum {
942 MT2063_SET_ATTEN,
943 MT2063_INCR_ATTEN,
944 MT2063_DECR_ATTEN
945} MT2063_ATTEN_CNTL_MODE;
946
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300947/*
Mauro Carvalho Chehab66aea302011-07-21 03:57:10 -0300948 * Constants used by the tuning algorithm
949 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300950#define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */
951#define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */
952#define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */
953#define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */
954#define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */
955#define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */
956#define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */
957#define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */
958#define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */
959#define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */
960#define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */
961#define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */
962#define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */
963#define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */
964#define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */
965#define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */
966#define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */
967#define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */
968
969/*
970** Define the supported Part/Rev codes for the MT2063
971*/
972#define MT2063_B0 (0x9B)
973#define MT2063_B1 (0x9C)
974#define MT2063_B2 (0x9D)
975#define MT2063_B3 (0x9E)
976
977/*
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300978** Constants for setting receiver modes.
979** (6 modes defined at this time, enumerated by MT2063_RCVR_MODES)
980** (DNC1GC & DNC2GC are the values, which are used, when the specific
981** DNC Output is selected, the other is always off)
982**
983** If PAL-L or L' is received, set:
984** MT2063_SetParam(hMT2063,MT2063_TAGC,1);
985**
986** --------------+----------------------------------------------
987** Mode 0 : | MT2063_CABLE_QAM
988** Mode 1 : | MT2063_CABLE_ANALOG
989** Mode 2 : | MT2063_OFFAIR_COFDM
990** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
991** Mode 4 : | MT2063_OFFAIR_ANALOG
992** Mode 5 : | MT2063_OFFAIR_8VSB
993** --------------+----+----+----+----+-----+-----+--------------
994** Mode | 0 | 1 | 2 | 3 | 4 | 5 |
995** --------------+----+----+----+----+-----+-----+
996**
997**
998*/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300999static const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 };
1000static const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 };
1001static const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 };
1002static const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 };
1003static const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 };
1004static const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 };
1005static const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 };
1006static const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 };
1007static const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
1008static const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 };
1009static const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 };
1010static const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
1011static const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 };
1012static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 };
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001013
1014/*
1015** Local Function Prototypes - not available for external access.
1016*/
1017
1018/* Forward declaration(s): */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001019static u32 MT2063_CalcLO1Mult(u32 * Div, u32 * FracN, u32 f_LO,
1020 u32 f_LO_Step, u32 f_Ref);
1021static u32 MT2063_CalcLO2Mult(u32 * Div, u32 * FracN, u32 f_LO,
1022 u32 f_LO_Step, u32 f_Ref);
1023static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num,
1024 u32 denom);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001025
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001026/**
1027 * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked
1028 *
1029 * @state: struct mt2063_state pointer
1030 *
1031 * This function returns 0, if no lock, 1 if locked and a value < 1 if error
1032 */
1033unsigned int mt2063_lockStatus(struct mt2063_state *state)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001034{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001035 const u32 nMaxWait = 100; /* wait a maximum of 100 msec */
1036 const u32 nPollRate = 2; /* poll status bits every 2 ms */
1037 const u32 nMaxLoops = nMaxWait / nPollRate;
1038 const u8 LO1LK = 0x80;
1039 u8 LO2LK = 0x08;
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001040 u32 status;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001041 u32 nDelays = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001042
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001043 /* LO2 Lock bit was in a different place for B0 version */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001044 if (state->tuner_id == MT2063_B0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001045 LO2LK = 0x40;
1046
1047 do {
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001048 status = mt2063_read(state, MT2063_REG_LO_STATUS,
1049 &state->reg[MT2063_REG_LO_STATUS], 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001050
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001051 if (status < 0)
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001052 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001053
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001054 if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) ==
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001055 (LO1LK | LO2LK)) {
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001056 return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001057 }
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001058 msleep(nPollRate); /* Wait between retries */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001059 }
1060 while (++nDelays < nMaxLoops);
1061
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001062 /*
1063 * Got no lock or partial lock
1064 */
1065 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001066}
Mauro Carvalho Chehab3d497002011-07-21 11:00:59 -03001067EXPORT_SYMBOL_GPL(mt2063_lockStatus);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001068
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001069/*
1070 * mt2063_set_dnc_output_enable()
1071 */
1072static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state,
1073 enum MT2063_DNC_Output_Enable *pValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001074{
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001075 if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */
1076 if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
1077 *pValue = MT2063_DNC_NONE;
1078 else
1079 *pValue = MT2063_DNC_2;
1080 } else { /* DNC1 is on */
1081 if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
1082 *pValue = MT2063_DNC_1;
1083 else
1084 *pValue = MT2063_DNC_BOTH;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001085 }
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001086 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001087}
1088
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001089/*
1090 * mt2063_set_dnc_output_enable()
1091 */
1092static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state,
1093 enum MT2063_DNC_Output_Enable nValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001094{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001095 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001096 u8 val = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001097
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001098 /* selects, which DNC output is used */
1099 switch (nValue) {
1100 case MT2063_DNC_NONE:
1101 {
1102 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
1103 if (state->reg[MT2063_REG_DNC_GAIN] !=
1104 val)
1105 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001106 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001107 MT2063_REG_DNC_GAIN,
1108 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001109
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001110 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
1111 if (state->reg[MT2063_REG_VGA_GAIN] !=
1112 val)
1113 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001114 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001115 MT2063_REG_VGA_GAIN,
1116 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001117
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001118 val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
1119 if (state->reg[MT2063_REG_RSVD_20] !=
1120 val)
1121 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001122 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001123 MT2063_REG_RSVD_20,
1124 val);
1125
1126 break;
1127 }
1128 case MT2063_DNC_1:
1129 {
1130 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */
1131 if (state->reg[MT2063_REG_DNC_GAIN] !=
1132 val)
1133 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001134 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001135 MT2063_REG_DNC_GAIN,
1136 val);
1137
1138 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
1139 if (state->reg[MT2063_REG_VGA_GAIN] !=
1140 val)
1141 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001142 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001143 MT2063_REG_VGA_GAIN,
1144 val);
1145
1146 val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
1147 if (state->reg[MT2063_REG_RSVD_20] !=
1148 val)
1149 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001150 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001151 MT2063_REG_RSVD_20,
1152 val);
1153
1154 break;
1155 }
1156 case MT2063_DNC_2:
1157 {
1158 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
1159 if (state->reg[MT2063_REG_DNC_GAIN] !=
1160 val)
1161 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001162 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001163 MT2063_REG_DNC_GAIN,
1164 val);
1165
1166 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */
1167 if (state->reg[MT2063_REG_VGA_GAIN] !=
1168 val)
1169 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001170 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001171 MT2063_REG_VGA_GAIN,
1172 val);
1173
1174 val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
1175 if (state->reg[MT2063_REG_RSVD_20] !=
1176 val)
1177 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001178 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001179 MT2063_REG_RSVD_20,
1180 val);
1181
1182 break;
1183 }
1184 case MT2063_DNC_BOTH:
1185 {
1186 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */
1187 if (state->reg[MT2063_REG_DNC_GAIN] !=
1188 val)
1189 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001190 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001191 MT2063_REG_DNC_GAIN,
1192 val);
1193
1194 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */
1195 if (state->reg[MT2063_REG_VGA_GAIN] !=
1196 val)
1197 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001198 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001199 MT2063_REG_VGA_GAIN,
1200 val);
1201
1202 val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
1203 if (state->reg[MT2063_REG_RSVD_20] !=
1204 val)
1205 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001206 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001207 MT2063_REG_RSVD_20,
1208 val);
1209
1210 break;
1211 }
1212 default:
1213 break;
1214 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001215
1216 return (status);
1217}
1218
1219/******************************************************************************
1220**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001221** Name: MT2063_SetReceiverMode
1222**
1223** Description: Set the MT2063 receiver mode
1224**
1225** --------------+----------------------------------------------
1226** Mode 0 : | MT2063_CABLE_QAM
1227** Mode 1 : | MT2063_CABLE_ANALOG
1228** Mode 2 : | MT2063_OFFAIR_COFDM
1229** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
1230** Mode 4 : | MT2063_OFFAIR_ANALOG
1231** Mode 5 : | MT2063_OFFAIR_8VSB
1232** --------------+----+----+----+----+-----+--------------------
1233** (DNC1GC & DNC2GC are the values, which are used, when the specific
1234** DNC Output is selected, the other is always off)
1235**
1236** |<---------- Mode -------------->|
1237** Reg Field | 0 | 1 | 2 | 3 | 4 | 5 |
1238** ------------+-----+-----+-----+-----+-----+-----+
1239** RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF
1240** LNARin | 0 | 0 | 3 | 3 | 3 | 3
1241** FIFFQen | 1 | 1 | 1 | 1 | 1 | 1
1242** FIFFq | 0 | 0 | 0 | 0 | 0 | 0
1243** DNC1gc | 0 | 0 | 0 | 0 | 0 | 0
1244** DNC2gc | 0 | 0 | 0 | 0 | 0 | 0
1245** GCU Auto | 1 | 1 | 1 | 1 | 1 | 1
1246** LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31
1247** LNA Target | 44 | 43 | 43 | 43 | 43 | 43
1248** ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0
1249** RF max Atn | 31 | 31 | 31 | 31 | 31 | 31
1250** PD1 Target | 36 | 36 | 38 | 38 | 36 | 38
1251** ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0
1252** FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5
1253** PD2 Target | 40 | 33 | 42 | 42 | 33 | 42
1254**
1255**
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001256** Parameters: state - ptr to mt2063_state structure
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001257** Mode - desired reciever mode
1258**
1259** Usage: status = MT2063_SetReceiverMode(hMT2063, Mode);
1260**
1261** Returns: status:
1262** MT_OK - No errors
1263** MT_COMM_ERR - Serial bus communications error
1264**
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001265** Dependencies: mt2063_setreg - Write a byte of data to a HW register.
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001266** Assumes that the tuner cache is valid.
1267**
1268** Revision History:
1269**
1270** SCR Date Author Description
1271** -------------------------------------------------------------------------
1272** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1273** N/A 01-10-2007 PINZ Added additional GCU Settings, FIFF Calib will be triggered
1274** 155 10-01-2007 DAD Ver 1.06: Add receiver mode for SECAM positive
1275** modulation
1276** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
1277** N/A 10-22-2007 PINZ Ver 1.07: Changed some Registers at init to have
1278** the same settings as with MT Launcher
1279** N/A 10-30-2007 PINZ Add SetParam VGAGC & VGAOI
1280** Add SetParam DNC_OUTPUT_ENABLE
1281** Removed VGAGC from receiver mode,
1282** default now 1
1283** N/A 10-31-2007 PINZ Ver 1.08: Add SetParam TAGC, removed from rcvr-mode
1284** Add SetParam AMPGC, removed from rcvr-mode
1285** Corrected names of GCU values
1286** reorganized receiver modes, removed,
1287** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
1288** Actualized Receiver-Mode values
1289** N/A 11-12-2007 PINZ Ver 1.09: Actualized Receiver-Mode values
1290** N/A 11-27-2007 PINZ Improved buffered writing
1291** 01-03-2008 PINZ Ver 1.10: Added a trigger of BYPATNUP for
1292** correct wakeup of the LNA after shutdown
1293** Set AFCsd = 1 as default
1294** Changed CAP1sel default
1295** 01-14-2008 PINZ Ver 1.11: Updated gain settings
1296** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
1297** Split SetParam up to ACLNA / ACLNA_MAX
1298** removed ACLNA_INRC/DECR (+RF & FIF)
1299** removed GCUAUTO / BYPATNDN/UP
1300**
1301******************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001302static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001303 enum MT2063_RCVR_MODES Mode)
1304{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001305 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001306 u8 val;
1307 u32 longval;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001308
1309 if (Mode >= MT2063_NUM_RCVR_MODES)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001310 status = -ERANGE;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001311
1312 /* RFAGCen */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001313 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001314 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001315 (state->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001316 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x40) | (RFAGCEN[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001317 ? 0x40 :
1318 0x00);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001319 if (state->reg[MT2063_REG_PD1_TGT] != val) {
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001320 status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001321 }
1322 }
1323
1324 /* LNARin */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001325 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001326 u8 val = (state-> reg[MT2063_REG_CTRL_2C] & (u8) ~ 0x03) |
1327 (LNARIN[Mode] & 0x03);
1328 if (state->reg[MT2063_REG_CTRL_2C] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001329 status |= mt2063_setreg(state, MT2063_REG_CTRL_2C,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001330 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001331 }
1332
1333 /* FIFFQEN and FIFFQ */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001334 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001335 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001336 (state->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001337 reg[MT2063_REG_FIFF_CTRL2] & (u8) ~ 0xF0) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001338 (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001339 if (state->reg[MT2063_REG_FIFF_CTRL2] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001340 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001341 mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001342 /* trigger FIFF calibration, needed after changing FIFFQ */
1343 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001344 (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001345 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001346 mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001347 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001348 (state->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001349 reg[MT2063_REG_FIFF_CTRL] & (u8) ~ 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001350 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001351 mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001352 }
1353 }
1354
1355 /* DNC1GC & DNC2GC */
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001356 status |= mt2063_get_dnc_output_enable(state, &longval);
1357 status |= mt2063_set_dnc_output_enable(state, longval);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001358
1359 /* acLNAmax */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001360 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001361 u8 val = (state-> reg[MT2063_REG_LNA_OV] & (u8) ~ 0x1F) |
1362 (ACLNAMAX[Mode] & 0x1F);
1363 if (state->reg[MT2063_REG_LNA_OV] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001364 status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001365 }
1366
1367 /* LNATGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001368 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001369 u8 val = (state-> reg[MT2063_REG_LNA_TGT] & (u8) ~ 0x3F) |
1370 (LNATGT[Mode] & 0x3F);
1371 if (state->reg[MT2063_REG_LNA_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001372 status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001373 }
1374
1375 /* ACRF */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001376 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001377 u8 val = (state-> reg[MT2063_REG_RF_OV] & (u8) ~ 0x1F) |
1378 (ACRFMAX[Mode] & 0x1F);
1379 if (state->reg[MT2063_REG_RF_OV] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001380 status |= mt2063_setreg(state, MT2063_REG_RF_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001381 }
1382
1383 /* PD1TGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001384 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001385 u8 val = (state-> reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x3F) |
1386 (PD1TGT[Mode] & 0x3F);
1387 if (state->reg[MT2063_REG_PD1_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001388 status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001389 }
1390
1391 /* FIFATN */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001392 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001393 u8 val = ACFIFMAX[Mode];
1394 if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5)
1395 val = 5;
1396 val = (state-> reg[MT2063_REG_FIF_OV] & (u8) ~ 0x1F) |
1397 (val & 0x1F);
1398 if (state->reg[MT2063_REG_FIF_OV] != val) {
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001399 status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val);
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001400 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001401 }
1402
1403 /* PD2TGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001404 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001405 u8 val = (state-> reg[MT2063_REG_PD2_TGT] & (u8) ~ 0x3F) |
1406 (PD2TGT[Mode] & 0x3F);
1407 if (state->reg[MT2063_REG_PD2_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001408 status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001409 }
1410
1411 /* Ignore ATN Overload */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001412 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001413 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001414 (state->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001415 reg[MT2063_REG_LNA_TGT] & (u8) ~ 0x80) | (RFOVDIS[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001416 ? 0x80 :
1417 0x00);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001418 if (state->reg[MT2063_REG_LNA_TGT] != val) {
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001419 status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001420 }
1421 }
1422
1423 /* Ignore FIF Overload */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001424 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001425 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001426 (state->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001427 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x80) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001428 (FIFOVDIS[Mode] ? 0x80 : 0x00);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001429 if (state->reg[MT2063_REG_PD1_TGT] != val) {
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001430 status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001431 }
1432 }
1433
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001434 if (status >= 0)
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001435 state->rcvr_mode = Mode;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001436
1437 return (status);
1438}
1439
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001440/****************************************************************************
1441**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001442** Name: MT2063_ClearPowerMaskBits
1443**
1444** Description: Clears the power-down mask bits for various sections of
1445** the MT2063
1446**
1447** Parameters: h - Tuner handle (returned by MT2063_Open)
1448** Bits - Mask bits to be cleared.
1449**
1450** See definition of MT2063_Mask_Bits type for description
1451** of each of the power bits.
1452**
1453** Returns: status:
1454** MT_OK - No errors
1455** MT_INV_HANDLE - Invalid tuner handle
1456** MT_COMM_ERR - Serial bus communications error
1457**
1458** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
1459**
1460** Revision History:
1461**
1462** SCR Date Author Description
1463** -------------------------------------------------------------------------
1464** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1465**
1466****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001467static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, enum MT2063_Mask_Bits Bits)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001468{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001469 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001470
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001471 Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */
1472 if ((Bits & 0xFF00) != 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001473 state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001474 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001475 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001476 MT2063_REG_PWR_2,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001477 &state->reg[MT2063_REG_PWR_2], 1);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001478 }
1479 if ((Bits & 0xFF) != 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001480 state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001481 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001482 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001483 MT2063_REG_PWR_1,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001484 &state->reg[MT2063_REG_PWR_1], 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001485 }
1486
1487 return (status);
1488}
1489
1490/****************************************************************************
1491**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001492** Name: MT2063_SoftwareShutdown
1493**
1494** Description: Enables or disables software shutdown function. When
1495** Shutdown==1, any section whose power mask is set will be
1496** shutdown.
1497**
1498** Parameters: h - Tuner handle (returned by MT2063_Open)
1499** Shutdown - 1 = shutdown the masked sections, otherwise
1500** power all sections on
1501**
1502** Returns: status:
1503** MT_OK - No errors
1504** MT_INV_HANDLE - Invalid tuner handle
1505** MT_COMM_ERR - Serial bus communications error
1506**
1507** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
1508**
1509** Revision History:
1510**
1511** SCR Date Author Description
1512** -------------------------------------------------------------------------
1513** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1514** 01-03-2008 PINZ Ver 1.xx: Added a trigger of BYPATNUP for
1515** correct wakeup of the LNA
1516**
1517****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001518static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001519{
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001520 u32 status; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001521
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001522 if (Shutdown == 1)
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001523 state->reg[MT2063_REG_PWR_1] |= 0x04; /* Turn the bit on */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001524 else
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001525 state->reg[MT2063_REG_PWR_1] &= ~0x04; /* Turn off the bit */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001526
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001527 status = mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001528 MT2063_REG_PWR_1,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001529 &state->reg[MT2063_REG_PWR_1], 1);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001530
1531 if (Shutdown != 1) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001532 state->reg[MT2063_REG_BYP_CTRL] =
1533 (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001534 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001535 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001536 MT2063_REG_BYP_CTRL,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001537 &state->reg[MT2063_REG_BYP_CTRL],
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001538 1);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001539 state->reg[MT2063_REG_BYP_CTRL] =
1540 (state->reg[MT2063_REG_BYP_CTRL] & 0x9F);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001541 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001542 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001543 MT2063_REG_BYP_CTRL,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001544 &state->reg[MT2063_REG_BYP_CTRL],
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001545 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001546 }
1547
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001548 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001549}
1550
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001551static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001552{
1553 return f_ref * (f_LO / f_ref)
1554 + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step);
1555}
1556
1557/****************************************************************************
1558**
1559** Name: fLO_FractionalTerm
1560**
1561** Description: Calculates the portion contributed by FracN / denom.
1562**
1563** This function preserves maximum precision without
1564** risk of overflow. It accurately calculates
1565** f_ref * num / denom to within 1 HZ with fixed math.
1566**
1567** Parameters: num - Fractional portion of the multiplier
1568** denom - denominator portion of the ratio
1569** This routine successfully handles denom values
1570** up to and including 2^18.
1571** f_Ref - SRO frequency. This calculation handles
1572** f_ref as two separate 14-bit fields.
1573** Therefore, a maximum value of 2^28-1
1574** may safely be used for f_ref. This is
1575** the genesis of the magic number "14" and the
1576** magic mask value of 0x03FFF.
1577**
1578** Returns: f_ref * num / denom
1579**
1580** Revision History:
1581**
1582** SCR Date Author Description
1583** -------------------------------------------------------------------------
1584** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1585**
1586****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001587static u32 MT2063_fLO_FractionalTerm(u32 f_ref,
1588 u32 num, u32 denom)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001589{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001590 u32 t1 = (f_ref >> 14) * num;
1591 u32 term1 = t1 / denom;
1592 u32 loss = t1 % denom;
1593 u32 term2 =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001594 (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom;
1595 return ((term1 << 14) + term2);
1596}
1597
1598/****************************************************************************
1599**
1600** Name: CalcLO1Mult
1601**
1602** Description: Calculates Integer divider value and the numerator
1603** value for a FracN PLL.
1604**
1605** This function assumes that the f_LO and f_Ref are
1606** evenly divisible by f_LO_Step.
1607**
1608** Parameters: Div - OUTPUT: Whole number portion of the multiplier
1609** FracN - OUTPUT: Fractional portion of the multiplier
1610** f_LO - desired LO frequency.
1611** f_LO_Step - Minimum step size for the LO (in Hz).
1612** f_Ref - SRO frequency.
1613** f_Avoid - Range of PLL frequencies to avoid near
1614** integer multiples of f_Ref (in Hz).
1615**
1616** Returns: Recalculated LO frequency.
1617**
1618** Revision History:
1619**
1620** SCR Date Author Description
1621** -------------------------------------------------------------------------
1622** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1623**
1624****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001625static u32 MT2063_CalcLO1Mult(u32 * Div,
1626 u32 * FracN,
1627 u32 f_LO,
1628 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001629{
1630 /* Calculate the whole number portion of the divider */
1631 *Div = f_LO / f_Ref;
1632
1633 /* Calculate the numerator value (round to nearest f_LO_Step) */
1634 *FracN =
1635 (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
1636 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
1637
1638 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64);
1639}
1640
1641/****************************************************************************
1642**
1643** Name: CalcLO2Mult
1644**
1645** Description: Calculates Integer divider value and the numerator
1646** value for a FracN PLL.
1647**
1648** This function assumes that the f_LO and f_Ref are
1649** evenly divisible by f_LO_Step.
1650**
1651** Parameters: Div - OUTPUT: Whole number portion of the multiplier
1652** FracN - OUTPUT: Fractional portion of the multiplier
1653** f_LO - desired LO frequency.
1654** f_LO_Step - Minimum step size for the LO (in Hz).
1655** f_Ref - SRO frequency.
1656** f_Avoid - Range of PLL frequencies to avoid near
1657** integer multiples of f_Ref (in Hz).
1658**
1659** Returns: Recalculated LO frequency.
1660**
1661** Revision History:
1662**
1663** SCR Date Author Description
1664** -------------------------------------------------------------------------
1665** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1666**
1667****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001668static u32 MT2063_CalcLO2Mult(u32 * Div,
1669 u32 * FracN,
1670 u32 f_LO,
1671 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001672{
1673 /* Calculate the whole number portion of the divider */
1674 *Div = f_LO / f_Ref;
1675
1676 /* Calculate the numerator value (round to nearest f_LO_Step) */
1677 *FracN =
1678 (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
1679 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
1680
1681 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN,
1682 8191);
1683}
1684
1685/****************************************************************************
1686**
1687** Name: FindClearTuneFilter
1688**
1689** Description: Calculate the corrrect ClearTune filter to be used for
1690** a given input frequency.
1691**
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001692** Parameters: state - ptr to tuner data structure
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001693** f_in - RF input center frequency (in Hz).
1694**
1695** Returns: ClearTune filter number (0-31)
1696**
1697** Dependencies: MUST CALL MT2064_Open BEFORE FindClearTuneFilter!
1698**
1699** Revision History:
1700**
1701** SCR Date Author Description
1702** -------------------------------------------------------------------------
1703** 04-10-2008 PINZ Ver 1.14: Use software-controlled ClearTune
1704** cross-over frequency values.
1705**
1706****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001707static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001708{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001709 u32 RFBand;
1710 u32 idx; /* index loop */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001711
1712 /*
1713 ** Find RF Band setting
1714 */
1715 RFBand = 31; /* def when f_in > all */
1716 for (idx = 0; idx < 31; ++idx) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001717 if (state->CTFiltMax[idx] >= f_in) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001718 RFBand = idx;
1719 break;
1720 }
1721 }
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001722 return RFBand;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001723}
1724
1725/****************************************************************************
1726**
1727** Name: MT2063_Tune
1728**
1729** Description: Change the tuner's tuned frequency to RFin.
1730**
1731** Parameters: h - Open handle to the tuner (from MT2063_Open).
1732** f_in - RF input center frequency (in Hz).
1733**
1734** Returns: status:
1735** MT_OK - No errors
1736** MT_INV_HANDLE - Invalid tuner handle
1737** MT_UPC_UNLOCK - Upconverter PLL unlocked
1738** MT_DNC_UNLOCK - Downconverter PLL unlocked
1739** MT_COMM_ERR - Serial bus communications error
1740** MT_SPUR_CNT_MASK - Count of avoided LO spurs
1741** MT_SPUR_PRESENT - LO spur possible in output
1742** MT_FIN_RANGE - Input freq out of range
1743** MT_FOUT_RANGE - Output freq out of range
1744** MT_UPC_RANGE - Upconverter freq out of range
1745** MT_DNC_RANGE - Downconverter freq out of range
1746**
1747** Dependencies: MUST CALL MT2063_Open BEFORE MT2063_Tune!
1748**
1749** MT_ReadSub - Read data from the two-wire serial bus
1750** MT_WriteSub - Write data to the two-wire serial bus
1751** MT_Sleep - Delay execution for x milliseconds
1752** MT2063_GetLocked - Checks to see if LO1 and LO2 are locked
1753**
1754** Revision History:
1755**
1756** SCR Date Author Description
1757** -------------------------------------------------------------------------
1758** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1759** 04-10-2008 PINZ Ver 1.05: Use software-controlled ClearTune
1760** cross-over frequency values.
1761** 175 I 16-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
1762** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
1763** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
1764**
1765****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001766static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001767{ /* RF input center frequency */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001768
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001769 u32 status = 0; /* status of operation */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001770 u32 LO1; /* 1st LO register value */
1771 u32 Num1; /* Numerator for LO1 reg. value */
1772 u32 f_IF1; /* 1st IF requested */
1773 u32 LO2; /* 2nd LO register value */
1774 u32 Num2; /* Numerator for LO2 reg. value */
1775 u32 ofLO1, ofLO2; /* last time's LO frequencies */
1776 u32 ofin, ofout; /* last time's I/O frequencies */
1777 u8 fiffc = 0x80; /* FIFF center freq from tuner */
1778 u32 fiffof; /* Offset from FIFF center freq */
1779 const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */
1780 u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */
1781 u8 val;
1782 u32 RFBand;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001783
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001784 /* Check the input and output frequency ranges */
1785 if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ))
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001786 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001787
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001788 if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ)
1789 || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ))
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001790 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001791
1792 /*
1793 ** Save original LO1 and LO2 register values
1794 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001795 ofLO1 = state->AS_Data.f_LO1;
1796 ofLO2 = state->AS_Data.f_LO2;
1797 ofin = state->AS_Data.f_in;
1798 ofout = state->AS_Data.f_out;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001799
1800 /*
1801 ** Find and set RF Band setting
1802 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001803 if (state->ctfilt_sw == 1) {
1804 val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08);
1805 if (state->reg[MT2063_REG_CTUNE_CTRL] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001806 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001807 mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001808 }
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001809 val = state->reg[MT2063_REG_CTUNE_OV];
1810 RFBand = FindClearTuneFilter(state, f_in);
1811 state->reg[MT2063_REG_CTUNE_OV] =
1812 (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001813 | RFBand);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001814 if (state->reg[MT2063_REG_CTUNE_OV] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001815 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001816 mt2063_setreg(state, MT2063_REG_CTUNE_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001817 }
1818 }
1819
1820 /*
1821 ** Read the FIFF Center Frequency from the tuner
1822 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001823 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001824 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001825 mt2063_read(state,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001826 MT2063_REG_FIFFC,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001827 &state->reg[MT2063_REG_FIFFC], 1);
1828 fiffc = state->reg[MT2063_REG_FIFFC];
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001829 }
1830 /*
1831 ** Assign in the requested values
1832 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001833 state->AS_Data.f_in = f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001834 /* Request a 1st IF such that LO1 is on a step size */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001835 state->AS_Data.f_if1_Request =
1836 MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in,
1837 state->AS_Data.f_LO1_Step,
1838 state->AS_Data.f_ref) - f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001839
1840 /*
1841 ** Calculate frequency settings. f_IF1_FREQ + f_in is the
1842 ** desired LO1 frequency
1843 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001844 MT2063_ResetExclZones(&state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001845
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001846 f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001847
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001848 state->AS_Data.f_LO1 =
1849 MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step,
1850 state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001851
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001852 state->AS_Data.f_LO2 =
1853 MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
1854 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001855
1856 /*
1857 ** Check for any LO spurs in the output bandwidth and adjust
1858 ** the LO settings to avoid them if needed
1859 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001860 status |= MT2063_AvoidSpurs(state, &state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001861 /*
1862 ** MT_AvoidSpurs spurs may have changed the LO1 & LO2 values.
1863 ** Recalculate the LO frequencies and the values to be placed
1864 ** in the tuning registers.
1865 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001866 state->AS_Data.f_LO1 =
1867 MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1,
1868 state->AS_Data.f_LO1_Step, state->AS_Data.f_ref);
1869 state->AS_Data.f_LO2 =
1870 MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
1871 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
1872 state->AS_Data.f_LO2 =
1873 MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2,
1874 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001875
1876 /*
1877 ** Check the upconverter and downconverter frequency ranges
1878 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001879 if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ)
1880 || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001881 status |= MT2063_UPC_RANGE;
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001882 if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ)
1883 || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001884 status |= MT2063_DNC_RANGE;
1885 /* LO2 Lock bit was in a different place for B0 version */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001886 if (state->tuner_id == MT2063_B0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001887 LO2LK = 0x40;
1888
1889 /*
1890 ** If we have the same LO frequencies and we're already locked,
1891 ** then skip re-programming the LO registers.
1892 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001893 if ((ofLO1 != state->AS_Data.f_LO1)
1894 || (ofLO2 != state->AS_Data.f_LO2)
1895 || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) !=
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001896 (LO1LK | LO2LK))) {
1897 /*
1898 ** Calculate the FIFFOF register value
1899 **
1900 ** IF1_Actual
1901 ** FIFFOF = ------------ - 8 * FIFFC - 4992
1902 ** f_ref/64
1903 */
1904 fiffof =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001905 (state->AS_Data.f_LO1 -
1906 f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc -
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001907 4992;
1908 if (fiffof > 0xFF)
1909 fiffof = 0xFF;
1910
1911 /*
1912 ** Place all of the calculated values into the local tuner
1913 ** register fields.
1914 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001915 if (status >= 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001916 state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */
1917 state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */
1918 state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001919 |(Num2 >> 12)); /* NUM2q (hi) */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001920 state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */
1921 state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001922
1923 /*
1924 ** Now write out the computed register values
1925 ** IMPORTANT: There is a required order for writing
1926 ** (0x05 must follow all the others).
1927 */
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001928 status |= mt2063_write(state, MT2063_REG_LO1CQ_1, &state->reg[MT2063_REG_LO1CQ_1], 5); /* 0x01 - 0x05 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001929 if (state->tuner_id == MT2063_B0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001930 /* Re-write the one-shot bits to trigger the tune operation */
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001931 status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001932 }
1933 /* Write out the FIFF offset only if it's changing */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001934 if (state->reg[MT2063_REG_FIFF_OFFSET] !=
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001935 (u8) fiffof) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001936 state->reg[MT2063_REG_FIFF_OFFSET] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001937 (u8) fiffof;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001938 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001939 mt2063_write(state,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001940 MT2063_REG_FIFF_OFFSET,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001941 &state->
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001942 reg[MT2063_REG_FIFF_OFFSET],
1943 1);
1944 }
1945 }
1946
1947 /*
1948 ** Check for LO's locking
1949 */
1950
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001951 if (status < 0)
1952 return status;
1953
1954 status = mt2063_lockStatus(state);
1955 if (status < 0)
1956 return status;
1957 if (!status)
1958 return -EINVAL; /* Couldn't lock */
1959
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001960 /*
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001961 * If we locked OK, assign calculated data to mt2063_state structure
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001962 */
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001963 state->f_IF1_actual = state->AS_Data.f_LO1 - f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001964 }
1965
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001966 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001967}
1968
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001969int mt2063_setTune(struct dvb_frontend *fe, u32 f_in, u32 bw_in,
Mauro Carvalho Chehabfad11db2011-07-21 10:35:30 -03001970 enum MTTune_atv_standard tv_type)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001971{
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001972 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001973 u32 status = 0;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001974 s32 pict_car = 0;
1975 s32 pict2chanb_vsb = 0;
1976 s32 pict2chanb_snd = 0;
1977 s32 pict2snd1 = 0;
1978 s32 pict2snd2 = 0;
1979 s32 ch_bw = 0;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001980 s32 if_mid = 0;
1981 s32 rcvr_mode = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001982
1983 switch (tv_type) {
1984 case MTTUNEA_PAL_B:{
1985 pict_car = 38900000;
1986 ch_bw = 8000000;
1987 pict2chanb_vsb = -1250000;
1988 pict2snd1 = 5500000;
1989 pict2snd2 = 5742000;
1990 rcvr_mode = 1;
1991 break;
1992 }
1993 case MTTUNEA_PAL_G:{
1994 pict_car = 38900000;
1995 ch_bw = 7000000;
1996 pict2chanb_vsb = -1250000;
1997 pict2snd1 = 5500000;
1998 pict2snd2 = 0;
1999 rcvr_mode = 1;
2000 break;
2001 }
2002 case MTTUNEA_PAL_I:{
2003 pict_car = 38900000;
2004 ch_bw = 8000000;
2005 pict2chanb_vsb = -1250000;
2006 pict2snd1 = 6000000;
2007 pict2snd2 = 0;
2008 rcvr_mode = 1;
2009 break;
2010 }
2011 case MTTUNEA_PAL_L:{
2012 pict_car = 38900000;
2013 ch_bw = 8000000;
2014 pict2chanb_vsb = -1250000;
2015 pict2snd1 = 6500000;
2016 pict2snd2 = 0;
2017 rcvr_mode = 1;
2018 break;
2019 }
2020 case MTTUNEA_PAL_MN:{
2021 pict_car = 38900000;
2022 ch_bw = 6000000;
2023 pict2chanb_vsb = -1250000;
2024 pict2snd1 = 4500000;
2025 pict2snd2 = 0;
2026 rcvr_mode = 1;
2027 break;
2028 }
2029 case MTTUNEA_PAL_DK:{
2030 pict_car = 38900000;
2031 ch_bw = 8000000;
2032 pict2chanb_vsb = -1250000;
2033 pict2snd1 = 6500000;
2034 pict2snd2 = 0;
2035 rcvr_mode = 1;
2036 break;
2037 }
2038 case MTTUNEA_DIGITAL:{
2039 pict_car = 36125000;
2040 ch_bw = 8000000;
2041 pict2chanb_vsb = -(ch_bw / 2);
2042 pict2snd1 = 0;
2043 pict2snd2 = 0;
2044 rcvr_mode = 2;
2045 break;
2046 }
2047 case MTTUNEA_FMRADIO:{
2048 pict_car = 38900000;
2049 ch_bw = 8000000;
2050 pict2chanb_vsb = -(ch_bw / 2);
2051 pict2snd1 = 0;
2052 pict2snd2 = 0;
2053 rcvr_mode = 4;
2054 //f_in -= 2900000;
2055 break;
2056 }
2057 case MTTUNEA_DVBC:{
2058 pict_car = 36125000;
2059 ch_bw = 8000000;
2060 pict2chanb_vsb = -(ch_bw / 2);
2061 pict2snd1 = 0;
2062 pict2snd2 = 0;
2063 rcvr_mode = MT2063_CABLE_QAM;
2064 break;
2065 }
2066 case MTTUNEA_DVBT:{
2067 pict_car = 36125000;
2068 ch_bw = bw_in; //8000000
2069 pict2chanb_vsb = -(ch_bw / 2);
2070 pict2snd1 = 0;
2071 pict2snd2 = 0;
2072 rcvr_mode = MT2063_OFFAIR_COFDM;
2073 break;
2074 }
2075 case MTTUNEA_UNKNOWN:
2076 break;
2077 default:
2078 break;
2079 }
2080
2081 pict2chanb_snd = pict2chanb_vsb - ch_bw;
2082 if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
2083
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03002084 state->AS_Data.f_LO2_Step = 125000;
2085 state->AS_Data.f_out = if_mid;
2086 state->AS_Data.f_out_bw = ch_bw + 750000;
2087 status = MT2063_SetReceiverMode(state, rcvr_mode);
2088 if (status < 0)
2089 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002090
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03002091 status = MT2063_Tune(state, (f_in + (pict2chanb_vsb + (ch_bw / 2))));
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002092
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03002093 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002094}
2095
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002096static const u8 MT2063B0_defaults[] = {
2097 /* Reg, Value */
2098 0x19, 0x05,
2099 0x1B, 0x1D,
2100 0x1C, 0x1F,
2101 0x1D, 0x0F,
2102 0x1E, 0x3F,
2103 0x1F, 0x0F,
2104 0x20, 0x3F,
2105 0x22, 0x21,
2106 0x23, 0x3F,
2107 0x24, 0x20,
2108 0x25, 0x3F,
2109 0x27, 0xEE,
2110 0x2C, 0x27, /* bit at 0x20 is cleared below */
2111 0x30, 0x03,
2112 0x2C, 0x07, /* bit at 0x20 is cleared here */
2113 0x2D, 0x87,
2114 0x2E, 0xAA,
2115 0x28, 0xE1, /* Set the FIFCrst bit here */
2116 0x28, 0xE0, /* Clear the FIFCrst bit here */
2117 0x00
2118};
2119
2120/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
2121static const u8 MT2063B1_defaults[] = {
2122 /* Reg, Value */
2123 0x05, 0xF0,
2124 0x11, 0x10, /* New Enable AFCsd */
2125 0x19, 0x05,
2126 0x1A, 0x6C,
2127 0x1B, 0x24,
2128 0x1C, 0x28,
2129 0x1D, 0x8F,
2130 0x1E, 0x14,
2131 0x1F, 0x8F,
2132 0x20, 0x57,
2133 0x22, 0x21, /* New - ver 1.03 */
2134 0x23, 0x3C, /* New - ver 1.10 */
2135 0x24, 0x20, /* New - ver 1.03 */
2136 0x2C, 0x24, /* bit at 0x20 is cleared below */
2137 0x2D, 0x87, /* FIFFQ=0 */
2138 0x2F, 0xF3,
2139 0x30, 0x0C, /* New - ver 1.11 */
2140 0x31, 0x1B, /* New - ver 1.11 */
2141 0x2C, 0x04, /* bit at 0x20 is cleared here */
2142 0x28, 0xE1, /* Set the FIFCrst bit here */
2143 0x28, 0xE0, /* Clear the FIFCrst bit here */
2144 0x00
2145};
2146
2147/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
2148static const u8 MT2063B3_defaults[] = {
2149 /* Reg, Value */
2150 0x05, 0xF0,
2151 0x19, 0x3D,
2152 0x2C, 0x24, /* bit at 0x20 is cleared below */
2153 0x2C, 0x04, /* bit at 0x20 is cleared here */
2154 0x28, 0xE1, /* Set the FIFCrst bit here */
2155 0x28, 0xE0, /* Clear the FIFCrst bit here */
2156 0x00
2157};
2158
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002159static int mt2063_init(struct dvb_frontend *fe)
2160{
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002161 u32 status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002162 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002163 u8 all_resets = 0xF0; /* reset/load bits */
2164 const u8 *def = NULL;
2165 u32 FCRUN;
2166 s32 maxReads;
2167 u32 fcu_osc;
2168 u32 i;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002169
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002170 state->rcvr_mode = MT2063_CABLE_QAM;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002171
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002172 /* Read the Part/Rev code from the tuner */
2173 status = mt2063_read(state, MT2063_REG_PART_REV, state->reg, 1);
2174 if (status < 0)
2175 return status;
2176
2177 /* Check the part/rev code */
2178 if (((state->reg[MT2063_REG_PART_REV] != MT2063_B0) /* MT2063 B0 */
2179 &&(state->reg[MT2063_REG_PART_REV] != MT2063_B1) /* MT2063 B1 */
2180 &&(state->reg[MT2063_REG_PART_REV] != MT2063_B3))) /* MT2063 B3 */
2181 return -ENODEV; /* Wrong tuner Part/Rev code */
2182
2183 /* Check the 2nd byte of the Part/Rev code from the tuner */
2184 status = mt2063_read(state, MT2063_REG_RSVD_3B,
2185 &state->reg[MT2063_REG_RSVD_3B], 1);
2186
2187 /* b7 != 0 ==> NOT MT2063 */
2188 if (status < 0 ||((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00))
2189 return -ENODEV; /* Wrong tuner Part/Rev code */
2190
2191 /* Reset the tuner */
2192 status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1);
2193 if (status < 0)
2194 return status;
2195
2196 /* change all of the default values that vary from the HW reset values */
2197 /* def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */
2198 switch (state->reg[MT2063_REG_PART_REV]) {
2199 case MT2063_B3:
2200 def = MT2063B3_defaults;
2201 break;
2202
2203 case MT2063_B1:
2204 def = MT2063B1_defaults;
2205 break;
2206
2207 case MT2063_B0:
2208 def = MT2063B0_defaults;
2209 break;
2210
2211 default:
2212 return -ENODEV;
2213 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002214 }
2215
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002216 while (status >= 0 && *def) {
2217 u8 reg = *def++;
2218 u8 val = *def++;
2219 status = mt2063_write(state, reg, &val, 1);
2220 }
2221 if (status < 0)
2222 return status;
2223
2224 /* Wait for FIFF location to complete. */
2225 FCRUN = 1;
2226 maxReads = 10;
2227 while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) {
2228 msleep(2);
2229 status = mt2063_read(state,
2230 MT2063_REG_XO_STATUS,
2231 &state->
2232 reg[MT2063_REG_XO_STATUS], 1);
2233 FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6;
2234 }
2235
2236 if (FCRUN != 0 || status < 0)
2237 return -ENODEV;
2238
2239 status = mt2063_read(state,
2240 MT2063_REG_FIFFC,
2241 &state->reg[MT2063_REG_FIFFC], 1);
2242 if (status < 0)
2243 return status;
2244
2245 /* Read back all the registers from the tuner */
2246 status = mt2063_read(state,
2247 MT2063_REG_PART_REV,
2248 state->reg, MT2063_REG_END_REGS);
2249 if (status < 0)
2250 return status;
2251
2252 /* Initialize the tuner state. */
2253 state->tuner_id = state->reg[MT2063_REG_PART_REV];
2254 state->AS_Data.f_ref = MT2063_REF_FREQ;
2255 state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) *
2256 ((u32) state->reg[MT2063_REG_FIFFC] + 640);
2257 state->AS_Data.f_if1_bw = MT2063_IF1_BW;
2258 state->AS_Data.f_out = 43750000UL;
2259 state->AS_Data.f_out_bw = 6750000UL;
2260 state->AS_Data.f_zif_bw = MT2063_ZIF_BW;
2261 state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64;
2262 state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE;
2263 state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1;
2264 state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2;
2265 state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP;
2266 state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center;
2267 state->AS_Data.f_LO1 = 2181000000UL;
2268 state->AS_Data.f_LO2 = 1486249786UL;
2269 state->f_IF1_actual = state->AS_Data.f_if1_Center;
2270 state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual;
2271 state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID;
2272 state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID;
2273 state->num_regs = MT2063_REG_END_REGS;
2274 state->AS_Data.avoidDECT = MT2063_AVOID_BOTH;
2275 state->ctfilt_sw = 0;
2276
2277 state->CTFiltMax[0] = 69230000;
2278 state->CTFiltMax[1] = 105770000;
2279 state->CTFiltMax[2] = 140350000;
2280 state->CTFiltMax[3] = 177110000;
2281 state->CTFiltMax[4] = 212860000;
2282 state->CTFiltMax[5] = 241130000;
2283 state->CTFiltMax[6] = 274370000;
2284 state->CTFiltMax[7] = 309820000;
2285 state->CTFiltMax[8] = 342450000;
2286 state->CTFiltMax[9] = 378870000;
2287 state->CTFiltMax[10] = 416210000;
2288 state->CTFiltMax[11] = 456500000;
2289 state->CTFiltMax[12] = 495790000;
2290 state->CTFiltMax[13] = 534530000;
2291 state->CTFiltMax[14] = 572610000;
2292 state->CTFiltMax[15] = 598970000;
2293 state->CTFiltMax[16] = 635910000;
2294 state->CTFiltMax[17] = 672130000;
2295 state->CTFiltMax[18] = 714840000;
2296 state->CTFiltMax[19] = 739660000;
2297 state->CTFiltMax[20] = 770410000;
2298 state->CTFiltMax[21] = 814660000;
2299 state->CTFiltMax[22] = 846950000;
2300 state->CTFiltMax[23] = 867820000;
2301 state->CTFiltMax[24] = 915980000;
2302 state->CTFiltMax[25] = 947450000;
2303 state->CTFiltMax[26] = 983110000;
2304 state->CTFiltMax[27] = 1021630000;
2305 state->CTFiltMax[28] = 1061870000;
2306 state->CTFiltMax[29] = 1098330000;
2307 state->CTFiltMax[30] = 1138990000;
2308
2309 /*
2310 ** Fetch the FCU osc value and use it and the fRef value to
2311 ** scale all of the Band Max values
2312 */
2313
2314 state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A;
2315 status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
2316 &state->reg[MT2063_REG_CTUNE_CTRL], 1);
2317 if (status < 0)
2318 return status;
2319
2320 /* Read the ClearTune filter calibration value */
2321 status = mt2063_read(state, MT2063_REG_FIFFC,
2322 &state->reg[MT2063_REG_FIFFC], 1);
2323 if (status < 0)
2324 return status;
2325
2326 fcu_osc = state->reg[MT2063_REG_FIFFC];
2327
2328 state->reg[MT2063_REG_CTUNE_CTRL] = 0x00;
2329 status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
2330 &state->reg[MT2063_REG_CTUNE_CTRL], 1);
2331 if (status < 0)
2332 return status;
2333
2334 /* Adjust each of the values in the ClearTune filter cross-over table */
2335 for (i = 0; i < 31; i++)
2336 state->CTFiltMax[i] =(state->CTFiltMax[i] / 768) * (fcu_osc + 640);
2337
2338 status = MT2063_SoftwareShutdown(state, 1);
2339 if (status < 0)
2340 return status;
2341 status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
2342 if (status < 0)
2343 return status;
2344
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002345 return 0;
2346}
2347
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002348static int mt2063_get_status(struct dvb_frontend *fe, u32 * status)
2349{
2350 int rc = 0;
2351
2352 //get tuner lock status
2353
2354 return rc;
2355}
2356
2357static int mt2063_get_state(struct dvb_frontend *fe,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002358 enum tuner_param param, struct tuner_state *tunstate)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002359{
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002360 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002361
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002362 switch (param) {
2363 case DVBFE_TUNER_FREQUENCY:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002364 //get frequency
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002365 break;
2366 case DVBFE_TUNER_TUNERSTEP:
2367 break;
2368 case DVBFE_TUNER_IFFREQ:
2369 break;
2370 case DVBFE_TUNER_BANDWIDTH:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002371 //get bandwidth
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002372 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002373 case DVBFE_TUNER_REFCLOCK:
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03002374 tunstate->refclock = mt2063_lockStatus(state);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002375 break;
2376 default:
2377 break;
2378 }
2379
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002380 return (int)tunstate->refclock;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002381}
2382
2383static int mt2063_set_state(struct dvb_frontend *fe,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002384 enum tuner_param param, struct tuner_state *tunstate)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002385{
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002386 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002387 u32 status = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002388
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002389 switch (param) {
2390 case DVBFE_TUNER_FREQUENCY:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002391 //set frequency
2392
2393 status =
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03002394 mt2063_setTune(fe,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002395 tunstate->frequency, tunstate->bandwidth,
2396 state->tv_type);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002397
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002398 state->frequency = tunstate->frequency;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002399 break;
2400 case DVBFE_TUNER_TUNERSTEP:
2401 break;
2402 case DVBFE_TUNER_IFFREQ:
2403 break;
2404 case DVBFE_TUNER_BANDWIDTH:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002405 //set bandwidth
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002406 state->bandwidth = tunstate->bandwidth;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002407 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002408 case DVBFE_TUNER_REFCLOCK:
2409
2410 break;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002411 default:
2412 break;
2413 }
2414
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002415 return (int)status;
2416}
2417
2418static int mt2063_release(struct dvb_frontend *fe)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002419{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002420 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002421
2422 fe->tuner_priv = NULL;
2423 kfree(state);
2424
2425 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002426}
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002427
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002428static struct dvb_tuner_ops mt2063_ops = {
2429 .info = {
2430 .name = "MT2063 Silicon Tuner",
2431 .frequency_min = 45000000,
2432 .frequency_max = 850000000,
2433 .frequency_step = 0,
2434 },
2435
2436 .init = mt2063_init,
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002437 .sleep = MT2063_Sleep,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002438 .get_status = mt2063_get_status,
2439 .get_state = mt2063_get_state,
2440 .set_state = mt2063_set_state,
2441 .release = mt2063_release
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002442};
2443
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002444struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
2445 struct mt2063_config *config,
2446 struct i2c_adapter *i2c)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002447{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002448 struct mt2063_state *state = NULL;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002449
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002450 state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002451 if (state == NULL)
2452 goto error;
2453
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002454 state->config = config;
2455 state->i2c = i2c;
2456 state->frontend = fe;
2457 state->reference = config->refclock / 1000; /* kHz */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002458 fe->tuner_priv = state;
2459 fe->ops.tuner_ops = mt2063_ops;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002460
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002461 printk("%s: Attaching MT2063 \n", __func__);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002462 return fe;
2463
2464error:
2465 kfree(state);
2466 return NULL;
2467}
Mauro Carvalho Chehab3d497002011-07-21 11:00:59 -03002468EXPORT_SYMBOL_GPL(mt2063_attach);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002469
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03002470/*
2471 * Ancillary routines visible outside mt2063
2472 * FIXME: Remove them in favor of using standard tuner callbacks
2473 */
2474unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe)
2475{
2476 struct mt2063_state *state = fe->tuner_priv;
2477 int err = 0;
2478
2479 err = MT2063_SoftwareShutdown(state, 1);
2480 if (err < 0)
2481 printk(KERN_ERR "%s: Couldn't shutdown\n", __func__);
2482
2483 return err;
2484}
2485EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown);
2486
2487unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe)
2488{
2489 struct mt2063_state *state = fe->tuner_priv;
2490 int err = 0;
2491
2492 err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
2493 if (err < 0)
2494 printk(KERN_ERR "%s: Invalid parameter\n", __func__);
2495
2496 return err;
2497}
2498EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits);
2499
2500
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002501MODULE_PARM_DESC(verbose, "Set Verbosity level");
2502
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002503MODULE_AUTHOR("Henry");
2504MODULE_DESCRIPTION("MT2063 Silicon tuner");
2505MODULE_LICENSE("GPL");