blob: d13b78ba45d0053a5c55ed3f5701e9623622b14b [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 Chehabe3f94fb2011-07-21 13:41:29 -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,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -0300737 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 Chehabe3f94fb2011-07-21 13:41:29 -0300852static u32 MT2063_AvoidSpurs(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
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001014/**
1015 * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked
1016 *
1017 * @state: struct mt2063_state pointer
1018 *
1019 * This function returns 0, if no lock, 1 if locked and a value < 1 if error
1020 */
1021unsigned int mt2063_lockStatus(struct mt2063_state *state)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001022{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001023 const u32 nMaxWait = 100; /* wait a maximum of 100 msec */
1024 const u32 nPollRate = 2; /* poll status bits every 2 ms */
1025 const u32 nMaxLoops = nMaxWait / nPollRate;
1026 const u8 LO1LK = 0x80;
1027 u8 LO2LK = 0x08;
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001028 u32 status;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001029 u32 nDelays = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001030
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001031 /* LO2 Lock bit was in a different place for B0 version */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001032 if (state->tuner_id == MT2063_B0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001033 LO2LK = 0x40;
1034
1035 do {
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001036 status = mt2063_read(state, MT2063_REG_LO_STATUS,
1037 &state->reg[MT2063_REG_LO_STATUS], 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001038
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001039 if (status < 0)
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001040 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001041
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001042 if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) ==
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001043 (LO1LK | LO2LK)) {
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001044 return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001045 }
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001046 msleep(nPollRate); /* Wait between retries */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001047 }
1048 while (++nDelays < nMaxLoops);
1049
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001050 /*
1051 * Got no lock or partial lock
1052 */
1053 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001054}
Mauro Carvalho Chehab3d497002011-07-21 11:00:59 -03001055EXPORT_SYMBOL_GPL(mt2063_lockStatus);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001056
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001057/*
1058 * mt2063_set_dnc_output_enable()
1059 */
1060static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state,
1061 enum MT2063_DNC_Output_Enable *pValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001062{
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001063 if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */
1064 if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
1065 *pValue = MT2063_DNC_NONE;
1066 else
1067 *pValue = MT2063_DNC_2;
1068 } else { /* DNC1 is on */
1069 if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
1070 *pValue = MT2063_DNC_1;
1071 else
1072 *pValue = MT2063_DNC_BOTH;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001073 }
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001074 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001075}
1076
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001077/*
1078 * mt2063_set_dnc_output_enable()
1079 */
1080static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state,
1081 enum MT2063_DNC_Output_Enable nValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001082{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001083 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001084 u8 val = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001085
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001086 /* selects, which DNC output is used */
1087 switch (nValue) {
1088 case MT2063_DNC_NONE:
1089 {
1090 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
1091 if (state->reg[MT2063_REG_DNC_GAIN] !=
1092 val)
1093 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001094 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001095 MT2063_REG_DNC_GAIN,
1096 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001097
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001098 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
1099 if (state->reg[MT2063_REG_VGA_GAIN] !=
1100 val)
1101 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001102 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001103 MT2063_REG_VGA_GAIN,
1104 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001105
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001106 val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
1107 if (state->reg[MT2063_REG_RSVD_20] !=
1108 val)
1109 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001110 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001111 MT2063_REG_RSVD_20,
1112 val);
1113
1114 break;
1115 }
1116 case MT2063_DNC_1:
1117 {
1118 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */
1119 if (state->reg[MT2063_REG_DNC_GAIN] !=
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_DNC_GAIN,
1124 val);
1125
1126 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
1127 if (state->reg[MT2063_REG_VGA_GAIN] !=
1128 val)
1129 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001130 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001131 MT2063_REG_VGA_GAIN,
1132 val);
1133
1134 val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
1135 if (state->reg[MT2063_REG_RSVD_20] !=
1136 val)
1137 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001138 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001139 MT2063_REG_RSVD_20,
1140 val);
1141
1142 break;
1143 }
1144 case MT2063_DNC_2:
1145 {
1146 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
1147 if (state->reg[MT2063_REG_DNC_GAIN] !=
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_DNC_GAIN,
1152 val);
1153
1154 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */
1155 if (state->reg[MT2063_REG_VGA_GAIN] !=
1156 val)
1157 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001158 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001159 MT2063_REG_VGA_GAIN,
1160 val);
1161
1162 val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
1163 if (state->reg[MT2063_REG_RSVD_20] !=
1164 val)
1165 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001166 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001167 MT2063_REG_RSVD_20,
1168 val);
1169
1170 break;
1171 }
1172 case MT2063_DNC_BOTH:
1173 {
1174 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */
1175 if (state->reg[MT2063_REG_DNC_GAIN] !=
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_DNC_GAIN,
1180 val);
1181
1182 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */
1183 if (state->reg[MT2063_REG_VGA_GAIN] !=
1184 val)
1185 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001186 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001187 MT2063_REG_VGA_GAIN,
1188 val);
1189
1190 val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
1191 if (state->reg[MT2063_REG_RSVD_20] !=
1192 val)
1193 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001194 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001195 MT2063_REG_RSVD_20,
1196 val);
1197
1198 break;
1199 }
1200 default:
1201 break;
1202 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001203
1204 return (status);
1205}
1206
1207/******************************************************************************
1208**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001209** Name: MT2063_SetReceiverMode
1210**
1211** Description: Set the MT2063 receiver mode
1212**
1213** --------------+----------------------------------------------
1214** Mode 0 : | MT2063_CABLE_QAM
1215** Mode 1 : | MT2063_CABLE_ANALOG
1216** Mode 2 : | MT2063_OFFAIR_COFDM
1217** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
1218** Mode 4 : | MT2063_OFFAIR_ANALOG
1219** Mode 5 : | MT2063_OFFAIR_8VSB
1220** --------------+----+----+----+----+-----+--------------------
1221** (DNC1GC & DNC2GC are the values, which are used, when the specific
1222** DNC Output is selected, the other is always off)
1223**
1224** |<---------- Mode -------------->|
1225** Reg Field | 0 | 1 | 2 | 3 | 4 | 5 |
1226** ------------+-----+-----+-----+-----+-----+-----+
1227** RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF
1228** LNARin | 0 | 0 | 3 | 3 | 3 | 3
1229** FIFFQen | 1 | 1 | 1 | 1 | 1 | 1
1230** FIFFq | 0 | 0 | 0 | 0 | 0 | 0
1231** DNC1gc | 0 | 0 | 0 | 0 | 0 | 0
1232** DNC2gc | 0 | 0 | 0 | 0 | 0 | 0
1233** GCU Auto | 1 | 1 | 1 | 1 | 1 | 1
1234** LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31
1235** LNA Target | 44 | 43 | 43 | 43 | 43 | 43
1236** ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0
1237** RF max Atn | 31 | 31 | 31 | 31 | 31 | 31
1238** PD1 Target | 36 | 36 | 38 | 38 | 36 | 38
1239** ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0
1240** FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5
1241** PD2 Target | 40 | 33 | 42 | 42 | 33 | 42
1242**
1243**
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001244** Parameters: state - ptr to mt2063_state structure
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001245** Mode - desired reciever mode
1246**
1247** Usage: status = MT2063_SetReceiverMode(hMT2063, Mode);
1248**
1249** Returns: status:
1250** MT_OK - No errors
1251** MT_COMM_ERR - Serial bus communications error
1252**
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001253** Dependencies: mt2063_setreg - Write a byte of data to a HW register.
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001254** Assumes that the tuner cache is valid.
1255**
1256** Revision History:
1257**
1258** SCR Date Author Description
1259** -------------------------------------------------------------------------
1260** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1261** N/A 01-10-2007 PINZ Added additional GCU Settings, FIFF Calib will be triggered
1262** 155 10-01-2007 DAD Ver 1.06: Add receiver mode for SECAM positive
1263** modulation
1264** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
1265** N/A 10-22-2007 PINZ Ver 1.07: Changed some Registers at init to have
1266** the same settings as with MT Launcher
1267** N/A 10-30-2007 PINZ Add SetParam VGAGC & VGAOI
1268** Add SetParam DNC_OUTPUT_ENABLE
1269** Removed VGAGC from receiver mode,
1270** default now 1
1271** N/A 10-31-2007 PINZ Ver 1.08: Add SetParam TAGC, removed from rcvr-mode
1272** Add SetParam AMPGC, removed from rcvr-mode
1273** Corrected names of GCU values
1274** reorganized receiver modes, removed,
1275** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
1276** Actualized Receiver-Mode values
1277** N/A 11-12-2007 PINZ Ver 1.09: Actualized Receiver-Mode values
1278** N/A 11-27-2007 PINZ Improved buffered writing
1279** 01-03-2008 PINZ Ver 1.10: Added a trigger of BYPATNUP for
1280** correct wakeup of the LNA after shutdown
1281** Set AFCsd = 1 as default
1282** Changed CAP1sel default
1283** 01-14-2008 PINZ Ver 1.11: Updated gain settings
1284** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
1285** Split SetParam up to ACLNA / ACLNA_MAX
1286** removed ACLNA_INRC/DECR (+RF & FIF)
1287** removed GCUAUTO / BYPATNDN/UP
1288**
1289******************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001290static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001291 enum MT2063_RCVR_MODES Mode)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001292{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001293 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001294 u8 val;
1295 u32 longval;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001296
1297 if (Mode >= MT2063_NUM_RCVR_MODES)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001298 status = -ERANGE;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001299
1300 /* RFAGCen */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001301 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001302 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001303 (state->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001304 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x40) | (RFAGCEN[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001305 ? 0x40 :
1306 0x00);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001307 if (state->reg[MT2063_REG_PD1_TGT] != val) {
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001308 status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001309 }
1310 }
1311
1312 /* LNARin */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001313 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001314 u8 val = (state-> reg[MT2063_REG_CTRL_2C] & (u8) ~ 0x03) |
1315 (LNARIN[Mode] & 0x03);
1316 if (state->reg[MT2063_REG_CTRL_2C] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001317 status |= mt2063_setreg(state, MT2063_REG_CTRL_2C,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001318 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001319 }
1320
1321 /* FIFFQEN and FIFFQ */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001322 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001323 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001324 (state->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001325 reg[MT2063_REG_FIFF_CTRL2] & (u8) ~ 0xF0) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001326 (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001327 if (state->reg[MT2063_REG_FIFF_CTRL2] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001328 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001329 mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001330 /* trigger FIFF calibration, needed after changing FIFFQ */
1331 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001332 (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001333 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001334 mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
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_CTRL] & (u8) ~ 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001338 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001339 mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001340 }
1341 }
1342
1343 /* DNC1GC & DNC2GC */
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001344 status |= mt2063_get_dnc_output_enable(state, &longval);
1345 status |= mt2063_set_dnc_output_enable(state, longval);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001346
1347 /* acLNAmax */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001348 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001349 u8 val = (state-> reg[MT2063_REG_LNA_OV] & (u8) ~ 0x1F) |
1350 (ACLNAMAX[Mode] & 0x1F);
1351 if (state->reg[MT2063_REG_LNA_OV] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001352 status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001353 }
1354
1355 /* LNATGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001356 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001357 u8 val = (state-> reg[MT2063_REG_LNA_TGT] & (u8) ~ 0x3F) |
1358 (LNATGT[Mode] & 0x3F);
1359 if (state->reg[MT2063_REG_LNA_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001360 status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001361 }
1362
1363 /* ACRF */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001364 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001365 u8 val = (state-> reg[MT2063_REG_RF_OV] & (u8) ~ 0x1F) |
1366 (ACRFMAX[Mode] & 0x1F);
1367 if (state->reg[MT2063_REG_RF_OV] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001368 status |= mt2063_setreg(state, MT2063_REG_RF_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001369 }
1370
1371 /* PD1TGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001372 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001373 u8 val = (state-> reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x3F) |
1374 (PD1TGT[Mode] & 0x3F);
1375 if (state->reg[MT2063_REG_PD1_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001376 status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001377 }
1378
1379 /* FIFATN */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001380 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001381 u8 val = ACFIFMAX[Mode];
1382 if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5)
1383 val = 5;
1384 val = (state-> reg[MT2063_REG_FIF_OV] & (u8) ~ 0x1F) |
1385 (val & 0x1F);
1386 if (state->reg[MT2063_REG_FIF_OV] != val) {
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001387 status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val);
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001388 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001389 }
1390
1391 /* PD2TGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001392 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001393 u8 val = (state-> reg[MT2063_REG_PD2_TGT] & (u8) ~ 0x3F) |
1394 (PD2TGT[Mode] & 0x3F);
1395 if (state->reg[MT2063_REG_PD2_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001396 status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001397 }
1398
1399 /* Ignore ATN Overload */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001400 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001401 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001402 (state->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001403 reg[MT2063_REG_LNA_TGT] & (u8) ~ 0x80) | (RFOVDIS[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001404 ? 0x80 :
1405 0x00);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001406 if (state->reg[MT2063_REG_LNA_TGT] != val) {
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001407 status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001408 }
1409 }
1410
1411 /* Ignore FIF 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_PD1_TGT] & (u8) ~ 0x80) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001416 (FIFOVDIS[Mode] ? 0x80 : 0x00);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001417 if (state->reg[MT2063_REG_PD1_TGT] != val) {
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001418 status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001419 }
1420 }
1421
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001422 if (status >= 0)
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001423 state->rcvr_mode = Mode;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001424
1425 return (status);
1426}
1427
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001428/****************************************************************************
1429**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001430** Name: MT2063_ClearPowerMaskBits
1431**
1432** Description: Clears the power-down mask bits for various sections of
1433** the MT2063
1434**
1435** Parameters: h - Tuner handle (returned by MT2063_Open)
1436** Bits - Mask bits to be cleared.
1437**
1438** See definition of MT2063_Mask_Bits type for description
1439** of each of the power bits.
1440**
1441** Returns: status:
1442** MT_OK - No errors
1443** MT_INV_HANDLE - Invalid tuner handle
1444** MT_COMM_ERR - Serial bus communications error
1445**
1446** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
1447**
1448** Revision History:
1449**
1450** SCR Date Author Description
1451** -------------------------------------------------------------------------
1452** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1453**
1454****************************************************************************/
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001455static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state,
1456 enum MT2063_Mask_Bits Bits)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001457{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001458 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001459
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001460 Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */
1461 if ((Bits & 0xFF00) != 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001462 state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001463 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001464 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001465 MT2063_REG_PWR_2,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001466 &state->reg[MT2063_REG_PWR_2], 1);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001467 }
1468 if ((Bits & 0xFF) != 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001469 state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001470 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001471 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001472 MT2063_REG_PWR_1,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001473 &state->reg[MT2063_REG_PWR_1], 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001474 }
1475
1476 return (status);
1477}
1478
1479/****************************************************************************
1480**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001481** Name: MT2063_SoftwareShutdown
1482**
1483** Description: Enables or disables software shutdown function. When
1484** Shutdown==1, any section whose power mask is set will be
1485** shutdown.
1486**
1487** Parameters: h - Tuner handle (returned by MT2063_Open)
1488** Shutdown - 1 = shutdown the masked sections, otherwise
1489** power all sections on
1490**
1491** Returns: status:
1492** MT_OK - No errors
1493** MT_INV_HANDLE - Invalid tuner handle
1494** MT_COMM_ERR - Serial bus communications error
1495**
1496** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
1497**
1498** Revision History:
1499**
1500** SCR Date Author Description
1501** -------------------------------------------------------------------------
1502** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1503** 01-03-2008 PINZ Ver 1.xx: Added a trigger of BYPATNUP for
1504** correct wakeup of the LNA
1505**
1506****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001507static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001508{
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001509 u32 status; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001510
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001511 if (Shutdown == 1)
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001512 state->reg[MT2063_REG_PWR_1] |= 0x04; /* Turn the bit on */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001513 else
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001514 state->reg[MT2063_REG_PWR_1] &= ~0x04; /* Turn off the bit */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001515
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001516 status = mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001517 MT2063_REG_PWR_1,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001518 &state->reg[MT2063_REG_PWR_1], 1);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001519
1520 if (Shutdown != 1) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001521 state->reg[MT2063_REG_BYP_CTRL] =
1522 (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001523 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001524 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001525 MT2063_REG_BYP_CTRL,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001526 &state->reg[MT2063_REG_BYP_CTRL],
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001527 1);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001528 state->reg[MT2063_REG_BYP_CTRL] =
1529 (state->reg[MT2063_REG_BYP_CTRL] & 0x9F);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001530 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001531 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001532 MT2063_REG_BYP_CTRL,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001533 &state->reg[MT2063_REG_BYP_CTRL],
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001534 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001535 }
1536
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001537 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001538}
1539
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001540static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001541{
1542 return f_ref * (f_LO / f_ref)
1543 + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step);
1544}
1545
1546/****************************************************************************
1547**
1548** Name: fLO_FractionalTerm
1549**
1550** Description: Calculates the portion contributed by FracN / denom.
1551**
1552** This function preserves maximum precision without
1553** risk of overflow. It accurately calculates
1554** f_ref * num / denom to within 1 HZ with fixed math.
1555**
1556** Parameters: num - Fractional portion of the multiplier
1557** denom - denominator portion of the ratio
1558** This routine successfully handles denom values
1559** up to and including 2^18.
1560** f_Ref - SRO frequency. This calculation handles
1561** f_ref as two separate 14-bit fields.
1562** Therefore, a maximum value of 2^28-1
1563** may safely be used for f_ref. This is
1564** the genesis of the magic number "14" and the
1565** magic mask value of 0x03FFF.
1566**
1567** Returns: f_ref * num / denom
1568**
1569** Revision History:
1570**
1571** SCR Date Author Description
1572** -------------------------------------------------------------------------
1573** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1574**
1575****************************************************************************/
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001576static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001577{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001578 u32 t1 = (f_ref >> 14) * num;
1579 u32 term1 = t1 / denom;
1580 u32 loss = t1 % denom;
1581 u32 term2 =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001582 (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom;
1583 return ((term1 << 14) + term2);
1584}
1585
1586/****************************************************************************
1587**
1588** Name: CalcLO1Mult
1589**
1590** Description: Calculates Integer divider value and the numerator
1591** value for a FracN PLL.
1592**
1593** This function assumes that the f_LO and f_Ref are
1594** evenly divisible by f_LO_Step.
1595**
1596** Parameters: Div - OUTPUT: Whole number portion of the multiplier
1597** FracN - OUTPUT: Fractional portion of the multiplier
1598** f_LO - desired LO frequency.
1599** f_LO_Step - Minimum step size for the LO (in Hz).
1600** f_Ref - SRO frequency.
1601** f_Avoid - Range of PLL frequencies to avoid near
1602** integer multiples of f_Ref (in Hz).
1603**
1604** Returns: Recalculated LO frequency.
1605**
1606** Revision History:
1607**
1608** SCR Date Author Description
1609** -------------------------------------------------------------------------
1610** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1611**
1612****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001613static u32 MT2063_CalcLO1Mult(u32 * Div,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001614 u32 * FracN,
1615 u32 f_LO,
1616 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001617{
1618 /* Calculate the whole number portion of the divider */
1619 *Div = f_LO / f_Ref;
1620
1621 /* Calculate the numerator value (round to nearest f_LO_Step) */
1622 *FracN =
1623 (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
1624 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
1625
1626 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64);
1627}
1628
1629/****************************************************************************
1630**
1631** Name: CalcLO2Mult
1632**
1633** Description: Calculates Integer divider value and the numerator
1634** value for a FracN PLL.
1635**
1636** This function assumes that the f_LO and f_Ref are
1637** evenly divisible by f_LO_Step.
1638**
1639** Parameters: Div - OUTPUT: Whole number portion of the multiplier
1640** FracN - OUTPUT: Fractional portion of the multiplier
1641** f_LO - desired LO frequency.
1642** f_LO_Step - Minimum step size for the LO (in Hz).
1643** f_Ref - SRO frequency.
1644** f_Avoid - Range of PLL frequencies to avoid near
1645** integer multiples of f_Ref (in Hz).
1646**
1647** Returns: Recalculated LO frequency.
1648**
1649** Revision History:
1650**
1651** SCR Date Author Description
1652** -------------------------------------------------------------------------
1653** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1654**
1655****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001656static u32 MT2063_CalcLO2Mult(u32 * Div,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001657 u32 * FracN,
1658 u32 f_LO,
1659 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001660{
1661 /* Calculate the whole number portion of the divider */
1662 *Div = f_LO / f_Ref;
1663
1664 /* Calculate the numerator value (round to nearest f_LO_Step) */
1665 *FracN =
1666 (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
1667 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
1668
1669 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN,
1670 8191);
1671}
1672
1673/****************************************************************************
1674**
1675** Name: FindClearTuneFilter
1676**
1677** Description: Calculate the corrrect ClearTune filter to be used for
1678** a given input frequency.
1679**
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001680** Parameters: state - ptr to tuner data structure
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001681** f_in - RF input center frequency (in Hz).
1682**
1683** Returns: ClearTune filter number (0-31)
1684**
1685** Dependencies: MUST CALL MT2064_Open BEFORE FindClearTuneFilter!
1686**
1687** Revision History:
1688**
1689** SCR Date Author Description
1690** -------------------------------------------------------------------------
1691** 04-10-2008 PINZ Ver 1.14: Use software-controlled ClearTune
1692** cross-over frequency values.
1693**
1694****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001695static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001696{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001697 u32 RFBand;
1698 u32 idx; /* index loop */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001699
1700 /*
1701 ** Find RF Band setting
1702 */
1703 RFBand = 31; /* def when f_in > all */
1704 for (idx = 0; idx < 31; ++idx) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001705 if (state->CTFiltMax[idx] >= f_in) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001706 RFBand = idx;
1707 break;
1708 }
1709 }
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001710 return RFBand;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001711}
1712
1713/****************************************************************************
1714**
1715** Name: MT2063_Tune
1716**
1717** Description: Change the tuner's tuned frequency to RFin.
1718**
1719** Parameters: h - Open handle to the tuner (from MT2063_Open).
1720** f_in - RF input center frequency (in Hz).
1721**
1722** Returns: status:
1723** MT_OK - No errors
1724** MT_INV_HANDLE - Invalid tuner handle
1725** MT_UPC_UNLOCK - Upconverter PLL unlocked
1726** MT_DNC_UNLOCK - Downconverter PLL unlocked
1727** MT_COMM_ERR - Serial bus communications error
1728** MT_SPUR_CNT_MASK - Count of avoided LO spurs
1729** MT_SPUR_PRESENT - LO spur possible in output
1730** MT_FIN_RANGE - Input freq out of range
1731** MT_FOUT_RANGE - Output freq out of range
1732** MT_UPC_RANGE - Upconverter freq out of range
1733** MT_DNC_RANGE - Downconverter freq out of range
1734**
1735** Dependencies: MUST CALL MT2063_Open BEFORE MT2063_Tune!
1736**
1737** MT_ReadSub - Read data from the two-wire serial bus
1738** MT_WriteSub - Write data to the two-wire serial bus
1739** MT_Sleep - Delay execution for x milliseconds
1740** MT2063_GetLocked - Checks to see if LO1 and LO2 are locked
1741**
1742** Revision History:
1743**
1744** SCR Date Author Description
1745** -------------------------------------------------------------------------
1746** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1747** 04-10-2008 PINZ Ver 1.05: Use software-controlled ClearTune
1748** cross-over frequency values.
1749** 175 I 16-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
1750** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
1751** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
1752**
1753****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001754static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001755{ /* RF input center frequency */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001756
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001757 u32 status = 0; /* status of operation */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001758 u32 LO1; /* 1st LO register value */
1759 u32 Num1; /* Numerator for LO1 reg. value */
1760 u32 f_IF1; /* 1st IF requested */
1761 u32 LO2; /* 2nd LO register value */
1762 u32 Num2; /* Numerator for LO2 reg. value */
1763 u32 ofLO1, ofLO2; /* last time's LO frequencies */
1764 u32 ofin, ofout; /* last time's I/O frequencies */
1765 u8 fiffc = 0x80; /* FIFF center freq from tuner */
1766 u32 fiffof; /* Offset from FIFF center freq */
1767 const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */
1768 u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */
1769 u8 val;
1770 u32 RFBand;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001771
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001772 /* Check the input and output frequency ranges */
1773 if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ))
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001774 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001775
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001776 if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ)
1777 || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ))
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001778 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001779
1780 /*
1781 ** Save original LO1 and LO2 register values
1782 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001783 ofLO1 = state->AS_Data.f_LO1;
1784 ofLO2 = state->AS_Data.f_LO2;
1785 ofin = state->AS_Data.f_in;
1786 ofout = state->AS_Data.f_out;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001787
1788 /*
1789 ** Find and set RF Band setting
1790 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001791 if (state->ctfilt_sw == 1) {
1792 val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08);
1793 if (state->reg[MT2063_REG_CTUNE_CTRL] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001794 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001795 mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001796 }
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001797 val = state->reg[MT2063_REG_CTUNE_OV];
1798 RFBand = FindClearTuneFilter(state, f_in);
1799 state->reg[MT2063_REG_CTUNE_OV] =
1800 (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001801 | RFBand);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001802 if (state->reg[MT2063_REG_CTUNE_OV] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001803 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001804 mt2063_setreg(state, MT2063_REG_CTUNE_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001805 }
1806 }
1807
1808 /*
1809 ** Read the FIFF Center Frequency from the tuner
1810 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001811 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001812 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001813 mt2063_read(state,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001814 MT2063_REG_FIFFC,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001815 &state->reg[MT2063_REG_FIFFC], 1);
1816 fiffc = state->reg[MT2063_REG_FIFFC];
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001817 }
1818 /*
1819 ** Assign in the requested values
1820 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001821 state->AS_Data.f_in = f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001822 /* Request a 1st IF such that LO1 is on a step size */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001823 state->AS_Data.f_if1_Request =
1824 MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in,
1825 state->AS_Data.f_LO1_Step,
1826 state->AS_Data.f_ref) - f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001827
1828 /*
1829 ** Calculate frequency settings. f_IF1_FREQ + f_in is the
1830 ** desired LO1 frequency
1831 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001832 MT2063_ResetExclZones(&state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001833
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001834 f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001835
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001836 state->AS_Data.f_LO1 =
1837 MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step,
1838 state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001839
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001840 state->AS_Data.f_LO2 =
1841 MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
1842 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001843
1844 /*
1845 ** Check for any LO spurs in the output bandwidth and adjust
1846 ** the LO settings to avoid them if needed
1847 */
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001848 status |= MT2063_AvoidSpurs(&state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001849 /*
1850 ** MT_AvoidSpurs spurs may have changed the LO1 & LO2 values.
1851 ** Recalculate the LO frequencies and the values to be placed
1852 ** in the tuning registers.
1853 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001854 state->AS_Data.f_LO1 =
1855 MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1,
1856 state->AS_Data.f_LO1_Step, state->AS_Data.f_ref);
1857 state->AS_Data.f_LO2 =
1858 MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
1859 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
1860 state->AS_Data.f_LO2 =
1861 MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2,
1862 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001863
1864 /*
1865 ** Check the upconverter and downconverter frequency ranges
1866 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001867 if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ)
1868 || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001869 status |= MT2063_UPC_RANGE;
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001870 if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ)
1871 || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001872 status |= MT2063_DNC_RANGE;
1873 /* LO2 Lock bit was in a different place for B0 version */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001874 if (state->tuner_id == MT2063_B0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001875 LO2LK = 0x40;
1876
1877 /*
1878 ** If we have the same LO frequencies and we're already locked,
1879 ** then skip re-programming the LO registers.
1880 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001881 if ((ofLO1 != state->AS_Data.f_LO1)
1882 || (ofLO2 != state->AS_Data.f_LO2)
1883 || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) !=
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001884 (LO1LK | LO2LK))) {
1885 /*
1886 ** Calculate the FIFFOF register value
1887 **
1888 ** IF1_Actual
1889 ** FIFFOF = ------------ - 8 * FIFFC - 4992
1890 ** f_ref/64
1891 */
1892 fiffof =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001893 (state->AS_Data.f_LO1 -
1894 f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc -
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001895 4992;
1896 if (fiffof > 0xFF)
1897 fiffof = 0xFF;
1898
1899 /*
1900 ** Place all of the calculated values into the local tuner
1901 ** register fields.
1902 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001903 if (status >= 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001904 state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */
1905 state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */
1906 state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001907 |(Num2 >> 12)); /* NUM2q (hi) */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001908 state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */
1909 state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001910
1911 /*
1912 ** Now write out the computed register values
1913 ** IMPORTANT: There is a required order for writing
1914 ** (0x05 must follow all the others).
1915 */
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001916 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 -03001917 if (state->tuner_id == MT2063_B0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001918 /* Re-write the one-shot bits to trigger the tune operation */
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001919 status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001920 }
1921 /* Write out the FIFF offset only if it's changing */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001922 if (state->reg[MT2063_REG_FIFF_OFFSET] !=
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001923 (u8) fiffof) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001924 state->reg[MT2063_REG_FIFF_OFFSET] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001925 (u8) fiffof;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001926 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001927 mt2063_write(state,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001928 MT2063_REG_FIFF_OFFSET,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001929 &state->
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001930 reg[MT2063_REG_FIFF_OFFSET],
1931 1);
1932 }
1933 }
1934
1935 /*
1936 ** Check for LO's locking
1937 */
1938
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001939 if (status < 0)
1940 return status;
1941
1942 status = mt2063_lockStatus(state);
1943 if (status < 0)
1944 return status;
1945 if (!status)
1946 return -EINVAL; /* Couldn't lock */
1947
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001948 /*
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001949 * If we locked OK, assign calculated data to mt2063_state structure
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001950 */
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001951 state->f_IF1_actual = state->AS_Data.f_LO1 - f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001952 }
1953
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001954 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001955}
1956
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001957int mt2063_setTune(struct dvb_frontend *fe, u32 f_in, u32 bw_in,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001958 enum MTTune_atv_standard tv_type)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001959{
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001960 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001961 u32 status = 0;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001962 s32 pict_car = 0;
1963 s32 pict2chanb_vsb = 0;
1964 s32 pict2chanb_snd = 0;
1965 s32 pict2snd1 = 0;
1966 s32 pict2snd2 = 0;
1967 s32 ch_bw = 0;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001968 s32 if_mid = 0;
1969 s32 rcvr_mode = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001970
1971 switch (tv_type) {
1972 case MTTUNEA_PAL_B:{
1973 pict_car = 38900000;
1974 ch_bw = 8000000;
1975 pict2chanb_vsb = -1250000;
1976 pict2snd1 = 5500000;
1977 pict2snd2 = 5742000;
1978 rcvr_mode = 1;
1979 break;
1980 }
1981 case MTTUNEA_PAL_G:{
1982 pict_car = 38900000;
1983 ch_bw = 7000000;
1984 pict2chanb_vsb = -1250000;
1985 pict2snd1 = 5500000;
1986 pict2snd2 = 0;
1987 rcvr_mode = 1;
1988 break;
1989 }
1990 case MTTUNEA_PAL_I:{
1991 pict_car = 38900000;
1992 ch_bw = 8000000;
1993 pict2chanb_vsb = -1250000;
1994 pict2snd1 = 6000000;
1995 pict2snd2 = 0;
1996 rcvr_mode = 1;
1997 break;
1998 }
1999 case MTTUNEA_PAL_L:{
2000 pict_car = 38900000;
2001 ch_bw = 8000000;
2002 pict2chanb_vsb = -1250000;
2003 pict2snd1 = 6500000;
2004 pict2snd2 = 0;
2005 rcvr_mode = 1;
2006 break;
2007 }
2008 case MTTUNEA_PAL_MN:{
2009 pict_car = 38900000;
2010 ch_bw = 6000000;
2011 pict2chanb_vsb = -1250000;
2012 pict2snd1 = 4500000;
2013 pict2snd2 = 0;
2014 rcvr_mode = 1;
2015 break;
2016 }
2017 case MTTUNEA_PAL_DK:{
2018 pict_car = 38900000;
2019 ch_bw = 8000000;
2020 pict2chanb_vsb = -1250000;
2021 pict2snd1 = 6500000;
2022 pict2snd2 = 0;
2023 rcvr_mode = 1;
2024 break;
2025 }
2026 case MTTUNEA_DIGITAL:{
2027 pict_car = 36125000;
2028 ch_bw = 8000000;
2029 pict2chanb_vsb = -(ch_bw / 2);
2030 pict2snd1 = 0;
2031 pict2snd2 = 0;
2032 rcvr_mode = 2;
2033 break;
2034 }
2035 case MTTUNEA_FMRADIO:{
2036 pict_car = 38900000;
2037 ch_bw = 8000000;
2038 pict2chanb_vsb = -(ch_bw / 2);
2039 pict2snd1 = 0;
2040 pict2snd2 = 0;
2041 rcvr_mode = 4;
2042 //f_in -= 2900000;
2043 break;
2044 }
2045 case MTTUNEA_DVBC:{
2046 pict_car = 36125000;
2047 ch_bw = 8000000;
2048 pict2chanb_vsb = -(ch_bw / 2);
2049 pict2snd1 = 0;
2050 pict2snd2 = 0;
2051 rcvr_mode = MT2063_CABLE_QAM;
2052 break;
2053 }
2054 case MTTUNEA_DVBT:{
2055 pict_car = 36125000;
2056 ch_bw = bw_in; //8000000
2057 pict2chanb_vsb = -(ch_bw / 2);
2058 pict2snd1 = 0;
2059 pict2snd2 = 0;
2060 rcvr_mode = MT2063_OFFAIR_COFDM;
2061 break;
2062 }
2063 case MTTUNEA_UNKNOWN:
2064 break;
2065 default:
2066 break;
2067 }
2068
2069 pict2chanb_snd = pict2chanb_vsb - ch_bw;
2070 if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
2071
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03002072 state->AS_Data.f_LO2_Step = 125000;
2073 state->AS_Data.f_out = if_mid;
2074 state->AS_Data.f_out_bw = ch_bw + 750000;
2075 status = MT2063_SetReceiverMode(state, rcvr_mode);
2076 if (status < 0)
2077 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002078
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03002079 status = MT2063_Tune(state, (f_in + (pict2chanb_vsb + (ch_bw / 2))));
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002080
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03002081 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002082}
2083
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002084static const u8 MT2063B0_defaults[] = {
2085 /* Reg, Value */
2086 0x19, 0x05,
2087 0x1B, 0x1D,
2088 0x1C, 0x1F,
2089 0x1D, 0x0F,
2090 0x1E, 0x3F,
2091 0x1F, 0x0F,
2092 0x20, 0x3F,
2093 0x22, 0x21,
2094 0x23, 0x3F,
2095 0x24, 0x20,
2096 0x25, 0x3F,
2097 0x27, 0xEE,
2098 0x2C, 0x27, /* bit at 0x20 is cleared below */
2099 0x30, 0x03,
2100 0x2C, 0x07, /* bit at 0x20 is cleared here */
2101 0x2D, 0x87,
2102 0x2E, 0xAA,
2103 0x28, 0xE1, /* Set the FIFCrst bit here */
2104 0x28, 0xE0, /* Clear the FIFCrst bit here */
2105 0x00
2106};
2107
2108/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
2109static const u8 MT2063B1_defaults[] = {
2110 /* Reg, Value */
2111 0x05, 0xF0,
2112 0x11, 0x10, /* New Enable AFCsd */
2113 0x19, 0x05,
2114 0x1A, 0x6C,
2115 0x1B, 0x24,
2116 0x1C, 0x28,
2117 0x1D, 0x8F,
2118 0x1E, 0x14,
2119 0x1F, 0x8F,
2120 0x20, 0x57,
2121 0x22, 0x21, /* New - ver 1.03 */
2122 0x23, 0x3C, /* New - ver 1.10 */
2123 0x24, 0x20, /* New - ver 1.03 */
2124 0x2C, 0x24, /* bit at 0x20 is cleared below */
2125 0x2D, 0x87, /* FIFFQ=0 */
2126 0x2F, 0xF3,
2127 0x30, 0x0C, /* New - ver 1.11 */
2128 0x31, 0x1B, /* New - ver 1.11 */
2129 0x2C, 0x04, /* bit at 0x20 is cleared here */
2130 0x28, 0xE1, /* Set the FIFCrst bit here */
2131 0x28, 0xE0, /* Clear the FIFCrst bit here */
2132 0x00
2133};
2134
2135/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
2136static const u8 MT2063B3_defaults[] = {
2137 /* Reg, Value */
2138 0x05, 0xF0,
2139 0x19, 0x3D,
2140 0x2C, 0x24, /* bit at 0x20 is cleared below */
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
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002147static int mt2063_init(struct dvb_frontend *fe)
2148{
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002149 u32 status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002150 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002151 u8 all_resets = 0xF0; /* reset/load bits */
2152 const u8 *def = NULL;
2153 u32 FCRUN;
2154 s32 maxReads;
2155 u32 fcu_osc;
2156 u32 i;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002157
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002158 state->rcvr_mode = MT2063_CABLE_QAM;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002159
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002160 /* Read the Part/Rev code from the tuner */
2161 status = mt2063_read(state, MT2063_REG_PART_REV, state->reg, 1);
2162 if (status < 0)
2163 return status;
2164
2165 /* Check the part/rev code */
2166 if (((state->reg[MT2063_REG_PART_REV] != MT2063_B0) /* MT2063 B0 */
2167 &&(state->reg[MT2063_REG_PART_REV] != MT2063_B1) /* MT2063 B1 */
2168 &&(state->reg[MT2063_REG_PART_REV] != MT2063_B3))) /* MT2063 B3 */
2169 return -ENODEV; /* Wrong tuner Part/Rev code */
2170
2171 /* Check the 2nd byte of the Part/Rev code from the tuner */
2172 status = mt2063_read(state, MT2063_REG_RSVD_3B,
2173 &state->reg[MT2063_REG_RSVD_3B], 1);
2174
2175 /* b7 != 0 ==> NOT MT2063 */
2176 if (status < 0 ||((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00))
2177 return -ENODEV; /* Wrong tuner Part/Rev code */
2178
2179 /* Reset the tuner */
2180 status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1);
2181 if (status < 0)
2182 return status;
2183
2184 /* change all of the default values that vary from the HW reset values */
2185 /* def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */
2186 switch (state->reg[MT2063_REG_PART_REV]) {
2187 case MT2063_B3:
2188 def = MT2063B3_defaults;
2189 break;
2190
2191 case MT2063_B1:
2192 def = MT2063B1_defaults;
2193 break;
2194
2195 case MT2063_B0:
2196 def = MT2063B0_defaults;
2197 break;
2198
2199 default:
2200 return -ENODEV;
2201 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002202 }
2203
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002204 while (status >= 0 && *def) {
2205 u8 reg = *def++;
2206 u8 val = *def++;
2207 status = mt2063_write(state, reg, &val, 1);
2208 }
2209 if (status < 0)
2210 return status;
2211
2212 /* Wait for FIFF location to complete. */
2213 FCRUN = 1;
2214 maxReads = 10;
2215 while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) {
2216 msleep(2);
2217 status = mt2063_read(state,
2218 MT2063_REG_XO_STATUS,
2219 &state->
2220 reg[MT2063_REG_XO_STATUS], 1);
2221 FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6;
2222 }
2223
2224 if (FCRUN != 0 || status < 0)
2225 return -ENODEV;
2226
2227 status = mt2063_read(state,
2228 MT2063_REG_FIFFC,
2229 &state->reg[MT2063_REG_FIFFC], 1);
2230 if (status < 0)
2231 return status;
2232
2233 /* Read back all the registers from the tuner */
2234 status = mt2063_read(state,
2235 MT2063_REG_PART_REV,
2236 state->reg, MT2063_REG_END_REGS);
2237 if (status < 0)
2238 return status;
2239
2240 /* Initialize the tuner state. */
2241 state->tuner_id = state->reg[MT2063_REG_PART_REV];
2242 state->AS_Data.f_ref = MT2063_REF_FREQ;
2243 state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) *
2244 ((u32) state->reg[MT2063_REG_FIFFC] + 640);
2245 state->AS_Data.f_if1_bw = MT2063_IF1_BW;
2246 state->AS_Data.f_out = 43750000UL;
2247 state->AS_Data.f_out_bw = 6750000UL;
2248 state->AS_Data.f_zif_bw = MT2063_ZIF_BW;
2249 state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64;
2250 state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE;
2251 state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1;
2252 state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2;
2253 state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP;
2254 state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center;
2255 state->AS_Data.f_LO1 = 2181000000UL;
2256 state->AS_Data.f_LO2 = 1486249786UL;
2257 state->f_IF1_actual = state->AS_Data.f_if1_Center;
2258 state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual;
2259 state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID;
2260 state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID;
2261 state->num_regs = MT2063_REG_END_REGS;
2262 state->AS_Data.avoidDECT = MT2063_AVOID_BOTH;
2263 state->ctfilt_sw = 0;
2264
2265 state->CTFiltMax[0] = 69230000;
2266 state->CTFiltMax[1] = 105770000;
2267 state->CTFiltMax[2] = 140350000;
2268 state->CTFiltMax[3] = 177110000;
2269 state->CTFiltMax[4] = 212860000;
2270 state->CTFiltMax[5] = 241130000;
2271 state->CTFiltMax[6] = 274370000;
2272 state->CTFiltMax[7] = 309820000;
2273 state->CTFiltMax[8] = 342450000;
2274 state->CTFiltMax[9] = 378870000;
2275 state->CTFiltMax[10] = 416210000;
2276 state->CTFiltMax[11] = 456500000;
2277 state->CTFiltMax[12] = 495790000;
2278 state->CTFiltMax[13] = 534530000;
2279 state->CTFiltMax[14] = 572610000;
2280 state->CTFiltMax[15] = 598970000;
2281 state->CTFiltMax[16] = 635910000;
2282 state->CTFiltMax[17] = 672130000;
2283 state->CTFiltMax[18] = 714840000;
2284 state->CTFiltMax[19] = 739660000;
2285 state->CTFiltMax[20] = 770410000;
2286 state->CTFiltMax[21] = 814660000;
2287 state->CTFiltMax[22] = 846950000;
2288 state->CTFiltMax[23] = 867820000;
2289 state->CTFiltMax[24] = 915980000;
2290 state->CTFiltMax[25] = 947450000;
2291 state->CTFiltMax[26] = 983110000;
2292 state->CTFiltMax[27] = 1021630000;
2293 state->CTFiltMax[28] = 1061870000;
2294 state->CTFiltMax[29] = 1098330000;
2295 state->CTFiltMax[30] = 1138990000;
2296
2297 /*
2298 ** Fetch the FCU osc value and use it and the fRef value to
2299 ** scale all of the Band Max values
2300 */
2301
2302 state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A;
2303 status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
2304 &state->reg[MT2063_REG_CTUNE_CTRL], 1);
2305 if (status < 0)
2306 return status;
2307
2308 /* Read the ClearTune filter calibration value */
2309 status = mt2063_read(state, MT2063_REG_FIFFC,
2310 &state->reg[MT2063_REG_FIFFC], 1);
2311 if (status < 0)
2312 return status;
2313
2314 fcu_osc = state->reg[MT2063_REG_FIFFC];
2315
2316 state->reg[MT2063_REG_CTUNE_CTRL] = 0x00;
2317 status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
2318 &state->reg[MT2063_REG_CTUNE_CTRL], 1);
2319 if (status < 0)
2320 return status;
2321
2322 /* Adjust each of the values in the ClearTune filter cross-over table */
2323 for (i = 0; i < 31; i++)
2324 state->CTFiltMax[i] =(state->CTFiltMax[i] / 768) * (fcu_osc + 640);
2325
2326 status = MT2063_SoftwareShutdown(state, 1);
2327 if (status < 0)
2328 return status;
2329 status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
2330 if (status < 0)
2331 return status;
2332
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002333 return 0;
2334}
2335
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002336static int mt2063_get_status(struct dvb_frontend *fe, u32 * status)
2337{
2338 int rc = 0;
2339
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03002340 /* FIXME: add get tuner lock status */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002341
2342 return rc;
2343}
2344
2345static int mt2063_get_state(struct dvb_frontend *fe,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002346 enum tuner_param param, struct tuner_state *tunstate)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002347{
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002348 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002349
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002350 switch (param) {
2351 case DVBFE_TUNER_FREQUENCY:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002352 //get frequency
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002353 break;
2354 case DVBFE_TUNER_TUNERSTEP:
2355 break;
2356 case DVBFE_TUNER_IFFREQ:
2357 break;
2358 case DVBFE_TUNER_BANDWIDTH:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002359 //get bandwidth
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002360 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002361 case DVBFE_TUNER_REFCLOCK:
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03002362 tunstate->refclock = mt2063_lockStatus(state);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002363 break;
2364 default:
2365 break;
2366 }
2367
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002368 return (int)tunstate->refclock;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002369}
2370
2371static int mt2063_set_state(struct dvb_frontend *fe,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002372 enum tuner_param param, struct tuner_state *tunstate)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002373{
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002374 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002375 u32 status = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002376
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002377 switch (param) {
2378 case DVBFE_TUNER_FREQUENCY:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002379 //set frequency
2380
2381 status =
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03002382 mt2063_setTune(fe,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002383 tunstate->frequency, tunstate->bandwidth,
2384 state->tv_type);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002385
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002386 state->frequency = tunstate->frequency;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002387 break;
2388 case DVBFE_TUNER_TUNERSTEP:
2389 break;
2390 case DVBFE_TUNER_IFFREQ:
2391 break;
2392 case DVBFE_TUNER_BANDWIDTH:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002393 //set bandwidth
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002394 state->bandwidth = tunstate->bandwidth;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002395 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002396 case DVBFE_TUNER_REFCLOCK:
2397
2398 break;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002399 default:
2400 break;
2401 }
2402
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002403 return (int)status;
2404}
2405
2406static int mt2063_release(struct dvb_frontend *fe)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002407{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002408 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002409
2410 fe->tuner_priv = NULL;
2411 kfree(state);
2412
2413 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002414}
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002415
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002416static struct dvb_tuner_ops mt2063_ops = {
2417 .info = {
2418 .name = "MT2063 Silicon Tuner",
2419 .frequency_min = 45000000,
2420 .frequency_max = 850000000,
2421 .frequency_step = 0,
2422 },
2423
2424 .init = mt2063_init,
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002425 .sleep = MT2063_Sleep,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002426 .get_status = mt2063_get_status,
2427 .get_state = mt2063_get_state,
2428 .set_state = mt2063_set_state,
2429 .release = mt2063_release
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002430};
2431
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002432struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
2433 struct mt2063_config *config,
2434 struct i2c_adapter *i2c)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002435{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002436 struct mt2063_state *state = NULL;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002437
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002438 state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002439 if (state == NULL)
2440 goto error;
2441
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002442 state->config = config;
2443 state->i2c = i2c;
2444 state->frontend = fe;
2445 state->reference = config->refclock / 1000; /* kHz */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002446 fe->tuner_priv = state;
2447 fe->ops.tuner_ops = mt2063_ops;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002448
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002449 printk("%s: Attaching MT2063 \n", __func__);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002450 return fe;
2451
2452error:
2453 kfree(state);
2454 return NULL;
2455}
Mauro Carvalho Chehab3d497002011-07-21 11:00:59 -03002456EXPORT_SYMBOL_GPL(mt2063_attach);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002457
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03002458/*
2459 * Ancillary routines visible outside mt2063
2460 * FIXME: Remove them in favor of using standard tuner callbacks
2461 */
2462unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe)
2463{
2464 struct mt2063_state *state = fe->tuner_priv;
2465 int err = 0;
2466
2467 err = MT2063_SoftwareShutdown(state, 1);
2468 if (err < 0)
2469 printk(KERN_ERR "%s: Couldn't shutdown\n", __func__);
2470
2471 return err;
2472}
2473EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown);
2474
2475unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe)
2476{
2477 struct mt2063_state *state = fe->tuner_priv;
2478 int err = 0;
2479
2480 err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
2481 if (err < 0)
2482 printk(KERN_ERR "%s: Invalid parameter\n", __func__);
2483
2484 return err;
2485}
2486EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits);
2487
2488
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002489MODULE_PARM_DESC(verbose, "Set Verbosity level");
2490
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002491MODULE_AUTHOR("Henry");
2492MODULE_DESCRIPTION("MT2063 Silicon tuner");
2493MODULE_LICENSE("GPL");