blob: 0c4ae7f15c459f5bf03cb08b2716c6ddda1960a2 [file] [log] [blame]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002#include <linux/init.h>
3#include <linux/kernel.h>
4#include <linux/module.h>
5#include <linux/string.h>
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03006
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03007#include "mt2063.h"
8
9/* Version of this module */
10#define MT2063_VERSION 10018 /* Version 01.18 */
11
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -030012static unsigned int verbose;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -030013module_param(verbose, int, 0644);
14
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030015/* Internal structures and types */
16
17#define DVBFE_TUNER_OPEN 99
18#define DVBFE_TUNER_SOFTWARE_SHUTDOWN 100
19#define DVBFE_TUNER_CLEAR_POWER_MASKBITS 101
20
21#define MT2063_ERROR (1 << 31)
22#define MT2063_USER_ERROR (1 << 30)
23
24/* Macro to be used to check for errors */
25#define MT2063_IS_ERROR(s) (((s) >> 30) != 0)
26#define MT2063_NO_ERROR(s) (((s) >> 30) == 0)
27
28#define MT2063_OK (0x00000000)
29
30/* Unknown error */
31#define MT2063_UNKNOWN (0x80000001)
32
33/* Error: Upconverter PLL is not locked */
34#define MT2063_UPC_UNLOCK (0x80000002)
35
36/* Error: Downconverter PLL is not locked */
37#define MT2063_DNC_UNLOCK (0x80000004)
38
39/* Error: Two-wire serial bus communications error */
40#define MT2063_COMM_ERR (0x80000008)
41
42/* Error: Tuner handle passed to function was invalid */
43#define MT2063_INV_HANDLE (0x80000010)
44
45/* Error: Function argument is invalid (out of range) */
46#define MT2063_ARG_RANGE (0x80000020)
47
48/* Error: Function argument (ptr to return value) was NULL */
49#define MT2063_ARG_NULL (0x80000040)
50
51/* Error: Attempt to open more than MT_TUNER_CNT tuners */
52#define MT2063_TUNER_CNT_ERR (0x80000080)
53
54/* Error: Tuner Part Code / Rev Code mismatches expected value */
55#define MT2063_TUNER_ID_ERR (0x80000100)
56
57/* Error: Tuner Initialization failure */
58#define MT2063_TUNER_INIT_ERR (0x80000200)
59
60#define MT2063_TUNER_OPEN_ERR (0x80000400)
61
62/* User-definable fields (see mt_userdef.h) */
63#define MT2063_USER_DEFINED1 (0x00001000)
64#define MT2063_USER_DEFINED2 (0x00002000)
65#define MT2063_USER_DEFINED3 (0x00004000)
66#define MT2063_USER_DEFINED4 (0x00008000)
67#define MT2063_USER_MASK (0x4000f000)
68#define MT2063_USER_SHIFT (12)
69
70/* Info: Mask of bits used for # of LO-related spurs that were avoided during tuning */
71#define MT2063_SPUR_CNT_MASK (0x001f0000)
72#define MT2063_SPUR_SHIFT (16)
73
74/* Info: Tuner timeout waiting for condition */
75#define MT2063_TUNER_TIMEOUT (0x00400000)
76
77/* Info: Unavoidable LO-related spur may be present in the output */
78#define MT2063_SPUR_PRESENT_ERR (0x00800000)
79
80/* Info: Tuner input frequency is out of range */
81#define MT2063_FIN_RANGE (0x01000000)
82
83/* Info: Tuner output frequency is out of range */
84#define MT2063_FOUT_RANGE (0x02000000)
85
86/* Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */
87#define MT2063_UPC_RANGE (0x04000000)
88
89/* Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */
90#define MT2063_DNC_RANGE (0x08000000)
91
92/*
93 * Data Types
94 */
95
96#define MAX_UDATA (4294967295) /* max value storable in u32 */
97
98/*
99 * Define an MTxxxx_CNT macro for each type of tuner that will be built
100 * into your application (e.g., MT2121, MT2060). MT_TUNER_CNT
101 * must be set to the SUM of all of the MTxxxx_CNT macros.
102 *
103 * #define MT2050_CNT (1)
104 * #define MT2060_CNT (1)
105 * #define MT2111_CNT (1)
106 * #define MT2121_CNT (3)
107 */
108
109
110#define MT2063_TUNER_CNT (1) /* total num of MicroTuner tuners */
111#define MT2063_I2C (0xC0)
112
113/*
114 * Constant defining the version of the following structure
115 * and therefore the API for this code.
116 *
117 * When compiling the tuner driver, the preprocessor will
118 * check against this version number to make sure that
119 * it matches the version that the tuner driver knows about.
120 */
121/* Version 010201 => 1.21 */
122#define MT2063_AVOID_SPURS_INFO_VERSION 010201
123
124/* DECT Frequency Avoidance */
125#define MT2063_DECT_AVOID_US_FREQS 0x00000001
126
127#define MT2063_DECT_AVOID_EURO_FREQS 0x00000002
128
129#define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0)
130
131#define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0)
132
133enum MT2063_DECT_Avoid_Type {
134 MT2063_NO_DECT_AVOIDANCE = 0, /* Do not create DECT exclusion zones. */
135 MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS, /* Avoid US DECT frequencies. */
136 MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS, /* Avoid European DECT frequencies. */
137 MT2063_AVOID_BOTH /* Avoid both regions. Not typically used. */
138};
139
140#define MT2063_MAX_ZONES 48
141
142struct MT2063_ExclZone_t;
143
144struct MT2063_ExclZone_t {
145 u32 min_;
146 u32 max_;
147 struct MT2063_ExclZone_t *next_;
148};
149
150/*
151 * Structure of data needed for Spur Avoidance
152 */
153struct MT2063_AvoidSpursData_t {
154 u32 nAS_Algorithm;
155 u32 f_ref;
156 u32 f_in;
157 u32 f_LO1;
158 u32 f_if1_Center;
159 u32 f_if1_Request;
160 u32 f_if1_bw;
161 u32 f_LO2;
162 u32 f_out;
163 u32 f_out_bw;
164 u32 f_LO1_Step;
165 u32 f_LO2_Step;
166 u32 f_LO1_FracN_Avoid;
167 u32 f_LO2_FracN_Avoid;
168 u32 f_zif_bw;
169 u32 f_min_LO_Separation;
170 u32 maxH1;
171 u32 maxH2;
172 enum MT2063_DECT_Avoid_Type avoidDECT;
173 u32 bSpurPresent;
174 u32 bSpurAvoided;
175 u32 nSpursFound;
176 u32 nZones;
177 struct MT2063_ExclZone_t *freeZones;
178 struct MT2063_ExclZone_t *usedZones;
179 struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES];
180};
181
182/*
183 * Values returned by the MT2063's on-chip temperature sensor
184 * to be read/written.
185 */
186enum MT2063_Temperature {
187 MT2063_T_0C = 0, /* Temperature approx 0C */
188 MT2063_T_10C, /* Temperature approx 10C */
189 MT2063_T_20C, /* Temperature approx 20C */
190 MT2063_T_30C, /* Temperature approx 30C */
191 MT2063_T_40C, /* Temperature approx 40C */
192 MT2063_T_50C, /* Temperature approx 50C */
193 MT2063_T_60C, /* Temperature approx 60C */
194 MT2063_T_70C, /* Temperature approx 70C */
195 MT2063_T_80C, /* Temperature approx 80C */
196 MT2063_T_90C, /* Temperature approx 90C */
197 MT2063_T_100C, /* Temperature approx 100C */
198 MT2063_T_110C, /* Temperature approx 110C */
199 MT2063_T_120C, /* Temperature approx 120C */
200 MT2063_T_130C, /* Temperature approx 130C */
201 MT2063_T_140C, /* Temperature approx 140C */
202 MT2063_T_150C, /* Temperature approx 150C */
203};
204
205/*
206 * Parameters for selecting GPIO bits
207 */
208enum MT2063_GPIO_Attr {
209 MT2063_GPIO_IN,
210 MT2063_GPIO_DIR,
211 MT2063_GPIO_OUT,
212};
213
214enum MT2063_GPIO_ID {
215 MT2063_GPIO0,
216 MT2063_GPIO1,
217 MT2063_GPIO2,
218};
219
220/*
221 * Parameter for function MT2063_SetExtSRO that specifies the external
222 * SRO drive frequency.
223 *
224 * MT2063_EXT_SRO_OFF is the power-up default value.
225 */
226enum MT2063_Ext_SRO {
227 MT2063_EXT_SRO_OFF, /* External SRO drive off */
228 MT2063_EXT_SRO_BY_4, /* External SRO drive divide by 4 */
229 MT2063_EXT_SRO_BY_2, /* External SRO drive divide by 2 */
230 MT2063_EXT_SRO_BY_1 /* External SRO drive divide by 1 */
231};
232
233/*
234 * Parameter for function MT2063_SetPowerMask that specifies the power down
235 * of various sections of the MT2063.
236 */
237enum MT2063_Mask_Bits {
238 MT2063_REG_SD = 0x0040, /* Shutdown regulator */
239 MT2063_SRO_SD = 0x0020, /* Shutdown SRO */
240 MT2063_AFC_SD = 0x0010, /* Shutdown AFC A/D */
241 MT2063_PD_SD = 0x0002, /* Enable power detector shutdown */
242 MT2063_PDADC_SD = 0x0001, /* Enable power detector A/D shutdown */
243 MT2063_VCO_SD = 0x8000, /* Enable VCO shutdown */
244 MT2063_LTX_SD = 0x4000, /* Enable LTX shutdown */
245 MT2063_LT1_SD = 0x2000, /* Enable LT1 shutdown */
246 MT2063_LNA_SD = 0x1000, /* Enable LNA shutdown */
247 MT2063_UPC_SD = 0x0800, /* Enable upconverter shutdown */
248 MT2063_DNC_SD = 0x0400, /* Enable downconverter shutdown */
249 MT2063_VGA_SD = 0x0200, /* Enable VGA shutdown */
250 MT2063_AMP_SD = 0x0100, /* Enable AMP shutdown */
251 MT2063_ALL_SD = 0xFF73, /* All shutdown bits for this tuner */
252 MT2063_NONE_SD = 0x0000 /* No shutdown bits */
253};
254
255/*
256 * Parameter for function MT2063_GetParam & MT2063_SetParam that
257 * specifies the tuning algorithm parameter to be read/written.
258 */
259enum MT2063_Param {
260 /* tuner address set by MT2063_Open() */
261 MT2063_IC_ADDR,
262
263 /* max number of MT2063 tuners set by MT_TUNER_CNT in mt_userdef.h */
264 MT2063_MAX_OPEN,
265
266 /* current number of open MT2063 tuners set by MT2063_Open() */
267 MT2063_NUM_OPEN,
268
269 /* crystal frequency (default: 16000000 Hz) */
270 MT2063_SRO_FREQ,
271
272 /* min tuning step size (default: 50000 Hz) */
273 MT2063_STEPSIZE,
274
275 /* input center frequency set by MT2063_Tune() */
276 MT2063_INPUT_FREQ,
277
278 /* LO1 Frequency set by MT2063_Tune() */
279 MT2063_LO1_FREQ,
280
281 /* LO1 minimum step size (default: 250000 Hz) */
282 MT2063_LO1_STEPSIZE,
283
284 /* LO1 FracN keep-out region (default: 999999 Hz) */
285 MT2063_LO1_FRACN_AVOID_PARAM,
286
287 /* Current 1st IF in use set by MT2063_Tune() */
288 MT2063_IF1_ACTUAL,
289
290 /* Requested 1st IF set by MT2063_Tune() */
291 MT2063_IF1_REQUEST,
292
293 /* Center of 1st IF SAW filter (default: 1218000000 Hz) */
294 MT2063_IF1_CENTER,
295
296 /* Bandwidth of 1st IF SAW filter (default: 20000000 Hz) */
297 MT2063_IF1_BW,
298
299 /* zero-IF bandwidth (default: 2000000 Hz) */
300 MT2063_ZIF_BW,
301
302 /* LO2 Frequency set by MT2063_Tune() */
303 MT2063_LO2_FREQ,
304
305 /* LO2 minimum step size (default: 50000 Hz) */
306 MT2063_LO2_STEPSIZE,
307
308 /* LO2 FracN keep-out region (default: 374999 Hz) */
309 MT2063_LO2_FRACN_AVOID,
310
311 /* output center frequency set by MT2063_Tune() */
312 MT2063_OUTPUT_FREQ,
313
314 /* output bandwidth set by MT2063_Tune() */
315 MT2063_OUTPUT_BW,
316
317 /* min inter-tuner LO separation (default: 1000000 Hz) */
318 MT2063_LO_SEPARATION,
319
320 /* ID of avoid-spurs algorithm in use compile-time constant */
321 MT2063_AS_ALG,
322
323 /* max # of intra-tuner harmonics (default: 15) */
324 MT2063_MAX_HARM1,
325
326 /* max # of inter-tuner harmonics (default: 7) */
327 MT2063_MAX_HARM2,
328
329 /* # of 1st IF exclusion zones used set by MT2063_Tune() */
330 MT2063_EXCL_ZONES,
331
332 /* # of spurs found/avoided set by MT2063_Tune() */
333 MT2063_NUM_SPURS,
334
335 /* >0 spurs avoided set by MT2063_Tune() */
336 MT2063_SPUR_AVOIDED,
337
338 /* >0 spurs in output (mathematically) set by MT2063_Tune() */
339 MT2063_SPUR_PRESENT,
340
341 /* Receiver Mode for some parameters. 1 is DVB-T */
342 MT2063_RCVR_MODE,
343
344 /* directly set LNA attenuation, parameter is value to set */
345 MT2063_ACLNA,
346
347 /* maximum LNA attenuation, parameter is value to set */
348 MT2063_ACLNA_MAX,
349
350 /* directly set ATN attenuation. Paremeter is value to set. */
351 MT2063_ACRF,
352
353 /* maxium ATN attenuation. Paremeter is value to set. */
354 MT2063_ACRF_MAX,
355
356 /* directly set FIF attenuation. Paremeter is value to set. */
357 MT2063_ACFIF,
358
359 /* maxium FIF attenuation. Paremeter is value to set. */
360 MT2063_ACFIF_MAX,
361
362 /* LNA Rin */
363 MT2063_LNA_RIN,
364
365 /* Power Detector LNA level target */
366 MT2063_LNA_TGT,
367
368 /* Power Detector 1 level */
369 MT2063_PD1,
370
371 /* Power Detector 1 level target */
372 MT2063_PD1_TGT,
373
374 /* Power Detector 2 level */
375 MT2063_PD2,
376
377 /* Power Detector 2 level target */
378 MT2063_PD2_TGT,
379
380 /* Selects, which DNC is activ */
381 MT2063_DNC_OUTPUT_ENABLE,
382
383 /* VGA gain code */
384 MT2063_VGAGC,
385
386 /* VGA bias current */
387 MT2063_VGAOI,
388
389 /* TAGC, determins the speed of the AGC */
390 MT2063_TAGC,
391
392 /* AMP gain code */
393 MT2063_AMPGC,
394
395 /* Control setting to avoid DECT freqs (default: MT_AVOID_BOTH) */
396 MT2063_AVOID_DECT,
397
398 /* Cleartune filter selection: 0 - by IC (default), 1 - by software */
399 MT2063_CTFILT_SW,
400
401 MT2063_EOP /* last entry in enumerated list */
402};
403
404/*
405 * Parameter for selecting tuner mode
406 */
407enum MT2063_RCVR_MODES {
408 MT2063_CABLE_QAM = 0, /* Digital cable */
409 MT2063_CABLE_ANALOG, /* Analog cable */
410 MT2063_OFFAIR_COFDM, /* Digital offair */
411 MT2063_OFFAIR_COFDM_SAWLESS, /* Digital offair without SAW */
412 MT2063_OFFAIR_ANALOG, /* Analog offair */
413 MT2063_OFFAIR_8VSB, /* Analog offair */
414 MT2063_NUM_RCVR_MODES
415};
416
417/*
418 * Possible values for MT2063_DNC_OUTPUT
419 */
420enum MT2063_DNC_Output_Enable {
421 MT2063_DNC_NONE = 0,
422 MT2063_DNC_1,
423 MT2063_DNC_2,
424 MT2063_DNC_BOTH
425};
426
427/*
428** Two-wire serial bus subaddresses of the tuner registers.
429** Also known as the tuner's register addresses.
430*/
431enum MT2063_Register_Offsets {
432 MT2063_REG_PART_REV = 0, /* 0x00: Part/Rev Code */
433 MT2063_REG_LO1CQ_1, /* 0x01: LO1C Queued Byte 1 */
434 MT2063_REG_LO1CQ_2, /* 0x02: LO1C Queued Byte 2 */
435 MT2063_REG_LO2CQ_1, /* 0x03: LO2C Queued Byte 1 */
436 MT2063_REG_LO2CQ_2, /* 0x04: LO2C Queued Byte 2 */
437 MT2063_REG_LO2CQ_3, /* 0x05: LO2C Queued Byte 3 */
438 MT2063_REG_RSVD_06, /* 0x06: Reserved */
439 MT2063_REG_LO_STATUS, /* 0x07: LO Status */
440 MT2063_REG_FIFFC, /* 0x08: FIFF Center */
441 MT2063_REG_CLEARTUNE, /* 0x09: ClearTune Filter */
442 MT2063_REG_ADC_OUT, /* 0x0A: ADC_OUT */
443 MT2063_REG_LO1C_1, /* 0x0B: LO1C Byte 1 */
444 MT2063_REG_LO1C_2, /* 0x0C: LO1C Byte 2 */
445 MT2063_REG_LO2C_1, /* 0x0D: LO2C Byte 1 */
446 MT2063_REG_LO2C_2, /* 0x0E: LO2C Byte 2 */
447 MT2063_REG_LO2C_3, /* 0x0F: LO2C Byte 3 */
448 MT2063_REG_RSVD_10, /* 0x10: Reserved */
449 MT2063_REG_PWR_1, /* 0x11: PWR Byte 1 */
450 MT2063_REG_PWR_2, /* 0x12: PWR Byte 2 */
451 MT2063_REG_TEMP_STATUS, /* 0x13: Temp Status */
452 MT2063_REG_XO_STATUS, /* 0x14: Crystal Status */
453 MT2063_REG_RF_STATUS, /* 0x15: RF Attn Status */
454 MT2063_REG_FIF_STATUS, /* 0x16: FIF Attn Status */
455 MT2063_REG_LNA_OV, /* 0x17: LNA Attn Override */
456 MT2063_REG_RF_OV, /* 0x18: RF Attn Override */
457 MT2063_REG_FIF_OV, /* 0x19: FIF Attn Override */
458 MT2063_REG_LNA_TGT, /* 0x1A: Reserved */
459 MT2063_REG_PD1_TGT, /* 0x1B: Pwr Det 1 Target */
460 MT2063_REG_PD2_TGT, /* 0x1C: Pwr Det 2 Target */
461 MT2063_REG_RSVD_1D, /* 0x1D: Reserved */
462 MT2063_REG_RSVD_1E, /* 0x1E: Reserved */
463 MT2063_REG_RSVD_1F, /* 0x1F: Reserved */
464 MT2063_REG_RSVD_20, /* 0x20: Reserved */
465 MT2063_REG_BYP_CTRL, /* 0x21: Bypass Control */
466 MT2063_REG_RSVD_22, /* 0x22: Reserved */
467 MT2063_REG_RSVD_23, /* 0x23: Reserved */
468 MT2063_REG_RSVD_24, /* 0x24: Reserved */
469 MT2063_REG_RSVD_25, /* 0x25: Reserved */
470 MT2063_REG_RSVD_26, /* 0x26: Reserved */
471 MT2063_REG_RSVD_27, /* 0x27: Reserved */
472 MT2063_REG_FIFF_CTRL, /* 0x28: FIFF Control */
473 MT2063_REG_FIFF_OFFSET, /* 0x29: FIFF Offset */
474 MT2063_REG_CTUNE_CTRL, /* 0x2A: Reserved */
475 MT2063_REG_CTUNE_OV, /* 0x2B: Reserved */
476 MT2063_REG_CTRL_2C, /* 0x2C: Reserved */
477 MT2063_REG_FIFF_CTRL2, /* 0x2D: Fiff Control */
478 MT2063_REG_RSVD_2E, /* 0x2E: Reserved */
479 MT2063_REG_DNC_GAIN, /* 0x2F: DNC Control */
480 MT2063_REG_VGA_GAIN, /* 0x30: VGA Gain Ctrl */
481 MT2063_REG_RSVD_31, /* 0x31: Reserved */
482 MT2063_REG_TEMP_SEL, /* 0x32: Temperature Selection */
483 MT2063_REG_RSVD_33, /* 0x33: Reserved */
484 MT2063_REG_RSVD_34, /* 0x34: Reserved */
485 MT2063_REG_RSVD_35, /* 0x35: Reserved */
486 MT2063_REG_RSVD_36, /* 0x36: Reserved */
487 MT2063_REG_RSVD_37, /* 0x37: Reserved */
488 MT2063_REG_RSVD_38, /* 0x38: Reserved */
489 MT2063_REG_RSVD_39, /* 0x39: Reserved */
490 MT2063_REG_RSVD_3A, /* 0x3A: Reserved */
491 MT2063_REG_RSVD_3B, /* 0x3B: Reserved */
492 MT2063_REG_RSVD_3C, /* 0x3C: Reserved */
493 MT2063_REG_END_REGS
494};
495
496struct MT2063_Info_t {
497 void *handle;
498 void *hUserData;
499 u32 address;
500 u32 version;
501 u32 tuner_id;
502 struct MT2063_AvoidSpursData_t AS_Data;
503 u32 f_IF1_actual;
504 u32 rcvr_mode;
505 u32 ctfilt_sw;
506 u32 CTFiltMax[31];
507 u32 num_regs;
508 u8 reg[MT2063_REG_END_REGS];
509};
510typedef struct MT2063_Info_t *pMT2063_Info_t;
511
512enum MTTune_atv_standard {
513 MTTUNEA_UNKNOWN = 0,
514 MTTUNEA_PAL_B,
515 MTTUNEA_PAL_G,
516 MTTUNEA_PAL_I,
517 MTTUNEA_PAL_L,
518 MTTUNEA_PAL_MN,
519 MTTUNEA_PAL_DK,
520 MTTUNEA_DIGITAL,
521 MTTUNEA_FMRADIO,
522 MTTUNEA_DVBC,
523 MTTUNEA_DVBT
524};
525
526
527struct mt2063_state {
528 struct i2c_adapter *i2c;
529
530 const struct mt2063_config *config;
531 struct dvb_tuner_ops ops;
532 struct dvb_frontend *frontend;
533 struct tuner_state status;
534 struct MT2063_Info_t *MT2063_ht;
535 bool MT2063_init;
536
537 enum MTTune_atv_standard tv_type;
538 u32 frequency;
539 u32 srate;
540 u32 bandwidth;
541 u32 reference;
542};
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300543
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300544/* Prototypes */
545static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
546 u32 f_min, u32 f_max);
547static u32 MT2063_ReInit(void *h);
548static u32 MT2063_Close(void *hMT2063);
549static u32 MT2063_GetReg(void *h, u8 reg, u8 * val);
550static u32 MT2063_GetParam(void *h, enum MT2063_Param param, u32 * pValue);
551static u32 MT2063_SetReg(void *h, u8 reg, u8 val);
552static u32 MT2063_SetParam(void *h, enum MT2063_Param param, u32 nValue);
553
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300554/*****************/
555/* From drivers/media/common/tuners/mt2063_cfg.h */
556
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300557unsigned int mt2063_setTune(struct dvb_frontend *fe, u32 f_in,
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300558 u32 bw_in,
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300559 enum MTTune_atv_standard tv_type)
560{
561 //return (int)MT_Tune_atv(h, f_in, bw_in, tv_type);
562
563 struct dvb_frontend_ops *frontend_ops = NULL;
564 struct dvb_tuner_ops *tuner_ops = NULL;
565 struct tuner_state t_state;
566 struct mt2063_state *mt2063State = fe->tuner_priv;
567 int err = 0;
568
569 t_state.frequency = f_in;
570 t_state.bandwidth = bw_in;
571 mt2063State->tv_type = tv_type;
572 if (&fe->ops)
573 frontend_ops = &fe->ops;
574 if (&frontend_ops->tuner_ops)
575 tuner_ops = &frontend_ops->tuner_ops;
576 if (tuner_ops->set_state) {
577 if ((err =
578 tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY,
579 &t_state)) < 0) {
580 printk("%s: Invalid parameter\n", __func__);
581 return err;
582 }
583 }
584
585 return err;
586}
587
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300588unsigned int mt2063_lockStatus(struct dvb_frontend *fe)
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300589{
590 struct dvb_frontend_ops *frontend_ops = &fe->ops;
591 struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
592 struct tuner_state t_state;
593 int err = 0;
594
595 if (&fe->ops)
596 frontend_ops = &fe->ops;
597 if (&frontend_ops->tuner_ops)
598 tuner_ops = &frontend_ops->tuner_ops;
599 if (tuner_ops->get_state) {
600 if ((err =
601 tuner_ops->get_state(fe, DVBFE_TUNER_REFCLOCK,
602 &t_state)) < 0) {
603 printk("%s: Invalid parameter\n", __func__);
604 return err;
605 }
606 }
607 return err;
608}
609
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300610unsigned int tuner_MT2063_Open(struct dvb_frontend *fe)
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300611{
612 struct dvb_frontend_ops *frontend_ops = &fe->ops;
613 struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
614 struct tuner_state t_state;
615 int err = 0;
616
617 if (&fe->ops)
618 frontend_ops = &fe->ops;
619 if (&frontend_ops->tuner_ops)
620 tuner_ops = &frontend_ops->tuner_ops;
621 if (tuner_ops->set_state) {
622 if ((err =
623 tuner_ops->set_state(fe, DVBFE_TUNER_OPEN,
624 &t_state)) < 0) {
625 printk("%s: Invalid parameter\n", __func__);
626 return err;
627 }
628 }
629
630 return err;
631}
632
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300633unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe)
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300634{
635 struct dvb_frontend_ops *frontend_ops = &fe->ops;
636 struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
637 struct tuner_state t_state;
638 int err = 0;
639
640 if (&fe->ops)
641 frontend_ops = &fe->ops;
642 if (&frontend_ops->tuner_ops)
643 tuner_ops = &frontend_ops->tuner_ops;
644 if (tuner_ops->set_state) {
645 if ((err =
646 tuner_ops->set_state(fe, DVBFE_TUNER_SOFTWARE_SHUTDOWN,
647 &t_state)) < 0) {
648 printk("%s: Invalid parameter\n", __func__);
649 return err;
650 }
651 }
652
653 return err;
654}
655
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300656unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe)
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300657{
658 struct dvb_frontend_ops *frontend_ops = &fe->ops;
659 struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
660 struct tuner_state t_state;
661 int err = 0;
662
663 if (&fe->ops)
664 frontend_ops = &fe->ops;
665 if (&frontend_ops->tuner_ops)
666 tuner_ops = &frontend_ops->tuner_ops;
667 if (tuner_ops->set_state) {
668 if ((err =
669 tuner_ops->set_state(fe, DVBFE_TUNER_CLEAR_POWER_MASKBITS,
670 &t_state)) < 0) {
671 printk("%s: Invalid parameter\n", __func__);
672 return err;
673 }
674 }
675
676 return err;
677}
678
679/*****************/
680
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300681//i2c operation
682static int mt2063_writeregs(struct mt2063_state *state, u8 reg1,
683 u8 * data, int len)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300684{
685 int ret;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300686 u8 buf[60]; /* = { reg1, data }; */
687
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300688 struct i2c_msg msg = {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300689 .addr = state->config->tuner_address,
690 .flags = 0,
691 .buf = buf,
692 .len = len + 1
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300693 };
694
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300695 msg.buf[0] = reg1;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300696 memcpy(msg.buf + 1, data, len);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300697
698 //printk("mt2063_writeregs state->i2c=%p\n", state->i2c);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300699 ret = i2c_transfer(state->i2c, &msg, 1);
700
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300701 if (ret < 0)
702 printk("mt2063_writeregs error ret=%d\n", ret);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300703
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300704 return ret;
705}
706
707static int mt2063_read_regs(struct mt2063_state *state, u8 reg1, u8 * b, u8 len)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300708{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300709 int ret;
710 u8 b0[] = { reg1 };
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300711 struct i2c_msg msg[] = {
712 {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300713 .addr = state->config->tuner_address,
714 .flags = I2C_M_RD,
715 .buf = b0,
716 .len = 1}, {
717 .addr = state->config->tuner_address,
718 .flags = I2C_M_RD,
719 .buf = b,
720 .len = len}
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300721 };
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300722
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300723 //printk("mt2063_read_regs state->i2c=%p\n", state->i2c);
724 ret = i2c_transfer(state->i2c, msg, 2);
725 if (ret < 0)
726 printk("mt2063_readregs error ret=%d\n", ret);
727
728 return ret;
729}
730
731//context of mt2063_userdef.c <Henry> ======================================
732//#################################################################
733//=================================================================
734/*****************************************************************************
735**
736** Name: MT_WriteSub
737**
738** Description: Write values to device using a two-wire serial bus.
739**
740** Parameters: hUserData - User-specific I/O parameter that was
741** passed to tuner's Open function.
742** addr - device serial bus address (value passed
743** as parameter to MTxxxx_Open)
744** subAddress - serial bus sub-address (Register Address)
745** pData - pointer to the Data to be written to the
746** device
747** cnt - number of bytes/registers to be written
748**
749** Returns: status:
750** MT_OK - No errors
751** MT_COMM_ERR - Serial bus communications error
752** user-defined
753**
754** Notes: This is a callback function that is called from the
755** the tuning algorithm. You MUST provide code for this
756** function to write data using the tuner's 2-wire serial
757** bus.
758**
759** The hUserData parameter is a user-specific argument.
760** If additional arguments are needed for the user's
761** serial bus read/write functions, this argument can be
762** used to supply the necessary information.
763** The hUserData parameter is initialized in the tuner's Open
764** function.
765**
766** Revision History:
767**
768** SCR Date Author Description
769** -------------------------------------------------------------------------
770** N/A 03-25-2004 DAD Original
771**
772*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300773static u32 MT2063_WriteSub(void *hUserData,
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300774 u32 addr,
775 u8 subAddress, u8 * pData, u32 cnt)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300776{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300777 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300778 struct dvb_frontend *fe = hUserData;
779 struct mt2063_state *state = fe->tuner_priv;
780 /*
781 ** ToDo: Add code here to implement a serial-bus write
782 ** operation to the MTxxxx tuner. If successful,
783 ** return MT_OK.
784 */
785/* return status; */
786
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300787 fe->ops.i2c_gate_ctrl(fe, 1); //I2C bypass drxk3926 close i2c bridge
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300788
789 if (mt2063_writeregs(state, subAddress, pData, cnt) < 0) {
790 status = MT2063_ERROR;
791 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300792 fe->ops.i2c_gate_ctrl(fe, 0); //I2C bypass drxk3926 close i2c bridge
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300793
794 return (status);
795}
796
797/*****************************************************************************
798**
799** Name: MT_ReadSub
800**
801** Description: Read values from device using a two-wire serial bus.
802**
803** Parameters: hUserData - User-specific I/O parameter that was
804** passed to tuner's Open function.
805** addr - device serial bus address (value passed
806** as parameter to MTxxxx_Open)
807** subAddress - serial bus sub-address (Register Address)
808** pData - pointer to the Data to be written to the
809** device
810** cnt - number of bytes/registers to be written
811**
812** Returns: status:
813** MT_OK - No errors
814** MT_COMM_ERR - Serial bus communications error
815** user-defined
816**
817** Notes: This is a callback function that is called from the
818** the tuning algorithm. You MUST provide code for this
819** function to read data using the tuner's 2-wire serial
820** bus.
821**
822** The hUserData parameter is a user-specific argument.
823** If additional arguments are needed for the user's
824** serial bus read/write functions, this argument can be
825** used to supply the necessary information.
826** The hUserData parameter is initialized in the tuner's Open
827** function.
828**
829** Revision History:
830**
831** SCR Date Author Description
832** -------------------------------------------------------------------------
833** N/A 03-25-2004 DAD Original
834**
835*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300836static u32 MT2063_ReadSub(void *hUserData,
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300837 u32 addr,
838 u8 subAddress, u8 * pData, u32 cnt)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300839{
840 /*
841 ** ToDo: Add code here to implement a serial-bus read
842 ** operation to the MTxxxx tuner. If successful,
843 ** return MT_OK.
844 */
845/* return status; */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300846 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300847 struct dvb_frontend *fe = hUserData;
848 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300849 u32 i = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300850 fe->ops.i2c_gate_ctrl(fe, 1); //I2C bypass drxk3926 close i2c bridge
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300851
852 for (i = 0; i < cnt; i++) {
853 if (mt2063_read_regs(state, subAddress + i, pData + i, 1) < 0) {
854 status = MT2063_ERROR;
855 break;
856 }
857 }
858
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300859 fe->ops.i2c_gate_ctrl(fe, 0); //I2C bypass drxk3926 close i2c bridge
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300860
861 return (status);
862}
863
864/*****************************************************************************
865**
866** Name: MT_Sleep
867**
868** Description: Delay execution for "nMinDelayTime" milliseconds
869**
870** Parameters: hUserData - User-specific I/O parameter that was
871** passed to tuner's Open function.
872** nMinDelayTime - Delay time in milliseconds
873**
874** Returns: None.
875**
876** Notes: This is a callback function that is called from the
877** the tuning algorithm. You MUST provide code that
878** blocks execution for the specified period of time.
879**
880** Revision History:
881**
882** SCR Date Author Description
883** -------------------------------------------------------------------------
884** N/A 03-25-2004 DAD Original
885**
886*****************************************************************************/
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300887static int MT2063_Sleep(struct dvb_frontend *fe)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300888{
889 /*
890 ** ToDo: Add code here to implement a OS blocking
891 ** for a period of "nMinDelayTime" milliseconds.
892 */
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300893 msleep(10);
894
895 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300896}
897
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300898//end of mt2063_userdef.c
899//=================================================================
900//#################################################################
901//=================================================================
902
903//context of mt2063_spuravoid.c <Henry> ======================================
904//#################################################################
905//=================================================================
906
907/*****************************************************************************
908**
909** Name: mt_spuravoid.c
910**
911** Description: Microtune spur avoidance software module.
912** Supports Microtune tuner drivers.
913**
914** CVS ID: $Id: mt_spuravoid.c,v 1.3 2008/06/26 15:39:52 software Exp $
915** CVS Source: $Source: /export/home/cvsroot/software/tuners/MT2063/mt_spuravoid.c,v $
916**
917** Revision History:
918**
919** SCR Date Author Description
920** -------------------------------------------------------------------------
921** 082 03-25-2005 JWS Original multi-tuner support - requires
922** MTxxxx_CNT declarations
923** 096 04-06-2005 DAD Ver 1.11: Fix divide by 0 error if maxH==0.
924** 094 04-06-2005 JWS Ver 1.11 Added uceil and ufloor to get rid
925** of compiler warnings
926** N/A 04-07-2005 DAD Ver 1.13: Merged single- and multi-tuner spur
927** avoidance into a single module.
928** 103 01-31-2005 DAD Ver 1.14: In MT_AddExclZone(), if the range
929** (f_min, f_max) < 0, ignore the entry.
930** 115 03-23-2007 DAD Fix declaration of spur due to truncation
931** errors.
932** 117 03-29-2007 RSK Ver 1.15: Re-wrote to match search order from
933** tuner DLL.
934** 137 06-18-2007 DAD Ver 1.16: Fix possible divide-by-0 error for
935** multi-tuners that have
936** (delta IF1) > (f_out-f_outbw/2).
937** 147 07-27-2007 RSK Ver 1.17: Corrected calculation (-) to (+)
938** Added logic to force f_Center within 1/2 f_Step.
939** 177 S 02-26-2008 RSK Ver 1.18: Corrected calculation using LO1 > MAX/2
940** Type casts added to preserve correct sign.
941** N/A I 06-17-2008 RSK Ver 1.19: Refactoring avoidance of DECT
942** frequencies into MT_ResetExclZones().
943** N/A I 06-20-2008 RSK Ver 1.21: New VERSION number for ver checking.
944**
945*****************************************************************************/
946
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300947/* Version of this module */
948#define MT2063_SPUR_VERSION 10201 /* Version 01.21 */
949
950/* Implement ceiling, floor functions. */
951#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0))
952#define uceil(n, d) ((n)/(d) + ((n)%(d) != 0))
953#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d))
954#define ufloor(n, d) ((n)/(d))
955
956struct MT2063_FIFZone_t {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300957 s32 min_;
958 s32 max_;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300959};
960
961#if MT2063_TUNER_CNT > 1
962static struct MT2063_AvoidSpursData_t *TunerList[MT2063_TUNER_CNT];
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300963static u32 TunerCount = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300964#endif
965
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300966static u32 MT2063_RegisterTuner(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300967{
968#if MT2063_TUNER_CNT == 1
969 pAS_Info->nAS_Algorithm = 1;
970 return MT2063_OK;
971#else
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300972 u32 index;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300973
974 pAS_Info->nAS_Algorithm = 2;
975
976 /*
977 ** Check to see if tuner is already registered
978 */
979 for (index = 0; index < TunerCount; index++) {
980 if (TunerList[index] == pAS_Info) {
981 return MT2063_OK; /* Already here - no problem */
982 }
983 }
984
985 /*
986 ** Add tuner to list - if there is room.
987 */
988 if (TunerCount < MT2063_TUNER_CNT) {
989 TunerList[TunerCount] = pAS_Info;
990 TunerCount++;
991 return MT2063_OK;
992 } else
993 return MT2063_TUNER_CNT_ERR;
994#endif
995}
996
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300997static void MT2063_UnRegisterTuner(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300998{
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300999#if MT2063_TUNER_CNT > 1
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001000 u32 index;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001001
1002 for (index = 0; index < TunerCount; index++) {
1003 if (TunerList[index] == pAS_Info) {
1004 TunerList[index] = TunerList[--TunerCount];
1005 }
1006 }
1007#endif
1008}
1009
1010/*
1011** Reset all exclusion zones.
1012** Add zones to protect the PLL FracN regions near zero
1013**
1014** N/A I 06-17-2008 RSK Ver 1.19: Refactoring avoidance of DECT
1015** frequencies into MT_ResetExclZones().
1016*/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001017static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001018{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001019 u32 center;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001020#if MT2063_TUNER_CNT > 1
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001021 u32 index;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001022 struct MT2063_AvoidSpursData_t *adj;
1023#endif
1024
1025 pAS_Info->nZones = 0; /* this clears the used list */
1026 pAS_Info->usedZones = NULL; /* reset ptr */
1027 pAS_Info->freeZones = NULL; /* reset ptr */
1028
1029 center =
1030 pAS_Info->f_ref *
1031 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 +
1032 pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in;
1033 while (center <
1034 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
1035 pAS_Info->f_LO1_FracN_Avoid) {
1036 /* Exclude LO1 FracN */
1037 MT2063_AddExclZone(pAS_Info,
1038 center - pAS_Info->f_LO1_FracN_Avoid,
1039 center - 1);
1040 MT2063_AddExclZone(pAS_Info, center + 1,
1041 center + pAS_Info->f_LO1_FracN_Avoid);
1042 center += pAS_Info->f_ref;
1043 }
1044
1045 center =
1046 pAS_Info->f_ref *
1047 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 -
1048 pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out;
1049 while (center <
1050 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
1051 pAS_Info->f_LO2_FracN_Avoid) {
1052 /* Exclude LO2 FracN */
1053 MT2063_AddExclZone(pAS_Info,
1054 center - pAS_Info->f_LO2_FracN_Avoid,
1055 center - 1);
1056 MT2063_AddExclZone(pAS_Info, center + 1,
1057 center + pAS_Info->f_LO2_FracN_Avoid);
1058 center += pAS_Info->f_ref;
1059 }
1060
1061 if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
1062 /* Exclude LO1 values that conflict with DECT channels */
1063 MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */
1064 MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */
1065 MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */
1066 MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */
1067 MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */
1068 }
1069
1070 if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
1071 MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */
1072 MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */
1073 MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */
1074 MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */
1075 MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */
1076 MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */
1077 MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */
1078 MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */
1079 MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */
1080 MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */
1081 }
1082#if MT2063_TUNER_CNT > 1
1083 /*
1084 ** Iterate through all adjacent tuners and exclude frequencies related to them
1085 */
1086 for (index = 0; index < TunerCount; ++index) {
1087 adj = TunerList[index];
1088 if (pAS_Info == adj) /* skip over our own data, don't process it */
1089 continue;
1090
1091 /*
1092 ** Add 1st IF exclusion zone covering adjacent tuner's LO2
1093 ** at "adjfLO2 + f_out" +/- m_MinLOSpacing
1094 */
1095 if (adj->f_LO2 != 0)
1096 MT2063_AddExclZone(pAS_Info,
1097 (adj->f_LO2 + pAS_Info->f_out) -
1098 pAS_Info->f_min_LO_Separation,
1099 (adj->f_LO2 + pAS_Info->f_out) +
1100 pAS_Info->f_min_LO_Separation);
1101
1102 /*
1103 ** Add 1st IF exclusion zone covering adjacent tuner's LO1
1104 ** at "adjfLO1 - f_in" +/- m_MinLOSpacing
1105 */
1106 if (adj->f_LO1 != 0)
1107 MT2063_AddExclZone(pAS_Info,
1108 (adj->f_LO1 - pAS_Info->f_in) -
1109 pAS_Info->f_min_LO_Separation,
1110 (adj->f_LO1 - pAS_Info->f_in) +
1111 pAS_Info->f_min_LO_Separation);
1112 }
1113#endif
1114}
1115
1116static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t
1117 *pAS_Info,
1118 struct MT2063_ExclZone_t *pPrevNode)
1119{
1120 struct MT2063_ExclZone_t *pNode;
1121 /* Check for a node in the free list */
1122 if (pAS_Info->freeZones != NULL) {
1123 /* Use one from the free list */
1124 pNode = pAS_Info->freeZones;
1125 pAS_Info->freeZones = pNode->next_;
1126 } else {
1127 /* Grab a node from the array */
1128 pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones];
1129 }
1130
1131 if (pPrevNode != NULL) {
1132 pNode->next_ = pPrevNode->next_;
1133 pPrevNode->next_ = pNode;
1134 } else { /* insert at the beginning of the list */
1135
1136 pNode->next_ = pAS_Info->usedZones;
1137 pAS_Info->usedZones = pNode;
1138 }
1139
1140 pAS_Info->nZones++;
1141 return pNode;
1142}
1143
1144static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t
1145 *pAS_Info,
1146 struct MT2063_ExclZone_t *pPrevNode,
1147 struct MT2063_ExclZone_t
1148 *pNodeToRemove)
1149{
1150 struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_;
1151
1152 /* Make previous node point to the subsequent node */
1153 if (pPrevNode != NULL)
1154 pPrevNode->next_ = pNext;
1155
1156 /* Add pNodeToRemove to the beginning of the freeZones */
1157 pNodeToRemove->next_ = pAS_Info->freeZones;
1158 pAS_Info->freeZones = pNodeToRemove;
1159
1160 /* Decrement node count */
1161 pAS_Info->nZones--;
1162
1163 return pNext;
1164}
1165
1166/*****************************************************************************
1167**
1168** Name: MT_AddExclZone
1169**
1170** Description: Add (and merge) an exclusion zone into the list.
1171** If the range (f_min, f_max) is totally outside the
1172** 1st IF BW, ignore the entry.
1173** If the range (f_min, f_max) is negative, ignore the entry.
1174**
1175** Revision History:
1176**
1177** SCR Date Author Description
1178** -------------------------------------------------------------------------
1179** 103 01-31-2005 DAD Ver 1.14: In MT_AddExclZone(), if the range
1180** (f_min, f_max) < 0, ignore the entry.
1181**
1182*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001183static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001184 u32 f_min, u32 f_max)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001185{
1186 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
1187 struct MT2063_ExclZone_t *pPrev = NULL;
1188 struct MT2063_ExclZone_t *pNext = NULL;
1189
1190 /* Check to see if this overlaps the 1st IF filter */
1191 if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2)))
1192 && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2)))
1193 && (f_min < f_max)) {
1194 /*
1195 ** 1 2 3 4 5 6
1196 **
1197 ** New entry: |---| |--| |--| |-| |---| |--|
1198 ** or or or or or
1199 ** Existing: |--| |--| |--| |---| |-| |--|
1200 */
1201
1202 /* Check for our place in the list */
1203 while ((pNode != NULL) && (pNode->max_ < f_min)) {
1204 pPrev = pNode;
1205 pNode = pNode->next_;
1206 }
1207
1208 if ((pNode != NULL) && (pNode->min_ < f_max)) {
1209 /* Combine me with pNode */
1210 if (f_min < pNode->min_)
1211 pNode->min_ = f_min;
1212 if (f_max > pNode->max_)
1213 pNode->max_ = f_max;
1214 } else {
1215 pNode = InsertNode(pAS_Info, pPrev);
1216 pNode->min_ = f_min;
1217 pNode->max_ = f_max;
1218 }
1219
1220 /* Look for merging possibilities */
1221 pNext = pNode->next_;
1222 while ((pNext != NULL) && (pNext->min_ < pNode->max_)) {
1223 if (pNext->max_ > pNode->max_)
1224 pNode->max_ = pNext->max_;
1225 pNext = RemoveNode(pAS_Info, pNode, pNext); /* Remove pNext, return ptr to pNext->next */
1226 }
1227 }
1228}
1229
1230/*****************************************************************************
1231**
1232** Name: MT_ChooseFirstIF
1233**
1234** Description: Choose the best available 1st IF
1235** If f_Desired is not excluded, choose that first.
1236** Otherwise, return the value closest to f_Center that is
1237** not excluded
1238**
1239** Revision History:
1240**
1241** SCR Date Author Description
1242** -------------------------------------------------------------------------
1243** 117 03-29-2007 RSK Ver 1.15: Re-wrote to match search order from
1244** tuner DLL.
1245** 147 07-27-2007 RSK Ver 1.17: Corrected calculation (-) to (+)
1246** Added logic to force f_Center within 1/2 f_Step.
1247**
1248*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001249static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001250{
1251 /*
1252 ** Update "f_Desired" to be the nearest "combinational-multiple" of "f_LO1_Step".
1253 ** The resulting number, F_LO1 must be a multiple of f_LO1_Step. And F_LO1 is the arithmetic sum
1254 ** of f_in + f_Center. Neither f_in, nor f_Center must be a multiple of f_LO1_Step.
1255 ** However, the sum must be.
1256 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001257 const u32 f_Desired =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001258 pAS_Info->f_LO1_Step *
1259 ((pAS_Info->f_if1_Request + pAS_Info->f_in +
1260 pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) -
1261 pAS_Info->f_in;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001262 const u32 f_Step =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001263 (pAS_Info->f_LO1_Step >
1264 pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info->
1265 f_LO2_Step;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001266 u32 f_Center;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001267
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001268 s32 i;
1269 s32 j = 0;
1270 u32 bDesiredExcluded = 0;
1271 u32 bZeroExcluded = 0;
1272 s32 tmpMin, tmpMax;
1273 s32 bestDiff;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001274 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
1275 struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES];
1276
1277 if (pAS_Info->nZones == 0)
1278 return f_Desired;
1279
1280 /* f_Center needs to be an integer multiple of f_Step away from f_Desired */
1281 if (pAS_Info->f_if1_Center > f_Desired)
1282 f_Center =
1283 f_Desired +
1284 f_Step *
1285 ((pAS_Info->f_if1_Center - f_Desired +
1286 f_Step / 2) / f_Step);
1287 else
1288 f_Center =
1289 f_Desired -
1290 f_Step *
1291 ((f_Desired - pAS_Info->f_if1_Center +
1292 f_Step / 2) / f_Step);
1293
1294 //assert;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001295 //if (!abs((s32) f_Center - (s32) pAS_Info->f_if1_Center) <= (s32) (f_Step/2))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001296 // return 0;
1297
1298 /* Take MT_ExclZones, center around f_Center and change the resolution to f_Step */
1299 while (pNode != NULL) {
1300 /* floor function */
1301 tmpMin =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001302 floor((s32) (pNode->min_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001303
1304 /* ceil function */
1305 tmpMax =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001306 ceil((s32) (pNode->max_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001307
1308 if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired))
1309 bDesiredExcluded = 1;
1310
1311 if ((tmpMin < 0) && (tmpMax > 0))
1312 bZeroExcluded = 1;
1313
1314 /* See if this zone overlaps the previous */
1315 if ((j > 0) && (tmpMin < zones[j - 1].max_))
1316 zones[j - 1].max_ = tmpMax;
1317 else {
1318 /* Add new zone */
1319 //assert(j<MT2063_MAX_ZONES);
1320 //if (j>=MT2063_MAX_ZONES)
1321 //break;
1322
1323 zones[j].min_ = tmpMin;
1324 zones[j].max_ = tmpMax;
1325 j++;
1326 }
1327 pNode = pNode->next_;
1328 }
1329
1330 /*
1331 ** If the desired is okay, return with it
1332 */
1333 if (bDesiredExcluded == 0)
1334 return f_Desired;
1335
1336 /*
1337 ** If the desired is excluded and the center is okay, return with it
1338 */
1339 if (bZeroExcluded == 0)
1340 return f_Center;
1341
1342 /* Find the value closest to 0 (f_Center) */
1343 bestDiff = zones[0].min_;
1344 for (i = 0; i < j; i++) {
1345 if (abs(zones[i].min_) < abs(bestDiff))
1346 bestDiff = zones[i].min_;
1347 if (abs(zones[i].max_) < abs(bestDiff))
1348 bestDiff = zones[i].max_;
1349 }
1350
1351 if (bestDiff < 0)
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001352 return f_Center - ((u32) (-bestDiff) * f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001353
1354 return f_Center + (bestDiff * f_Step);
1355}
1356
1357/****************************************************************************
1358**
1359** Name: gcd
1360**
1361** Description: Uses Euclid's algorithm
1362**
1363** Parameters: u, v - unsigned values whose GCD is desired.
1364**
1365** Global: None
1366**
1367** Returns: greatest common divisor of u and v, if either value
1368** is 0, the other value is returned as the result.
1369**
1370** Dependencies: None.
1371**
1372** Revision History:
1373**
1374** SCR Date Author Description
1375** -------------------------------------------------------------------------
1376** N/A 06-01-2004 JWS Original
1377** N/A 08-03-2004 DAD Changed to Euclid's since it can handle
1378** unsigned numbers.
1379**
1380****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001381static u32 MT2063_gcd(u32 u, u32 v)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001382{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001383 u32 r;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001384
1385 while (v != 0) {
1386 r = u % v;
1387 u = v;
1388 v = r;
1389 }
1390
1391 return u;
1392}
1393
1394/****************************************************************************
1395**
1396** Name: umax
1397**
1398** Description: Implements a simple maximum function for unsigned numbers.
1399** Implemented as a function rather than a macro to avoid
1400** multiple evaluation of the calling parameters.
1401**
1402** Parameters: a, b - Values to be compared
1403**
1404** Global: None
1405**
1406** Returns: larger of the input values.
1407**
1408** Dependencies: None.
1409**
1410** Revision History:
1411**
1412** SCR Date Author Description
1413** -------------------------------------------------------------------------
1414** N/A 06-02-2004 JWS Original
1415**
1416****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001417static u32 MT2063_umax(u32 a, u32 b)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001418{
1419 return (a >= b) ? a : b;
1420}
1421
1422#if MT2063_TUNER_CNT > 1
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001423static s32 RoundAwayFromZero(s32 n, s32 d)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001424{
1425 return (n < 0) ? floor(n, d) : ceil(n, d);
1426}
1427
1428/****************************************************************************
1429**
1430** Name: IsSpurInAdjTunerBand
1431**
1432** Description: Checks to see if a spur will be present within the IF's
1433** bandwidth or near the zero IF.
1434** (fIFOut +/- fIFBW/2, -fIFOut +/- fIFBW/2)
1435** and
1436** (0 +/- fZIFBW/2)
1437**
1438** ma mb me mf mc md
1439** <--+-+-+-----------------+-+-+-----------------+-+-+-->
1440** | ^ 0 ^ |
1441** ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^
1442** a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2
1443**
1444** Note that some equations are doubled to prevent round-off
1445** problems when calculating fIFBW/2
1446**
1447** The spur frequencies are computed as:
1448**
1449** fSpur = n * f1 - m * f2 - fOffset
1450**
1451** Parameters: f1 - The 1st local oscillator (LO) frequency
1452** of the tuner whose output we are examining
1453** f2 - The 1st local oscillator (LO) frequency
1454** of the adjacent tuner
1455** fOffset - The 2nd local oscillator of the tuner whose
1456** output we are examining
1457** fIFOut - Output IF center frequency
1458** fIFBW - Output IF Bandwidth
1459** nMaxH - max # of LO harmonics to search
1460** fp - If spur, positive distance to spur-free band edge (returned)
1461** fm - If spur, negative distance to spur-free band edge (returned)
1462**
1463** Returns: 1 if an LO spur would be present, otherwise 0.
1464**
1465** Dependencies: None.
1466**
1467** Revision History:
1468**
1469** SCR Date Author Description
1470** -------------------------------------------------------------------------
1471** N/A 01-21-2005 JWS Original, adapted from MT_DoubleConversion.
1472** 115 03-23-2007 DAD Fix declaration of spur due to truncation
1473** errors.
1474** 137 06-18-2007 DAD Ver 1.16: Fix possible divide-by-0 error for
1475** multi-tuners that have
1476** (delta IF1) > (f_out-f_outbw/2).
1477** 177 S 02-26-2008 RSK Ver 1.18: Corrected calculation using LO1 > MAX/2
1478** Type casts added to preserve correct sign.
1479**
1480****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001481static u32 IsSpurInAdjTunerBand(u32 bIsMyOutput,
1482 u32 f1,
1483 u32 f2,
1484 u32 fOffset,
1485 u32 fIFOut,
1486 u32 fIFBW,
1487 u32 fZIFBW,
1488 u32 nMaxH, u32 * fp, u32 * fm)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001489{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001490 u32 bSpurFound = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001491
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001492 const u32 fHalf_IFBW = fIFBW / 2;
1493 const u32 fHalf_ZIFBW = fZIFBW / 2;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001494
1495 /* Calculate a scale factor for all frequencies, so that our
1496 calculations all stay within 31 bits */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001497 const u32 f_Scale =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001498 ((f1 +
1499 (fOffset + fIFOut +
1500 fHalf_IFBW) / nMaxH) / (MAX_UDATA / 2 / nMaxH)) + 1;
1501
1502 /*
1503 ** After this scaling, _f1, _f2, and _f3 are guaranteed to fit into
1504 ** signed data types (smaller than MAX_UDATA/2)
1505 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001506 const s32 _f1 = (s32) (f1 / f_Scale);
1507 const s32 _f2 = (s32) (f2 / f_Scale);
1508 const s32 _f3 = (s32) (fOffset / f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001509
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001510 const s32 c = (s32) (fIFOut - fHalf_IFBW) / (s32) f_Scale;
1511 const s32 d = (s32) ((fIFOut + fHalf_IFBW) / f_Scale);
1512 const s32 f = (s32) (fHalf_ZIFBW / f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001513
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001514 s32 ma, mb, mc, md, me, mf;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001515
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001516 s32 fp_ = 0;
1517 s32 fm_ = 0;
1518 s32 n;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001519
1520 /*
1521 ** If the other tuner does not have an LO frequency defined,
1522 ** assume that we cannot interfere with it
1523 */
1524 if (f2 == 0)
1525 return 0;
1526
1527 /* Check out all multiples of f1 from -nMaxH to +nMaxH */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001528 for (n = -(s32) nMaxH; n <= (s32) nMaxH; ++n) {
1529 const s32 nf1 = n * _f1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001530 md = (_f3 + d - nf1) / _f2;
1531
1532 /* If # f2 harmonics > nMaxH, then no spurs present */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001533 if (md <= -(s32) nMaxH)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001534 break;
1535
1536 ma = (_f3 - d - nf1) / _f2;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001537 if ((ma == md) || (ma >= (s32) (nMaxH)))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001538 continue;
1539
1540 mc = (_f3 + c - nf1) / _f2;
1541 if (mc != md) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001542 const s32 m = (n < 0) ? md : mc;
1543 const s32 fspur = (nf1 + m * _f2 - _f3);
1544 const s32 den = (bIsMyOutput ? n - 1 : n);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001545 if (den == 0) {
1546 fp_ = (d - fspur) * f_Scale;
1547 fm_ = (fspur - c) * f_Scale;
1548 } else {
1549 fp_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001550 (s32) RoundAwayFromZero((d - fspur) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001551 f_Scale, den);
1552 fm_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001553 (s32) RoundAwayFromZero((fspur - c) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001554 f_Scale, den);
1555 }
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001556 if (((u32) abs(fm_) >= f_Scale)
1557 && ((u32) abs(fp_) >= f_Scale)) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001558 bSpurFound = 1;
1559 break;
1560 }
1561 }
1562
1563 /* Location of Zero-IF-spur to be checked */
1564 mf = (_f3 + f - nf1) / _f2;
1565 me = (_f3 - f - nf1) / _f2;
1566 if (me != mf) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001567 const s32 m = (n < 0) ? mf : me;
1568 const s32 fspur = (nf1 + m * _f2 - _f3);
1569 const s32 den = (bIsMyOutput ? n - 1 : n);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001570 if (den == 0) {
1571 fp_ = (d - fspur) * f_Scale;
1572 fm_ = (fspur - c) * f_Scale;
1573 } else {
1574 fp_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001575 (s32) RoundAwayFromZero((f - fspur) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001576 f_Scale, den);
1577 fm_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001578 (s32) RoundAwayFromZero((fspur + f) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001579 f_Scale, den);
1580 }
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001581 if (((u32) abs(fm_) >= f_Scale)
1582 && ((u32) abs(fp_) >= f_Scale)) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001583 bSpurFound = 1;
1584 break;
1585 }
1586 }
1587
1588 mb = (_f3 - c - nf1) / _f2;
1589 if (ma != mb) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001590 const s32 m = (n < 0) ? mb : ma;
1591 const s32 fspur = (nf1 + m * _f2 - _f3);
1592 const s32 den = (bIsMyOutput ? n - 1 : n);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001593 if (den == 0) {
1594 fp_ = (d - fspur) * f_Scale;
1595 fm_ = (fspur - c) * f_Scale;
1596 } else {
1597 fp_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001598 (s32) RoundAwayFromZero((-c - fspur) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001599 f_Scale, den);
1600 fm_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001601 (s32) RoundAwayFromZero((fspur + d) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001602 f_Scale, den);
1603 }
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001604 if (((u32) abs(fm_) >= f_Scale)
1605 && ((u32) abs(fp_) >= f_Scale)) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001606 bSpurFound = 1;
1607 break;
1608 }
1609 }
1610 }
1611
1612 /*
1613 ** Verify that fm & fp are both positive
1614 ** Add one to ensure next 1st IF choice is not right on the edge
1615 */
1616 if (fp_ < 0) {
1617 *fp = -fm_ + 1;
1618 *fm = -fp_ + 1;
1619 } else if (fp_ > 0) {
1620 *fp = fp_ + 1;
1621 *fm = fm_ + 1;
1622 } else {
1623 *fp = 1;
1624 *fm = abs(fm_) + 1;
1625 }
1626
1627 return bSpurFound;
1628}
1629#endif
1630
1631/****************************************************************************
1632**
1633** Name: IsSpurInBand
1634**
1635** Description: Checks to see if a spur will be present within the IF's
1636** bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW)
1637**
1638** ma mb mc md
1639** <--+-+-+-------------------+-------------------+-+-+-->
1640** | ^ 0 ^ |
1641** ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^
1642** a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2
1643**
1644** Note that some equations are doubled to prevent round-off
1645** problems when calculating fIFBW/2
1646**
1647** Parameters: pAS_Info - Avoid Spurs information block
1648** fm - If spur, amount f_IF1 has to move negative
1649** fp - If spur, amount f_IF1 has to move positive
1650**
1651** Global: None
1652**
1653** Returns: 1 if an LO spur would be present, otherwise 0.
1654**
1655** Dependencies: None.
1656**
1657** Revision History:
1658**
1659** SCR Date Author Description
1660** -------------------------------------------------------------------------
1661** N/A 11-28-2002 DAD Implemented algorithm from applied patent
1662**
1663****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001664static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info,
1665 u32 * fm, u32 * fp)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001666{
1667 /*
1668 ** Calculate LO frequency settings.
1669 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001670 u32 n, n0;
1671 const u32 f_LO1 = pAS_Info->f_LO1;
1672 const u32 f_LO2 = pAS_Info->f_LO2;
1673 const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2;
1674 const u32 c = d - pAS_Info->f_out_bw;
1675 const u32 f = pAS_Info->f_zif_bw / 2;
1676 const u32 f_Scale = (f_LO1 / (MAX_UDATA / 2 / pAS_Info->maxH1)) + 1;
1677 s32 f_nsLO1, f_nsLO2;
1678 s32 f_Spur;
1679 u32 ma, mb, mc, md, me, mf;
1680 u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001681#if MT2063_TUNER_CNT > 1
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001682 u32 index;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001683
1684 struct MT2063_AvoidSpursData_t *adj;
1685#endif
1686 *fm = 0;
1687
1688 /*
1689 ** For each edge (d, c & f), calculate a scale, based on the gcd
1690 ** of f_LO1, f_LO2 and the edge value. Use the larger of this
1691 ** gcd-based scale factor or f_Scale.
1692 */
1693 lo_gcd = MT2063_gcd(f_LO1, f_LO2);
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001694 gd_Scale = MT2063_umax((u32) MT2063_gcd(lo_gcd, d), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001695 hgds = gd_Scale / 2;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001696 gc_Scale = MT2063_umax((u32) MT2063_gcd(lo_gcd, c), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001697 hgcs = gc_Scale / 2;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001698 gf_Scale = MT2063_umax((u32) MT2063_gcd(lo_gcd, f), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001699 hgfs = gf_Scale / 2;
1700
1701 n0 = uceil(f_LO2 - d, f_LO1 - f_LO2);
1702
1703 /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */
1704 for (n = n0; n <= pAS_Info->maxH1; ++n) {
1705 md = (n * ((f_LO1 + hgds) / gd_Scale) -
1706 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
1707
1708 /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */
1709 if (md >= pAS_Info->maxH1)
1710 break;
1711
1712 ma = (n * ((f_LO1 + hgds) / gd_Scale) +
1713 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
1714
1715 /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */
1716 if (md == ma)
1717 continue;
1718
1719 mc = (n * ((f_LO1 + hgcs) / gc_Scale) -
1720 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
1721 if (mc != md) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001722 f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale));
1723 f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale));
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001724 f_Spur =
1725 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
1726 n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale);
1727
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001728 *fp = ((f_Spur - (s32) c) / (mc - n)) + 1;
1729 *fm = (((s32) d - f_Spur) / (mc - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001730 return 1;
1731 }
1732
1733 /* Location of Zero-IF-spur to be checked */
1734 me = (n * ((f_LO1 + hgfs) / gf_Scale) +
1735 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
1736 mf = (n * ((f_LO1 + hgfs) / gf_Scale) -
1737 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
1738 if (me != mf) {
1739 f_nsLO1 = n * (f_LO1 / gf_Scale);
1740 f_nsLO2 = me * (f_LO2 / gf_Scale);
1741 f_Spur =
1742 (gf_Scale * (f_nsLO1 - f_nsLO2)) +
1743 n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale);
1744
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001745 *fp = ((f_Spur + (s32) f) / (me - n)) + 1;
1746 *fm = (((s32) f - f_Spur) / (me - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001747 return 1;
1748 }
1749
1750 mb = (n * ((f_LO1 + hgcs) / gc_Scale) +
1751 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
1752 if (ma != mb) {
1753 f_nsLO1 = n * (f_LO1 / gc_Scale);
1754 f_nsLO2 = ma * (f_LO2 / gc_Scale);
1755 f_Spur =
1756 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
1757 n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale);
1758
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001759 *fp = (((s32) d + f_Spur) / (ma - n)) + 1;
1760 *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001761 return 1;
1762 }
1763 }
1764
1765#if MT2063_TUNER_CNT > 1
1766 /* If no spur found, see if there are more tuners on the same board */
1767 for (index = 0; index < TunerCount; ++index) {
1768 adj = TunerList[index];
1769 if (pAS_Info == adj) /* skip over our own data, don't process it */
1770 continue;
1771
1772 /* Look for LO-related spurs from the adjacent tuner generated into my IF output */
1773 if (IsSpurInAdjTunerBand(1, /* check my IF output */
1774 pAS_Info->f_LO1, /* my fLO1 */
1775 adj->f_LO1, /* the other tuner's fLO1 */
1776 pAS_Info->f_LO2, /* my fLO2 */
1777 pAS_Info->f_out, /* my fOut */
1778 pAS_Info->f_out_bw, /* my output IF bandwidth */
1779 pAS_Info->f_zif_bw, /* my Zero-IF bandwidth */
1780 pAS_Info->maxH2, fp, /* minimum amount to move LO's positive */
1781 fm)) /* miminum amount to move LO's negative */
1782 return 1;
1783 /* Look for LO-related spurs from my tuner generated into the adjacent tuner's IF output */
1784 if (IsSpurInAdjTunerBand(0, /* check his IF output */
1785 pAS_Info->f_LO1, /* my fLO1 */
1786 adj->f_LO1, /* the other tuner's fLO1 */
1787 adj->f_LO2, /* the other tuner's fLO2 */
1788 adj->f_out, /* the other tuner's fOut */
1789 adj->f_out_bw, /* the other tuner's output IF bandwidth */
1790 pAS_Info->f_zif_bw, /* the other tuner's Zero-IF bandwidth */
1791 adj->maxH2, fp, /* minimum amount to move LO's positive */
1792 fm)) /* miminum amount to move LO's negative */
1793 return 1;
1794 }
1795#endif
1796 /* No spurs found */
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001797 return 0;
1798}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001799
1800/*****************************************************************************
1801**
1802** Name: MT_AvoidSpurs
1803**
1804** Description: Main entry point to avoid spurs.
1805** Checks for existing spurs in present LO1, LO2 freqs
1806** and if present, chooses spur-free LO1, LO2 combination
1807** that tunes the same input/output frequencies.
1808**
1809** Revision History:
1810**
1811** SCR Date Author Description
1812** -------------------------------------------------------------------------
1813** 096 04-06-2005 DAD Ver 1.11: Fix divide by 0 error if maxH==0.
1814**
1815*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001816static u32 MT2063_AvoidSpurs(void *h, struct MT2063_AvoidSpursData_t * pAS_Info)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001817{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001818 u32 status = MT2063_OK;
1819 u32 fm, fp; /* restricted range on LO's */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001820 pAS_Info->bSpurAvoided = 0;
1821 pAS_Info->nSpursFound = 0;
1822
1823 if (pAS_Info->maxH1 == 0)
1824 return MT2063_OK;
1825
1826 /*
1827 ** Avoid LO Generated Spurs
1828 **
1829 ** Make sure that have no LO-related spurs within the IF output
1830 ** bandwidth.
1831 **
1832 ** If there is an LO spur in this band, start at the current IF1 frequency
1833 ** and work out until we find a spur-free frequency or run up against the
1834 ** 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they
1835 ** will be unchanged if a spur-free setting is not found.
1836 */
1837 pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
1838 if (pAS_Info->bSpurPresent) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001839 u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */
1840 u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */
1841 u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */
1842 u32 delta_IF1;
1843 u32 new_IF1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001844
1845 /*
1846 ** Spur was found, attempt to find a spur-free 1st IF
1847 */
1848 do {
1849 pAS_Info->nSpursFound++;
1850
1851 /* Raise f_IF1_upper, if needed */
1852 MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp);
1853
1854 /* Choose next IF1 that is closest to f_IF1_CENTER */
1855 new_IF1 = MT2063_ChooseFirstIF(pAS_Info);
1856
1857 if (new_IF1 > zfIF1) {
1858 pAS_Info->f_LO1 += (new_IF1 - zfIF1);
1859 pAS_Info->f_LO2 += (new_IF1 - zfIF1);
1860 } else {
1861 pAS_Info->f_LO1 -= (zfIF1 - new_IF1);
1862 pAS_Info->f_LO2 -= (zfIF1 - new_IF1);
1863 }
1864 zfIF1 = new_IF1;
1865
1866 if (zfIF1 > pAS_Info->f_if1_Center)
1867 delta_IF1 = zfIF1 - pAS_Info->f_if1_Center;
1868 else
1869 delta_IF1 = pAS_Info->f_if1_Center - zfIF1;
1870 }
1871 /*
1872 ** Continue while the new 1st IF is still within the 1st IF bandwidth
1873 ** and there is a spur in the band (again)
1874 */
1875 while ((2 * delta_IF1 + pAS_Info->f_out_bw <=
1876 pAS_Info->f_if1_bw)
1877 && (pAS_Info->bSpurPresent =
1878 IsSpurInBand(pAS_Info, &fm, &fp)));
1879
1880 /*
1881 ** Use the LO-spur free values found. If the search went all the way to
1882 ** the 1st IF band edge and always found spurs, just leave the original
1883 ** choice. It's as "good" as any other.
1884 */
1885 if (pAS_Info->bSpurPresent == 1) {
1886 status |= MT2063_SPUR_PRESENT_ERR;
1887 pAS_Info->f_LO1 = zfLO1;
1888 pAS_Info->f_LO2 = zfLO2;
1889 } else
1890 pAS_Info->bSpurAvoided = 1;
1891 }
1892
1893 status |=
1894 ((pAS_Info->
1895 nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK);
1896
1897 return (status);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001898}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001899
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001900//end of mt2063_spuravoid.c
1901//=================================================================
1902//#################################################################
1903//=================================================================
1904
1905/*
1906** The expected version of MT_AvoidSpursData_t
1907** If the version is different, an updated file is needed from Microtune
1908*/
1909/* Expecting version 1.21 of the Spur Avoidance API */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001910
1911typedef enum {
1912 MT2063_SET_ATTEN,
1913 MT2063_INCR_ATTEN,
1914 MT2063_DECR_ATTEN
1915} MT2063_ATTEN_CNTL_MODE;
1916
1917//#define TUNER_MT2063_OPTIMIZATION
1918/*
1919** Constants used by the tuning algorithm
1920*/
1921#define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */
1922#define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */
1923#define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */
1924#define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */
1925#define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */
1926#define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */
1927#define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */
1928#define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */
1929#define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */
1930#define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */
1931#define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */
1932#define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */
1933#define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */
1934#define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */
1935#define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */
1936#define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */
1937#define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */
1938#define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */
1939
1940/*
1941** Define the supported Part/Rev codes for the MT2063
1942*/
1943#define MT2063_B0 (0x9B)
1944#define MT2063_B1 (0x9C)
1945#define MT2063_B2 (0x9D)
1946#define MT2063_B3 (0x9E)
1947
1948/*
1949** The number of Tuner Registers
1950*/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001951static const u32 MT2063_Num_Registers = MT2063_REG_END_REGS;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001952
1953#define USE_GLOBAL_TUNER 0
1954
Mauro Carvalho Chehaba0813ea2011-07-20 21:19:08 -03001955static u32 nMT2063MaxTuners = 1;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001956static u32 nMT2063OpenTuners = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001957
1958/*
1959** Constants for setting receiver modes.
1960** (6 modes defined at this time, enumerated by MT2063_RCVR_MODES)
1961** (DNC1GC & DNC2GC are the values, which are used, when the specific
1962** DNC Output is selected, the other is always off)
1963**
1964** If PAL-L or L' is received, set:
1965** MT2063_SetParam(hMT2063,MT2063_TAGC,1);
1966**
1967** --------------+----------------------------------------------
1968** Mode 0 : | MT2063_CABLE_QAM
1969** Mode 1 : | MT2063_CABLE_ANALOG
1970** Mode 2 : | MT2063_OFFAIR_COFDM
1971** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
1972** Mode 4 : | MT2063_OFFAIR_ANALOG
1973** Mode 5 : | MT2063_OFFAIR_8VSB
1974** --------------+----+----+----+----+-----+-----+--------------
1975** Mode | 0 | 1 | 2 | 3 | 4 | 5 |
1976** --------------+----+----+----+----+-----+-----+
1977**
1978**
1979*/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001980static const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 };
1981static const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 };
1982static const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 };
1983static const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 };
1984static const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 };
1985static const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 };
1986static const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 };
1987static const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 };
1988static const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
1989static const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 };
1990static const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 };
1991static const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
1992static const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 };
1993static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 };
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001994
1995/*
1996** Local Function Prototypes - not available for external access.
1997*/
1998
1999/* Forward declaration(s): */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002000static u32 MT2063_CalcLO1Mult(u32 * Div, u32 * FracN, u32 f_LO,
2001 u32 f_LO_Step, u32 f_Ref);
2002static u32 MT2063_CalcLO2Mult(u32 * Div, u32 * FracN, u32 f_LO,
2003 u32 f_LO_Step, u32 f_Ref);
2004static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num,
2005 u32 denom);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002006
2007/******************************************************************************
2008**
2009** Name: MT2063_Open
2010**
2011** Description: Initialize the tuner's register values.
2012**
2013** Parameters: MT2063_Addr - Serial bus address of the tuner.
2014** hMT2063 - Tuner handle passed back.
2015** hUserData - User-defined data, if needed for the
2016** MT_ReadSub() & MT_WriteSub functions.
2017**
2018** Returns: status:
2019** MT_OK - No errors
2020** MT_TUNER_ID_ERR - Tuner Part/Rev code mismatch
2021** MT_TUNER_INIT_ERR - Tuner initialization failed
2022** MT_COMM_ERR - Serial bus communications error
2023** MT_ARG_NULL - Null pointer argument passed
2024** MT_TUNER_CNT_ERR - Too many tuners open
2025**
2026** Dependencies: MT_ReadSub - Read byte(s) of data from the two-wire bus
2027** MT_WriteSub - Write byte(s) of data to the two-wire bus
2028**
2029** Revision History:
2030**
2031** SCR Date Author Description
2032** -------------------------------------------------------------------------
2033** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2034**
2035******************************************************************************/
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -03002036static u32 MT2063_Open(u32 MT2063_Addr, struct MT2063_Info_t **hMT2063, void *hUserData)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002037{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002038 u32 status = MT2063_OK; /* Status to be returned. */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002039 struct MT2063_Info_t *pInfo = NULL;
2040 struct dvb_frontend *fe = (struct dvb_frontend *)hUserData;
2041 struct mt2063_state *state = fe->tuner_priv;
2042
2043 /* Check the argument before using */
2044 if (hMT2063 == NULL) {
2045 return MT2063_ARG_NULL;
2046 }
2047
2048 /* Default tuner handle to NULL. If successful, it will be reassigned */
2049
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002050 if (state->MT2063_init == false) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002051 pInfo = kzalloc(sizeof(struct MT2063_Info_t), GFP_KERNEL);
2052 if (pInfo == NULL) {
2053 return MT2063_TUNER_OPEN_ERR;
2054 }
2055 pInfo->handle = NULL;
2056 pInfo->address = MAX_UDATA;
2057 pInfo->rcvr_mode = MT2063_CABLE_QAM;
2058 pInfo->hUserData = NULL;
2059 } else {
2060 pInfo = *hMT2063;
2061 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002062
2063 if (MT2063_NO_ERROR(status)) {
2064 status |= MT2063_RegisterTuner(&pInfo->AS_Data);
2065 }
2066
2067 if (MT2063_NO_ERROR(status)) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002068 pInfo->handle = (void *) pInfo;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002069
2070 pInfo->hUserData = hUserData;
2071 pInfo->address = MT2063_Addr;
2072 pInfo->rcvr_mode = MT2063_CABLE_QAM;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002073 status |= MT2063_ReInit((void *) pInfo);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002074 }
2075
2076 if (MT2063_IS_ERROR(status))
2077 /* MT2063_Close handles the un-registration of the tuner */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002078 MT2063_Close((void *) pInfo);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002079 else {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002080 state->MT2063_init = true;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002081 *hMT2063 = pInfo->handle;
2082
2083 }
2084
2085 return (status);
2086}
2087
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002088static u32 MT2063_IsValidHandle(struct MT2063_Info_t *handle)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002089{
2090 return ((handle != NULL) && (handle->handle == handle)) ? 1 : 0;
2091}
2092
2093/******************************************************************************
2094**
2095** Name: MT2063_Close
2096**
2097** Description: Release the handle to the tuner.
2098**
2099** Parameters: hMT2063 - Handle to the MT2063 tuner
2100**
2101** Returns: status:
2102** MT_OK - No errors
2103** MT_INV_HANDLE - Invalid tuner handle
2104**
2105** Dependencies: mt_errordef.h - definition of error codes
2106**
2107** Revision History:
2108**
2109** SCR Date Author Description
2110** -------------------------------------------------------------------------
2111** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2112**
2113******************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002114static u32 MT2063_Close(void *hMT2063)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002115{
2116 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)hMT2063;
2117
2118 if (!MT2063_IsValidHandle(pInfo))
2119 return MT2063_INV_HANDLE;
2120
2121 /* Unregister tuner with SpurAvoidance routines (if needed) */
2122 MT2063_UnRegisterTuner(&pInfo->AS_Data);
2123 /* Now remove the tuner from our own list of tuners */
2124 pInfo->handle = NULL;
2125 pInfo->address = MAX_UDATA;
2126 pInfo->hUserData = NULL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002127 //kfree(pInfo);
2128 //pInfo = NULL;
Mauro Carvalho Chehaba0813ea2011-07-20 21:19:08 -03002129
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002130 return MT2063_OK;
2131}
2132
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002133/****************************************************************************
2134**
2135** Name: MT2063_GetLocked
2136**
2137** Description: Checks to see if LO1 and LO2 are locked.
2138**
2139** Parameters: h - Open handle to the tuner (from MT2063_Open).
2140**
2141** Returns: status:
2142** MT_OK - No errors
2143** MT_UPC_UNLOCK - Upconverter PLL unlocked
2144** MT_DNC_UNLOCK - Downconverter PLL unlocked
2145** MT_COMM_ERR - Serial bus communications error
2146** MT_INV_HANDLE - Invalid tuner handle
2147**
2148** Dependencies: MT_ReadSub - Read byte(s) of data from the serial bus
2149** MT_Sleep - Delay execution for x milliseconds
2150**
2151** Revision History:
2152**
2153** SCR Date Author Description
2154** -------------------------------------------------------------------------
2155** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2156**
2157****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002158static u32 MT2063_GetLocked(void *h)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002159{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002160 const u32 nMaxWait = 100; /* wait a maximum of 100 msec */
2161 const u32 nPollRate = 2; /* poll status bits every 2 ms */
2162 const u32 nMaxLoops = nMaxWait / nPollRate;
2163 const u8 LO1LK = 0x80;
2164 u8 LO2LK = 0x08;
2165 u32 status = MT2063_OK; /* Status to be returned */
2166 u32 nDelays = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002167 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
2168
2169 if (MT2063_IsValidHandle(pInfo) == 0)
2170 return MT2063_INV_HANDLE;
2171
2172 /* LO2 Lock bit was in a different place for B0 version */
2173 if (pInfo->tuner_id == MT2063_B0)
2174 LO2LK = 0x40;
2175
2176 do {
2177 status |=
2178 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
2179 MT2063_REG_LO_STATUS,
2180 &pInfo->reg[MT2063_REG_LO_STATUS], 1);
2181
2182 if (MT2063_IS_ERROR(status))
2183 return (status);
2184
2185 if ((pInfo->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) ==
2186 (LO1LK | LO2LK)) {
2187 return (status);
2188 }
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002189 msleep(nPollRate); /* Wait between retries */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002190 }
2191 while (++nDelays < nMaxLoops);
2192
2193 if ((pInfo->reg[MT2063_REG_LO_STATUS] & LO1LK) == 0x00)
2194 status |= MT2063_UPC_UNLOCK;
2195 if ((pInfo->reg[MT2063_REG_LO_STATUS] & LO2LK) == 0x00)
2196 status |= MT2063_DNC_UNLOCK;
2197
2198 return (status);
2199}
2200
2201/****************************************************************************
2202**
2203** Name: MT2063_GetParam
2204**
2205** Description: Gets a tuning algorithm parameter.
2206**
2207** This function provides access to the internals of the
2208** tuning algorithm - mostly for testing purposes.
2209**
2210** Parameters: h - Tuner handle (returned by MT2063_Open)
2211** param - Tuning algorithm parameter
2212** (see enum MT2063_Param)
2213** pValue - ptr to returned value
2214**
2215** param Description
2216** ---------------------- --------------------------------
2217** MT2063_IC_ADDR Serial Bus address of this tuner
2218** MT2063_MAX_OPEN Max # of MT2063's allowed open
2219** MT2063_NUM_OPEN # of MT2063's open
2220** MT2063_SRO_FREQ crystal frequency
2221** MT2063_STEPSIZE minimum tuning step size
2222** MT2063_INPUT_FREQ input center frequency
2223** MT2063_LO1_FREQ LO1 Frequency
2224** MT2063_LO1_STEPSIZE LO1 minimum step size
2225** MT2063_LO1_FRACN_AVOID LO1 FracN keep-out region
2226** MT2063_IF1_ACTUAL Current 1st IF in use
2227** MT2063_IF1_REQUEST Requested 1st IF
2228** MT2063_IF1_CENTER Center of 1st IF SAW filter
2229** MT2063_IF1_BW Bandwidth of 1st IF SAW filter
2230** MT2063_ZIF_BW zero-IF bandwidth
2231** MT2063_LO2_FREQ LO2 Frequency
2232** MT2063_LO2_STEPSIZE LO2 minimum step size
2233** MT2063_LO2_FRACN_AVOID LO2 FracN keep-out region
2234** MT2063_OUTPUT_FREQ output center frequency
2235** MT2063_OUTPUT_BW output bandwidth
2236** MT2063_LO_SEPARATION min inter-tuner LO separation
2237** MT2063_AS_ALG ID of avoid-spurs algorithm in use
2238** MT2063_MAX_HARM1 max # of intra-tuner harmonics
2239** MT2063_MAX_HARM2 max # of inter-tuner harmonics
2240** MT2063_EXCL_ZONES # of 1st IF exclusion zones
2241** MT2063_NUM_SPURS # of spurs found/avoided
2242** MT2063_SPUR_AVOIDED >0 spurs avoided
2243** MT2063_SPUR_PRESENT >0 spurs in output (mathematically)
2244** MT2063_RCVR_MODE Predefined modes.
2245** MT2063_ACLNA LNA attenuator gain code
2246** MT2063_ACRF RF attenuator gain code
2247** MT2063_ACFIF FIF attenuator gain code
2248** MT2063_ACLNA_MAX LNA attenuator limit
2249** MT2063_ACRF_MAX RF attenuator limit
2250** MT2063_ACFIF_MAX FIF attenuator limit
2251** MT2063_PD1 Actual value of PD1
2252** MT2063_PD2 Actual value of PD2
2253** MT2063_DNC_OUTPUT_ENABLE DNC output selection
2254** MT2063_VGAGC VGA gain code
2255** MT2063_VGAOI VGA output current
2256** MT2063_TAGC TAGC setting
2257** MT2063_AMPGC AMP gain code
2258** MT2063_AVOID_DECT Avoid DECT Frequencies
2259** MT2063_CTFILT_SW Cleartune filter selection
2260**
2261** Usage: status |= MT2063_GetParam(hMT2063,
2262** MT2063_IF1_ACTUAL,
2263** &f_IF1_Actual);
2264**
2265** Returns: status:
2266** MT_OK - No errors
2267** MT_INV_HANDLE - Invalid tuner handle
2268** MT_ARG_NULL - Null pointer argument passed
2269** MT_ARG_RANGE - Invalid parameter requested
2270**
2271** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
2272**
2273** See Also: MT2063_SetParam, MT2063_Open
2274**
2275** Revision History:
2276**
2277** SCR Date Author Description
2278** -------------------------------------------------------------------------
2279** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2280** 154 09-13-2007 RSK Ver 1.05: Get/SetParam changes for LOx_FREQ
2281** 10-31-2007 PINZ Ver 1.08: Get/SetParam add VGAGC, VGAOI, AMPGC, TAGC
2282** 173 M 01-23-2008 RSK Ver 1.12: Read LO1C and LO2C registers from HW
2283** in GetParam.
2284** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
2285** Split SetParam up to ACLNA / ACLNA_MAX
2286** removed ACLNA_INRC/DECR (+RF & FIF)
2287** removed GCUAUTO / BYPATNDN/UP
2288** 175 I 16-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
2289** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
2290** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
2291**
2292****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002293static u32 MT2063_GetParam(void *h, enum MT2063_Param param, u32 * pValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002294{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002295 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002296 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002297 u32 Div;
2298 u32 Num;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002299
2300 if (pValue == NULL)
2301 status |= MT2063_ARG_NULL;
2302
2303 /* Verify that the handle passed points to a valid tuner */
2304 if (MT2063_IsValidHandle(pInfo) == 0)
2305 status |= MT2063_INV_HANDLE;
2306
2307 if (MT2063_NO_ERROR(status)) {
2308 switch (param) {
2309 /* Serial Bus address of this tuner */
2310 case MT2063_IC_ADDR:
2311 *pValue = pInfo->address;
2312 break;
2313
2314 /* Max # of MT2063's allowed to be open */
2315 case MT2063_MAX_OPEN:
2316 *pValue = nMT2063MaxTuners;
2317 break;
2318
2319 /* # of MT2063's open */
2320 case MT2063_NUM_OPEN:
2321 *pValue = nMT2063OpenTuners;
2322 break;
2323
2324 /* crystal frequency */
2325 case MT2063_SRO_FREQ:
2326 *pValue = pInfo->AS_Data.f_ref;
2327 break;
2328
2329 /* minimum tuning step size */
2330 case MT2063_STEPSIZE:
2331 *pValue = pInfo->AS_Data.f_LO2_Step;
2332 break;
2333
2334 /* input center frequency */
2335 case MT2063_INPUT_FREQ:
2336 *pValue = pInfo->AS_Data.f_in;
2337 break;
2338
2339 /* LO1 Frequency */
2340 case MT2063_LO1_FREQ:
2341 {
2342 /* read the actual tuner register values for LO1C_1 and LO1C_2 */
2343 status |=
2344 MT2063_ReadSub(pInfo->hUserData,
2345 pInfo->address,
2346 MT2063_REG_LO1C_1,
2347 &pInfo->
2348 reg[MT2063_REG_LO1C_1], 2);
2349 Div = pInfo->reg[MT2063_REG_LO1C_1];
2350 Num = pInfo->reg[MT2063_REG_LO1C_2] & 0x3F;
2351 pInfo->AS_Data.f_LO1 =
2352 (pInfo->AS_Data.f_ref * Div) +
2353 MT2063_fLO_FractionalTerm(pInfo->AS_Data.
2354 f_ref, Num, 64);
2355 }
2356 *pValue = pInfo->AS_Data.f_LO1;
2357 break;
2358
2359 /* LO1 minimum step size */
2360 case MT2063_LO1_STEPSIZE:
2361 *pValue = pInfo->AS_Data.f_LO1_Step;
2362 break;
2363
2364 /* LO1 FracN keep-out region */
2365 case MT2063_LO1_FRACN_AVOID_PARAM:
2366 *pValue = pInfo->AS_Data.f_LO1_FracN_Avoid;
2367 break;
2368
2369 /* Current 1st IF in use */
2370 case MT2063_IF1_ACTUAL:
2371 *pValue = pInfo->f_IF1_actual;
2372 break;
2373
2374 /* Requested 1st IF */
2375 case MT2063_IF1_REQUEST:
2376 *pValue = pInfo->AS_Data.f_if1_Request;
2377 break;
2378
2379 /* Center of 1st IF SAW filter */
2380 case MT2063_IF1_CENTER:
2381 *pValue = pInfo->AS_Data.f_if1_Center;
2382 break;
2383
2384 /* Bandwidth of 1st IF SAW filter */
2385 case MT2063_IF1_BW:
2386 *pValue = pInfo->AS_Data.f_if1_bw;
2387 break;
2388
2389 /* zero-IF bandwidth */
2390 case MT2063_ZIF_BW:
2391 *pValue = pInfo->AS_Data.f_zif_bw;
2392 break;
2393
2394 /* LO2 Frequency */
2395 case MT2063_LO2_FREQ:
2396 {
2397 /* Read the actual tuner register values for LO2C_1, LO2C_2 and LO2C_3 */
2398 status |=
2399 MT2063_ReadSub(pInfo->hUserData,
2400 pInfo->address,
2401 MT2063_REG_LO2C_1,
2402 &pInfo->
2403 reg[MT2063_REG_LO2C_1], 3);
2404 Div =
2405 (pInfo->reg[MT2063_REG_LO2C_1] & 0xFE) >> 1;
2406 Num =
2407 ((pInfo->
2408 reg[MT2063_REG_LO2C_1] & 0x01) << 12) |
2409 (pInfo->
2410 reg[MT2063_REG_LO2C_2] << 4) | (pInfo->
2411 reg
2412 [MT2063_REG_LO2C_3]
2413 & 0x00F);
2414 pInfo->AS_Data.f_LO2 =
2415 (pInfo->AS_Data.f_ref * Div) +
2416 MT2063_fLO_FractionalTerm(pInfo->AS_Data.
2417 f_ref, Num, 8191);
2418 }
2419 *pValue = pInfo->AS_Data.f_LO2;
2420 break;
2421
2422 /* LO2 minimum step size */
2423 case MT2063_LO2_STEPSIZE:
2424 *pValue = pInfo->AS_Data.f_LO2_Step;
2425 break;
2426
2427 /* LO2 FracN keep-out region */
2428 case MT2063_LO2_FRACN_AVOID:
2429 *pValue = pInfo->AS_Data.f_LO2_FracN_Avoid;
2430 break;
2431
2432 /* output center frequency */
2433 case MT2063_OUTPUT_FREQ:
2434 *pValue = pInfo->AS_Data.f_out;
2435 break;
2436
2437 /* output bandwidth */
2438 case MT2063_OUTPUT_BW:
2439 *pValue = pInfo->AS_Data.f_out_bw - 750000;
2440 break;
2441
2442 /* min inter-tuner LO separation */
2443 case MT2063_LO_SEPARATION:
2444 *pValue = pInfo->AS_Data.f_min_LO_Separation;
2445 break;
2446
2447 /* ID of avoid-spurs algorithm in use */
2448 case MT2063_AS_ALG:
2449 *pValue = pInfo->AS_Data.nAS_Algorithm;
2450 break;
2451
2452 /* max # of intra-tuner harmonics */
2453 case MT2063_MAX_HARM1:
2454 *pValue = pInfo->AS_Data.maxH1;
2455 break;
2456
2457 /* max # of inter-tuner harmonics */
2458 case MT2063_MAX_HARM2:
2459 *pValue = pInfo->AS_Data.maxH2;
2460 break;
2461
2462 /* # of 1st IF exclusion zones */
2463 case MT2063_EXCL_ZONES:
2464 *pValue = pInfo->AS_Data.nZones;
2465 break;
2466
2467 /* # of spurs found/avoided */
2468 case MT2063_NUM_SPURS:
2469 *pValue = pInfo->AS_Data.nSpursFound;
2470 break;
2471
2472 /* >0 spurs avoided */
2473 case MT2063_SPUR_AVOIDED:
2474 *pValue = pInfo->AS_Data.bSpurAvoided;
2475 break;
2476
2477 /* >0 spurs in output (mathematically) */
2478 case MT2063_SPUR_PRESENT:
2479 *pValue = pInfo->AS_Data.bSpurPresent;
2480 break;
2481
2482 /* Predefined receiver setup combination */
2483 case MT2063_RCVR_MODE:
2484 *pValue = pInfo->rcvr_mode;
2485 break;
2486
2487 case MT2063_PD1:
2488 case MT2063_PD2:
2489 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002490 u8 mask = (param == MT2063_PD1 ? 0x01 : 0x03); /* PD1 vs PD2 */
2491 u8 orig = (pInfo->reg[MT2063_REG_BYP_CTRL]);
2492 u8 reg = (orig & 0xF1) | mask; /* Only set 3 bits (not 5) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002493 int i;
2494
2495 *pValue = 0;
2496
2497 /* Initiate ADC output to reg 0x0A */
2498 if (reg != orig)
2499 status |=
2500 MT2063_WriteSub(pInfo->hUserData,
2501 pInfo->address,
2502 MT2063_REG_BYP_CTRL,
2503 &reg, 1);
2504
2505 if (MT2063_IS_ERROR(status))
2506 return (status);
2507
2508 for (i = 0; i < 8; i++) {
2509 status |=
2510 MT2063_ReadSub(pInfo->hUserData,
2511 pInfo->address,
2512 MT2063_REG_ADC_OUT,
2513 &pInfo->
2514 reg
2515 [MT2063_REG_ADC_OUT],
2516 1);
2517
2518 if (MT2063_NO_ERROR(status))
2519 *pValue +=
2520 pInfo->
2521 reg[MT2063_REG_ADC_OUT];
2522 else {
2523 if (i)
2524 *pValue /= i;
2525 return (status);
2526 }
2527 }
2528 *pValue /= 8; /* divide by number of reads */
2529 *pValue >>= 2; /* only want 6 MSB's out of 8 */
2530
2531 /* Restore value of Register BYP_CTRL */
2532 if (reg != orig)
2533 status |=
2534 MT2063_WriteSub(pInfo->hUserData,
2535 pInfo->address,
2536 MT2063_REG_BYP_CTRL,
2537 &orig, 1);
2538 }
2539 break;
2540
2541 /* Get LNA attenuator code */
2542 case MT2063_ACLNA:
2543 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002544 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002545 status |=
2546 MT2063_GetReg(pInfo, MT2063_REG_XO_STATUS,
2547 &val);
2548 *pValue = val & 0x1f;
2549 }
2550 break;
2551
2552 /* Get RF attenuator code */
2553 case MT2063_ACRF:
2554 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002555 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002556 status |=
2557 MT2063_GetReg(pInfo, MT2063_REG_RF_STATUS,
2558 &val);
2559 *pValue = val & 0x1f;
2560 }
2561 break;
2562
2563 /* Get FIF attenuator code */
2564 case MT2063_ACFIF:
2565 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002566 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002567 status |=
2568 MT2063_GetReg(pInfo, MT2063_REG_FIF_STATUS,
2569 &val);
2570 *pValue = val & 0x1f;
2571 }
2572 break;
2573
2574 /* Get LNA attenuator limit */
2575 case MT2063_ACLNA_MAX:
2576 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002577 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002578 status |=
2579 MT2063_GetReg(pInfo, MT2063_REG_LNA_OV,
2580 &val);
2581 *pValue = val & 0x1f;
2582 }
2583 break;
2584
2585 /* Get RF attenuator limit */
2586 case MT2063_ACRF_MAX:
2587 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002588 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002589 status |=
2590 MT2063_GetReg(pInfo, MT2063_REG_RF_OV,
2591 &val);
2592 *pValue = val & 0x1f;
2593 }
2594 break;
2595
2596 /* Get FIF attenuator limit */
2597 case MT2063_ACFIF_MAX:
2598 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002599 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002600 status |=
2601 MT2063_GetReg(pInfo, MT2063_REG_FIF_OV,
2602 &val);
2603 *pValue = val & 0x1f;
2604 }
2605 break;
2606
2607 /* Get current used DNC output */
2608 case MT2063_DNC_OUTPUT_ENABLE:
2609 {
2610 if ((pInfo->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */
2611 if ((pInfo->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
2612 *pValue =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002613 (u32) MT2063_DNC_NONE;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002614 else
2615 *pValue =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002616 (u32) MT2063_DNC_2;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002617 } else { /* DNC1 is on */
2618
2619 if ((pInfo->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
2620 *pValue =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002621 (u32) MT2063_DNC_1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002622 else
2623 *pValue =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002624 (u32) MT2063_DNC_BOTH;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002625 }
2626 }
2627 break;
2628
2629 /* Get VGA Gain Code */
2630 case MT2063_VGAGC:
2631 *pValue =
2632 ((pInfo->reg[MT2063_REG_VGA_GAIN] & 0x0C) >> 2);
2633 break;
2634
2635 /* Get VGA bias current */
2636 case MT2063_VGAOI:
2637 *pValue = (pInfo->reg[MT2063_REG_RSVD_31] & 0x07);
2638 break;
2639
2640 /* Get TAGC setting */
2641 case MT2063_TAGC:
2642 *pValue = (pInfo->reg[MT2063_REG_RSVD_1E] & 0x03);
2643 break;
2644
2645 /* Get AMP Gain Code */
2646 case MT2063_AMPGC:
2647 *pValue = (pInfo->reg[MT2063_REG_TEMP_SEL] & 0x03);
2648 break;
2649
2650 /* Avoid DECT Frequencies */
2651 case MT2063_AVOID_DECT:
2652 *pValue = pInfo->AS_Data.avoidDECT;
2653 break;
2654
2655 /* Cleartune filter selection: 0 - by IC (default), 1 - by software */
2656 case MT2063_CTFILT_SW:
2657 *pValue = pInfo->ctfilt_sw;
2658 break;
2659
2660 case MT2063_EOP:
2661 default:
2662 status |= MT2063_ARG_RANGE;
2663 }
2664 }
2665 return (status);
2666}
2667
2668/****************************************************************************
2669**
2670** Name: MT2063_GetReg
2671**
2672** Description: Gets an MT2063 register.
2673**
2674** Parameters: h - Tuner handle (returned by MT2063_Open)
2675** reg - MT2063 register/subaddress location
2676** *val - MT2063 register/subaddress value
2677**
2678** Returns: status:
2679** MT_OK - No errors
2680** MT_COMM_ERR - Serial bus communications error
2681** MT_INV_HANDLE - Invalid tuner handle
2682** MT_ARG_NULL - Null pointer argument passed
2683** MT_ARG_RANGE - Argument out of range
2684**
2685** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
2686**
2687** Use this function if you need to read a register from
2688** the MT2063.
2689**
2690** Revision History:
2691**
2692** SCR Date Author Description
2693** -------------------------------------------------------------------------
2694** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2695**
2696****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002697static u32 MT2063_GetReg(void *h, u8 reg, u8 * val)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002698{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002699 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002700 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
2701
2702 /* Verify that the handle passed points to a valid tuner */
2703 if (MT2063_IsValidHandle(pInfo) == 0)
2704 status |= MT2063_INV_HANDLE;
2705
2706 if (val == NULL)
2707 status |= MT2063_ARG_NULL;
2708
2709 if (reg >= MT2063_REG_END_REGS)
2710 status |= MT2063_ARG_RANGE;
2711
2712 if (MT2063_NO_ERROR(status)) {
2713 status |=
2714 MT2063_ReadSub(pInfo->hUserData, pInfo->address, reg,
2715 &pInfo->reg[reg], 1);
2716 if (MT2063_NO_ERROR(status))
2717 *val = pInfo->reg[reg];
2718 }
2719
2720 return (status);
2721}
2722
2723/******************************************************************************
2724**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002725** Name: MT2063_SetReceiverMode
2726**
2727** Description: Set the MT2063 receiver mode
2728**
2729** --------------+----------------------------------------------
2730** Mode 0 : | MT2063_CABLE_QAM
2731** Mode 1 : | MT2063_CABLE_ANALOG
2732** Mode 2 : | MT2063_OFFAIR_COFDM
2733** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
2734** Mode 4 : | MT2063_OFFAIR_ANALOG
2735** Mode 5 : | MT2063_OFFAIR_8VSB
2736** --------------+----+----+----+----+-----+--------------------
2737** (DNC1GC & DNC2GC are the values, which are used, when the specific
2738** DNC Output is selected, the other is always off)
2739**
2740** |<---------- Mode -------------->|
2741** Reg Field | 0 | 1 | 2 | 3 | 4 | 5 |
2742** ------------+-----+-----+-----+-----+-----+-----+
2743** RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF
2744** LNARin | 0 | 0 | 3 | 3 | 3 | 3
2745** FIFFQen | 1 | 1 | 1 | 1 | 1 | 1
2746** FIFFq | 0 | 0 | 0 | 0 | 0 | 0
2747** DNC1gc | 0 | 0 | 0 | 0 | 0 | 0
2748** DNC2gc | 0 | 0 | 0 | 0 | 0 | 0
2749** GCU Auto | 1 | 1 | 1 | 1 | 1 | 1
2750** LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31
2751** LNA Target | 44 | 43 | 43 | 43 | 43 | 43
2752** ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0
2753** RF max Atn | 31 | 31 | 31 | 31 | 31 | 31
2754** PD1 Target | 36 | 36 | 38 | 38 | 36 | 38
2755** ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0
2756** FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5
2757** PD2 Target | 40 | 33 | 42 | 42 | 33 | 42
2758**
2759**
2760** Parameters: pInfo - ptr to MT2063_Info_t structure
2761** Mode - desired reciever mode
2762**
2763** Usage: status = MT2063_SetReceiverMode(hMT2063, Mode);
2764**
2765** Returns: status:
2766** MT_OK - No errors
2767** MT_COMM_ERR - Serial bus communications error
2768**
2769** Dependencies: MT2063_SetReg - Write a byte of data to a HW register.
2770** Assumes that the tuner cache is valid.
2771**
2772** Revision History:
2773**
2774** SCR Date Author Description
2775** -------------------------------------------------------------------------
2776** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2777** N/A 01-10-2007 PINZ Added additional GCU Settings, FIFF Calib will be triggered
2778** 155 10-01-2007 DAD Ver 1.06: Add receiver mode for SECAM positive
2779** modulation
2780** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
2781** N/A 10-22-2007 PINZ Ver 1.07: Changed some Registers at init to have
2782** the same settings as with MT Launcher
2783** N/A 10-30-2007 PINZ Add SetParam VGAGC & VGAOI
2784** Add SetParam DNC_OUTPUT_ENABLE
2785** Removed VGAGC from receiver mode,
2786** default now 1
2787** N/A 10-31-2007 PINZ Ver 1.08: Add SetParam TAGC, removed from rcvr-mode
2788** Add SetParam AMPGC, removed from rcvr-mode
2789** Corrected names of GCU values
2790** reorganized receiver modes, removed,
2791** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
2792** Actualized Receiver-Mode values
2793** N/A 11-12-2007 PINZ Ver 1.09: Actualized Receiver-Mode values
2794** N/A 11-27-2007 PINZ Improved buffered writing
2795** 01-03-2008 PINZ Ver 1.10: Added a trigger of BYPATNUP for
2796** correct wakeup of the LNA after shutdown
2797** Set AFCsd = 1 as default
2798** Changed CAP1sel default
2799** 01-14-2008 PINZ Ver 1.11: Updated gain settings
2800** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
2801** Split SetParam up to ACLNA / ACLNA_MAX
2802** removed ACLNA_INRC/DECR (+RF & FIF)
2803** removed GCUAUTO / BYPATNDN/UP
2804**
2805******************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002806static u32 MT2063_SetReceiverMode(struct MT2063_Info_t *pInfo,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002807 enum MT2063_RCVR_MODES Mode)
2808{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002809 u32 status = MT2063_OK; /* Status to be returned */
2810 u8 val;
2811 u32 longval;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002812
2813 if (Mode >= MT2063_NUM_RCVR_MODES)
2814 status = MT2063_ARG_RANGE;
2815
2816 /* RFAGCen */
2817 if (MT2063_NO_ERROR(status)) {
2818 val =
2819 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002820 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x40) | (RFAGCEN[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002821 ? 0x40 :
2822 0x00);
2823 if (pInfo->reg[MT2063_REG_PD1_TGT] != val) {
2824 status |= MT2063_SetReg(pInfo, MT2063_REG_PD1_TGT, val);
2825 }
2826 }
2827
2828 /* LNARin */
2829 if (MT2063_NO_ERROR(status)) {
2830 status |= MT2063_SetParam(pInfo, MT2063_LNA_RIN, LNARIN[Mode]);
2831 }
2832
2833 /* FIFFQEN and FIFFQ */
2834 if (MT2063_NO_ERROR(status)) {
2835 val =
2836 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002837 reg[MT2063_REG_FIFF_CTRL2] & (u8) ~ 0xF0) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002838 (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
2839 if (pInfo->reg[MT2063_REG_FIFF_CTRL2] != val) {
2840 status |=
2841 MT2063_SetReg(pInfo, MT2063_REG_FIFF_CTRL2, val);
2842 /* trigger FIFF calibration, needed after changing FIFFQ */
2843 val =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002844 (pInfo->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002845 status |=
2846 MT2063_SetReg(pInfo, MT2063_REG_FIFF_CTRL, val);
2847 val =
2848 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002849 reg[MT2063_REG_FIFF_CTRL] & (u8) ~ 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002850 status |=
2851 MT2063_SetReg(pInfo, MT2063_REG_FIFF_CTRL, val);
2852 }
2853 }
2854
2855 /* DNC1GC & DNC2GC */
2856 status |= MT2063_GetParam(pInfo, MT2063_DNC_OUTPUT_ENABLE, &longval);
2857 status |= MT2063_SetParam(pInfo, MT2063_DNC_OUTPUT_ENABLE, longval);
2858
2859 /* acLNAmax */
2860 if (MT2063_NO_ERROR(status)) {
2861 status |=
2862 MT2063_SetParam(pInfo, MT2063_ACLNA_MAX, ACLNAMAX[Mode]);
2863 }
2864
2865 /* LNATGT */
2866 if (MT2063_NO_ERROR(status)) {
2867 status |= MT2063_SetParam(pInfo, MT2063_LNA_TGT, LNATGT[Mode]);
2868 }
2869
2870 /* ACRF */
2871 if (MT2063_NO_ERROR(status)) {
2872 status |=
2873 MT2063_SetParam(pInfo, MT2063_ACRF_MAX, ACRFMAX[Mode]);
2874 }
2875
2876 /* PD1TGT */
2877 if (MT2063_NO_ERROR(status)) {
2878 status |= MT2063_SetParam(pInfo, MT2063_PD1_TGT, PD1TGT[Mode]);
2879 }
2880
2881 /* FIFATN */
2882 if (MT2063_NO_ERROR(status)) {
2883 status |=
2884 MT2063_SetParam(pInfo, MT2063_ACFIF_MAX, ACFIFMAX[Mode]);
2885 }
2886
2887 /* PD2TGT */
2888 if (MT2063_NO_ERROR(status)) {
2889 status |= MT2063_SetParam(pInfo, MT2063_PD2_TGT, PD2TGT[Mode]);
2890 }
2891
2892 /* Ignore ATN Overload */
2893 if (MT2063_NO_ERROR(status)) {
2894 val =
2895 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002896 reg[MT2063_REG_LNA_TGT] & (u8) ~ 0x80) | (RFOVDIS[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002897 ? 0x80 :
2898 0x00);
2899 if (pInfo->reg[MT2063_REG_LNA_TGT] != val) {
2900 status |= MT2063_SetReg(pInfo, MT2063_REG_LNA_TGT, val);
2901 }
2902 }
2903
2904 /* Ignore FIF Overload */
2905 if (MT2063_NO_ERROR(status)) {
2906 val =
2907 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002908 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x80) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002909 (FIFOVDIS[Mode] ? 0x80 : 0x00);
2910 if (pInfo->reg[MT2063_REG_PD1_TGT] != val) {
2911 status |= MT2063_SetReg(pInfo, MT2063_REG_PD1_TGT, val);
2912 }
2913 }
2914
2915 if (MT2063_NO_ERROR(status))
2916 pInfo->rcvr_mode = Mode;
2917
2918 return (status);
2919}
2920
2921/******************************************************************************
2922**
2923** Name: MT2063_ReInit
2924**
2925** Description: Initialize the tuner's register values.
2926**
2927** Parameters: h - Tuner handle (returned by MT2063_Open)
2928**
2929** Returns: status:
2930** MT_OK - No errors
2931** MT_TUNER_ID_ERR - Tuner Part/Rev code mismatch
2932** MT_INV_HANDLE - Invalid tuner handle
2933** MT_COMM_ERR - Serial bus communications error
2934**
2935** Dependencies: MT_ReadSub - Read byte(s) of data from the two-wire bus
2936** MT_WriteSub - Write byte(s) of data to the two-wire bus
2937**
2938** Revision History:
2939**
2940** SCR Date Author Description
2941** -------------------------------------------------------------------------
2942** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2943** 148 09-04-2007 RSK Ver 1.02: Corrected logic of Reg 3B Reference
2944** 153 09-07-2007 RSK Ver 1.03: Lock Time improvements
2945** N/A 10-31-2007 PINZ Ver 1.08: Changed values suitable to rcvr-mode 0
2946** N/A 11-12-2007 PINZ Ver 1.09: Changed values suitable to rcvr-mode 0
2947** N/A 01-03-2007 PINZ Ver 1.10: Added AFCsd = 1 into defaults
2948** N/A 01-04-2007 PINZ Ver 1.10: Changed CAP1sel default
2949** 01-14-2008 PINZ Ver 1.11: Updated gain settings
2950** 03-18-2008 PINZ Ver 1.13: Added Support for B3
2951** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
2952** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
2953**
2954******************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002955static u32 MT2063_ReInit(void *h)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002956{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002957 u8 all_resets = 0xF0; /* reset/load bits */
2958 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002959 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -03002960 u8 *def = NULL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002961
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002962 u8 MT2063B0_defaults[] = { /* Reg, Value */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002963 0x19, 0x05,
2964 0x1B, 0x1D,
2965 0x1C, 0x1F,
2966 0x1D, 0x0F,
2967 0x1E, 0x3F,
2968 0x1F, 0x0F,
2969 0x20, 0x3F,
2970 0x22, 0x21,
2971 0x23, 0x3F,
2972 0x24, 0x20,
2973 0x25, 0x3F,
2974 0x27, 0xEE,
2975 0x2C, 0x27, /* bit at 0x20 is cleared below */
2976 0x30, 0x03,
2977 0x2C, 0x07, /* bit at 0x20 is cleared here */
2978 0x2D, 0x87,
2979 0x2E, 0xAA,
2980 0x28, 0xE1, /* Set the FIFCrst bit here */
2981 0x28, 0xE0, /* Clear the FIFCrst bit here */
2982 0x00
2983 };
2984
2985 /* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002986 u8 MT2063B1_defaults[] = { /* Reg, Value */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002987 0x05, 0xF0,
2988 0x11, 0x10, /* New Enable AFCsd */
2989 0x19, 0x05,
2990 0x1A, 0x6C,
2991 0x1B, 0x24,
2992 0x1C, 0x28,
2993 0x1D, 0x8F,
2994 0x1E, 0x14,
2995 0x1F, 0x8F,
2996 0x20, 0x57,
2997 0x22, 0x21, /* New - ver 1.03 */
2998 0x23, 0x3C, /* New - ver 1.10 */
2999 0x24, 0x20, /* New - ver 1.03 */
3000 0x2C, 0x24, /* bit at 0x20 is cleared below */
3001 0x2D, 0x87, /* FIFFQ=0 */
3002 0x2F, 0xF3,
3003 0x30, 0x0C, /* New - ver 1.11 */
3004 0x31, 0x1B, /* New - ver 1.11 */
3005 0x2C, 0x04, /* bit at 0x20 is cleared here */
3006 0x28, 0xE1, /* Set the FIFCrst bit here */
3007 0x28, 0xE0, /* Clear the FIFCrst bit here */
3008 0x00
3009 };
3010
3011 /* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003012 u8 MT2063B3_defaults[] = { /* Reg, Value */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003013 0x05, 0xF0,
3014 0x19, 0x3D,
3015 0x2C, 0x24, /* bit at 0x20 is cleared below */
3016 0x2C, 0x04, /* bit at 0x20 is cleared here */
3017 0x28, 0xE1, /* Set the FIFCrst bit here */
3018 0x28, 0xE0, /* Clear the FIFCrst bit here */
3019 0x00
3020 };
3021
3022 /* Verify that the handle passed points to a valid tuner */
3023 if (MT2063_IsValidHandle(pInfo) == 0)
3024 status |= MT2063_INV_HANDLE;
3025
3026 /* Read the Part/Rev code from the tuner */
3027 if (MT2063_NO_ERROR(status)) {
3028 status |=
3029 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
3030 MT2063_REG_PART_REV, pInfo->reg, 1);
3031 }
3032
3033 if (MT2063_NO_ERROR(status) /* Check the part/rev code */
3034 &&((pInfo->reg[MT2063_REG_PART_REV] != MT2063_B0) /* MT2063 B0 */
3035 &&(pInfo->reg[MT2063_REG_PART_REV] != MT2063_B1) /* MT2063 B1 */
3036 &&(pInfo->reg[MT2063_REG_PART_REV] != MT2063_B3))) /* MT2063 B3 */
3037 status |= MT2063_TUNER_ID_ERR; /* Wrong tuner Part/Rev code */
3038
3039 /* Read the Part/Rev code (2nd byte) from the tuner */
3040 if (MT2063_NO_ERROR(status))
3041 status |=
3042 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
3043 MT2063_REG_RSVD_3B,
3044 &pInfo->reg[MT2063_REG_RSVD_3B], 1);
3045
3046 if (MT2063_NO_ERROR(status) /* Check the 2nd part/rev code */
3047 &&((pInfo->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) /* b7 != 0 ==> NOT MT2063 */
3048 status |= MT2063_TUNER_ID_ERR; /* Wrong tuner Part/Rev code */
3049
3050 /* Reset the tuner */
3051 if (MT2063_NO_ERROR(status))
3052 status |= MT2063_WriteSub(pInfo->hUserData,
3053 pInfo->address,
3054 MT2063_REG_LO2CQ_3, &all_resets, 1);
3055
3056 /* change all of the default values that vary from the HW reset values */
3057 /* def = (pInfo->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */
3058 switch (pInfo->reg[MT2063_REG_PART_REV]) {
3059 case MT2063_B3:
3060 def = MT2063B3_defaults;
3061 break;
3062
3063 case MT2063_B1:
3064 def = MT2063B1_defaults;
3065 break;
3066
3067 case MT2063_B0:
3068 def = MT2063B0_defaults;
3069 break;
3070
3071 default:
3072 status |= MT2063_TUNER_ID_ERR;
3073 break;
3074 }
3075
3076 while (MT2063_NO_ERROR(status) && *def) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003077 u8 reg = *def++;
3078 u8 val = *def++;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003079 status |=
3080 MT2063_WriteSub(pInfo->hUserData, pInfo->address, reg, &val,
3081 1);
3082 }
3083
3084 /* Wait for FIFF location to complete. */
3085 if (MT2063_NO_ERROR(status)) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003086 u32 FCRUN = 1;
3087 s32 maxReads = 10;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003088 while (MT2063_NO_ERROR(status) && (FCRUN != 0)
3089 && (maxReads-- > 0)) {
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03003090 msleep(2);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003091 status |= MT2063_ReadSub(pInfo->hUserData,
3092 pInfo->address,
3093 MT2063_REG_XO_STATUS,
3094 &pInfo->
3095 reg[MT2063_REG_XO_STATUS], 1);
3096 FCRUN = (pInfo->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6;
3097 }
3098
3099 if (FCRUN != 0)
3100 status |= MT2063_TUNER_INIT_ERR | MT2063_TUNER_TIMEOUT;
3101
3102 if (MT2063_NO_ERROR(status)) /* Re-read FIFFC value */
3103 status |=
3104 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
3105 MT2063_REG_FIFFC,
3106 &pInfo->reg[MT2063_REG_FIFFC], 1);
3107 }
3108
3109 /* Read back all the registers from the tuner */
3110 if (MT2063_NO_ERROR(status))
3111 status |= MT2063_ReadSub(pInfo->hUserData,
3112 pInfo->address,
3113 MT2063_REG_PART_REV,
3114 pInfo->reg, MT2063_REG_END_REGS);
3115
3116 if (MT2063_NO_ERROR(status)) {
3117 /* Initialize the tuner state. */
3118 pInfo->version = MT2063_VERSION;
3119 pInfo->tuner_id = pInfo->reg[MT2063_REG_PART_REV];
3120 pInfo->AS_Data.f_ref = MT2063_REF_FREQ;
3121 pInfo->AS_Data.f_if1_Center =
3122 (pInfo->AS_Data.f_ref / 8) *
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003123 ((u32) pInfo->reg[MT2063_REG_FIFFC] + 640);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003124 pInfo->AS_Data.f_if1_bw = MT2063_IF1_BW;
3125 pInfo->AS_Data.f_out = 43750000UL;
3126 pInfo->AS_Data.f_out_bw = 6750000UL;
3127 pInfo->AS_Data.f_zif_bw = MT2063_ZIF_BW;
3128 pInfo->AS_Data.f_LO1_Step = pInfo->AS_Data.f_ref / 64;
3129 pInfo->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE;
3130 pInfo->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1;
3131 pInfo->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2;
3132 pInfo->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP;
3133 pInfo->AS_Data.f_if1_Request = pInfo->AS_Data.f_if1_Center;
3134 pInfo->AS_Data.f_LO1 = 2181000000UL;
3135 pInfo->AS_Data.f_LO2 = 1486249786UL;
3136 pInfo->f_IF1_actual = pInfo->AS_Data.f_if1_Center;
3137 pInfo->AS_Data.f_in =
3138 pInfo->AS_Data.f_LO1 - pInfo->f_IF1_actual;
3139 pInfo->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID;
3140 pInfo->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID;
3141 pInfo->num_regs = MT2063_REG_END_REGS;
3142 pInfo->AS_Data.avoidDECT = MT2063_AVOID_BOTH;
3143 pInfo->ctfilt_sw = 0;
3144 }
3145
3146 if (MT2063_NO_ERROR(status)) {
3147 pInfo->CTFiltMax[0] = 69230000;
3148 pInfo->CTFiltMax[1] = 105770000;
3149 pInfo->CTFiltMax[2] = 140350000;
3150 pInfo->CTFiltMax[3] = 177110000;
3151 pInfo->CTFiltMax[4] = 212860000;
3152 pInfo->CTFiltMax[5] = 241130000;
3153 pInfo->CTFiltMax[6] = 274370000;
3154 pInfo->CTFiltMax[7] = 309820000;
3155 pInfo->CTFiltMax[8] = 342450000;
3156 pInfo->CTFiltMax[9] = 378870000;
3157 pInfo->CTFiltMax[10] = 416210000;
3158 pInfo->CTFiltMax[11] = 456500000;
3159 pInfo->CTFiltMax[12] = 495790000;
3160 pInfo->CTFiltMax[13] = 534530000;
3161 pInfo->CTFiltMax[14] = 572610000;
3162 pInfo->CTFiltMax[15] = 598970000;
3163 pInfo->CTFiltMax[16] = 635910000;
3164 pInfo->CTFiltMax[17] = 672130000;
3165 pInfo->CTFiltMax[18] = 714840000;
3166 pInfo->CTFiltMax[19] = 739660000;
3167 pInfo->CTFiltMax[20] = 770410000;
3168 pInfo->CTFiltMax[21] = 814660000;
3169 pInfo->CTFiltMax[22] = 846950000;
3170 pInfo->CTFiltMax[23] = 867820000;
3171 pInfo->CTFiltMax[24] = 915980000;
3172 pInfo->CTFiltMax[25] = 947450000;
3173 pInfo->CTFiltMax[26] = 983110000;
3174 pInfo->CTFiltMax[27] = 1021630000;
3175 pInfo->CTFiltMax[28] = 1061870000;
3176 pInfo->CTFiltMax[29] = 1098330000;
3177 pInfo->CTFiltMax[30] = 1138990000;
3178 }
3179
3180 /*
3181 ** Fetch the FCU osc value and use it and the fRef value to
3182 ** scale all of the Band Max values
3183 */
3184 if (MT2063_NO_ERROR(status)) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003185 u32 fcu_osc;
3186 u32 i;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003187
3188 pInfo->reg[MT2063_REG_CTUNE_CTRL] = 0x0A;
3189 status |=
3190 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3191 MT2063_REG_CTUNE_CTRL,
3192 &pInfo->reg[MT2063_REG_CTUNE_CTRL], 1);
3193 /* Read the ClearTune filter calibration value */
3194 status |=
3195 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
3196 MT2063_REG_FIFFC,
3197 &pInfo->reg[MT2063_REG_FIFFC], 1);
3198 fcu_osc = pInfo->reg[MT2063_REG_FIFFC];
3199
3200 pInfo->reg[MT2063_REG_CTUNE_CTRL] = 0x00;
3201 status |=
3202 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3203 MT2063_REG_CTUNE_CTRL,
3204 &pInfo->reg[MT2063_REG_CTUNE_CTRL], 1);
3205
3206 /* Adjust each of the values in the ClearTune filter cross-over table */
3207 for (i = 0; i < 31; i++) {
3208 pInfo->CTFiltMax[i] =
3209 (pInfo->CTFiltMax[i] / 768) * (fcu_osc + 640);
3210 }
3211 }
3212
3213 return (status);
3214}
3215
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003216/****************************************************************************
3217**
3218** Name: MT2063_SetParam
3219**
3220** Description: Sets a tuning algorithm parameter.
3221**
3222** This function provides access to the internals of the
3223** tuning algorithm. You can override many of the tuning
3224** algorithm defaults using this function.
3225**
3226** Parameters: h - Tuner handle (returned by MT2063_Open)
3227** param - Tuning algorithm parameter
3228** (see enum MT2063_Param)
3229** nValue - value to be set
3230**
3231** param Description
3232** ---------------------- --------------------------------
3233** MT2063_SRO_FREQ crystal frequency
3234** MT2063_STEPSIZE minimum tuning step size
3235** MT2063_LO1_FREQ LO1 frequency
3236** MT2063_LO1_STEPSIZE LO1 minimum step size
3237** MT2063_LO1_FRACN_AVOID LO1 FracN keep-out region
3238** MT2063_IF1_REQUEST Requested 1st IF
3239** MT2063_ZIF_BW zero-IF bandwidth
3240** MT2063_LO2_FREQ LO2 frequency
3241** MT2063_LO2_STEPSIZE LO2 minimum step size
3242** MT2063_LO2_FRACN_AVOID LO2 FracN keep-out region
3243** MT2063_OUTPUT_FREQ output center frequency
3244** MT2063_OUTPUT_BW output bandwidth
3245** MT2063_LO_SEPARATION min inter-tuner LO separation
3246** MT2063_MAX_HARM1 max # of intra-tuner harmonics
3247** MT2063_MAX_HARM2 max # of inter-tuner harmonics
3248** MT2063_RCVR_MODE Predefined modes
3249** MT2063_LNA_RIN Set LNA Rin (*)
3250** MT2063_LNA_TGT Set target power level at LNA (*)
3251** MT2063_PD1_TGT Set target power level at PD1 (*)
3252** MT2063_PD2_TGT Set target power level at PD2 (*)
3253** MT2063_ACLNA_MAX LNA attenuator limit (*)
3254** MT2063_ACRF_MAX RF attenuator limit (*)
3255** MT2063_ACFIF_MAX FIF attenuator limit (*)
3256** MT2063_DNC_OUTPUT_ENABLE DNC output selection
3257** MT2063_VGAGC VGA gain code
3258** MT2063_VGAOI VGA output current
3259** MT2063_TAGC TAGC setting
3260** MT2063_AMPGC AMP gain code
3261** MT2063_AVOID_DECT Avoid DECT Frequencies
3262** MT2063_CTFILT_SW Cleartune filter selection
3263**
3264** (*) This parameter is set by MT2063_RCVR_MODE, do not call
3265** additionally.
3266**
3267** Usage: status |= MT2063_SetParam(hMT2063,
3268** MT2063_STEPSIZE,
3269** 50000);
3270**
3271** Returns: status:
3272** MT_OK - No errors
3273** MT_INV_HANDLE - Invalid tuner handle
3274** MT_ARG_NULL - Null pointer argument passed
3275** MT_ARG_RANGE - Invalid parameter requested
3276** or set value out of range
3277** or non-writable parameter
3278**
3279** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3280**
3281** See Also: MT2063_GetParam, MT2063_Open
3282**
3283** Revision History:
3284**
3285** SCR Date Author Description
3286** -------------------------------------------------------------------------
3287** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3288** 154 09-13-2007 RSK Ver 1.05: Get/SetParam changes for LOx_FREQ
3289** 10-31-2007 PINZ Ver 1.08: Get/SetParam add VGAGC, VGAOI, AMPGC, TAGC
3290** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
3291** Split SetParam up to ACLNA / ACLNA_MAX
3292** removed ACLNA_INRC/DECR (+RF & FIF)
3293** removed GCUAUTO / BYPATNDN/UP
3294** 175 I 06-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
3295** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
3296** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
3297**
3298****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03003299static u32 MT2063_SetParam(void *h, enum MT2063_Param param, u32 nValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003300{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003301 u32 status = MT2063_OK; /* Status to be returned */
3302 u8 val = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003303 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
3304
3305 /* Verify that the handle passed points to a valid tuner */
3306 if (MT2063_IsValidHandle(pInfo) == 0)
3307 status |= MT2063_INV_HANDLE;
3308
3309 if (MT2063_NO_ERROR(status)) {
3310 switch (param) {
3311 /* crystal frequency */
3312 case MT2063_SRO_FREQ:
3313 pInfo->AS_Data.f_ref = nValue;
3314 pInfo->AS_Data.f_LO1_FracN_Avoid = 0;
3315 pInfo->AS_Data.f_LO2_FracN_Avoid = nValue / 80 - 1;
3316 pInfo->AS_Data.f_LO1_Step = nValue / 64;
3317 pInfo->AS_Data.f_if1_Center =
3318 (pInfo->AS_Data.f_ref / 8) *
3319 (pInfo->reg[MT2063_REG_FIFFC] + 640);
3320 break;
3321
3322 /* minimum tuning step size */
3323 case MT2063_STEPSIZE:
3324 pInfo->AS_Data.f_LO2_Step = nValue;
3325 break;
3326
3327 /* LO1 frequency */
3328 case MT2063_LO1_FREQ:
3329 {
3330 /* Note: LO1 and LO2 are BOTH written at toggle of LDLOos */
3331 /* Capture the Divider and Numerator portions of other LO */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003332 u8 tempLO2CQ[3];
3333 u8 tempLO2C[3];
3334 u8 tmpOneShot;
3335 u32 Div, FracN;
3336 u8 restore = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003337
3338 /* Buffer the queue for restoration later and get actual LO2 values. */
3339 status |=
3340 MT2063_ReadSub(pInfo->hUserData,
3341 pInfo->address,
3342 MT2063_REG_LO2CQ_1,
3343 &(tempLO2CQ[0]), 3);
3344 status |=
3345 MT2063_ReadSub(pInfo->hUserData,
3346 pInfo->address,
3347 MT2063_REG_LO2C_1,
3348 &(tempLO2C[0]), 3);
3349
3350 /* clear the one-shot bits */
3351 tempLO2CQ[2] = tempLO2CQ[2] & 0x0F;
3352 tempLO2C[2] = tempLO2C[2] & 0x0F;
3353
3354 /* only write the queue values if they are different from the actual. */
3355 if ((tempLO2CQ[0] != tempLO2C[0]) ||
3356 (tempLO2CQ[1] != tempLO2C[1]) ||
3357 (tempLO2CQ[2] != tempLO2C[2])) {
3358 /* put actual LO2 value into queue (with 0 in one-shot bits) */
3359 status |=
3360 MT2063_WriteSub(pInfo->hUserData,
3361 pInfo->address,
3362 MT2063_REG_LO2CQ_1,
3363 &(tempLO2C[0]), 3);
3364
3365 if (status == MT2063_OK) {
3366 /* cache the bytes just written. */
3367 pInfo->reg[MT2063_REG_LO2CQ_1] =
3368 tempLO2C[0];
3369 pInfo->reg[MT2063_REG_LO2CQ_2] =
3370 tempLO2C[1];
3371 pInfo->reg[MT2063_REG_LO2CQ_3] =
3372 tempLO2C[2];
3373 }
3374 restore = 1;
3375 }
3376
3377 /* Calculate the Divider and Numberator components of LO1 */
3378 status =
3379 MT2063_CalcLO1Mult(&Div, &FracN, nValue,
3380 pInfo->AS_Data.f_ref /
3381 64,
3382 pInfo->AS_Data.f_ref);
3383 pInfo->reg[MT2063_REG_LO1CQ_1] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003384 (u8) (Div & 0x00FF);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003385 pInfo->reg[MT2063_REG_LO1CQ_2] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003386 (u8) (FracN);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003387 status |=
3388 MT2063_WriteSub(pInfo->hUserData,
3389 pInfo->address,
3390 MT2063_REG_LO1CQ_1,
3391 &pInfo->
3392 reg[MT2063_REG_LO1CQ_1], 2);
3393
3394 /* set the one-shot bit to load the pair of LO values */
3395 tmpOneShot = tempLO2CQ[2] | 0xE0;
3396 status |=
3397 MT2063_WriteSub(pInfo->hUserData,
3398 pInfo->address,
3399 MT2063_REG_LO2CQ_3,
3400 &tmpOneShot, 1);
3401
3402 /* only restore the queue values if they were different from the actual. */
3403 if (restore) {
3404 /* put actual LO2 value into queue (0 in one-shot bits) */
3405 status |=
3406 MT2063_WriteSub(pInfo->hUserData,
3407 pInfo->address,
3408 MT2063_REG_LO2CQ_1,
3409 &(tempLO2CQ[0]), 3);
3410
3411 /* cache the bytes just written. */
3412 pInfo->reg[MT2063_REG_LO2CQ_1] =
3413 tempLO2CQ[0];
3414 pInfo->reg[MT2063_REG_LO2CQ_2] =
3415 tempLO2CQ[1];
3416 pInfo->reg[MT2063_REG_LO2CQ_3] =
3417 tempLO2CQ[2];
3418 }
3419
3420 MT2063_GetParam(pInfo->hUserData,
3421 MT2063_LO1_FREQ,
3422 &pInfo->AS_Data.f_LO1);
3423 }
3424 break;
3425
3426 /* LO1 minimum step size */
3427 case MT2063_LO1_STEPSIZE:
3428 pInfo->AS_Data.f_LO1_Step = nValue;
3429 break;
3430
3431 /* LO1 FracN keep-out region */
3432 case MT2063_LO1_FRACN_AVOID_PARAM:
3433 pInfo->AS_Data.f_LO1_FracN_Avoid = nValue;
3434 break;
3435
3436 /* Requested 1st IF */
3437 case MT2063_IF1_REQUEST:
3438 pInfo->AS_Data.f_if1_Request = nValue;
3439 break;
3440
3441 /* zero-IF bandwidth */
3442 case MT2063_ZIF_BW:
3443 pInfo->AS_Data.f_zif_bw = nValue;
3444 break;
3445
3446 /* LO2 frequency */
3447 case MT2063_LO2_FREQ:
3448 {
3449 /* Note: LO1 and LO2 are BOTH written at toggle of LDLOos */
3450 /* Capture the Divider and Numerator portions of other LO */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003451 u8 tempLO1CQ[2];
3452 u8 tempLO1C[2];
3453 u32 Div2;
3454 u32 FracN2;
3455 u8 tmpOneShot;
3456 u8 restore = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003457
3458 /* Buffer the queue for restoration later and get actual LO2 values. */
3459 status |=
3460 MT2063_ReadSub(pInfo->hUserData,
3461 pInfo->address,
3462 MT2063_REG_LO1CQ_1,
3463 &(tempLO1CQ[0]), 2);
3464 status |=
3465 MT2063_ReadSub(pInfo->hUserData,
3466 pInfo->address,
3467 MT2063_REG_LO1C_1,
3468 &(tempLO1C[0]), 2);
3469
3470 /* only write the queue values if they are different from the actual. */
3471 if ((tempLO1CQ[0] != tempLO1C[0])
3472 || (tempLO1CQ[1] != tempLO1C[1])) {
3473 /* put actual LO1 value into queue */
3474 status |=
3475 MT2063_WriteSub(pInfo->hUserData,
3476 pInfo->address,
3477 MT2063_REG_LO1CQ_1,
3478 &(tempLO1C[0]), 2);
3479
3480 /* cache the bytes just written. */
3481 pInfo->reg[MT2063_REG_LO1CQ_1] =
3482 tempLO1C[0];
3483 pInfo->reg[MT2063_REG_LO1CQ_2] =
3484 tempLO1C[1];
3485 restore = 1;
3486 }
3487
3488 /* Calculate the Divider and Numberator components of LO2 */
3489 status =
3490 MT2063_CalcLO2Mult(&Div2, &FracN2, nValue,
3491 pInfo->AS_Data.f_ref /
3492 8191,
3493 pInfo->AS_Data.f_ref);
3494 pInfo->reg[MT2063_REG_LO2CQ_1] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003495 (u8) ((Div2 << 1) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003496 ((FracN2 >> 12) & 0x01)) & 0xFF;
3497 pInfo->reg[MT2063_REG_LO2CQ_2] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003498 (u8) ((FracN2 >> 4) & 0xFF);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003499 pInfo->reg[MT2063_REG_LO2CQ_3] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003500 (u8) ((FracN2 & 0x0F));
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003501 status |=
3502 MT2063_WriteSub(pInfo->hUserData,
3503 pInfo->address,
3504 MT2063_REG_LO1CQ_1,
3505 &pInfo->
3506 reg[MT2063_REG_LO1CQ_1], 3);
3507
3508 /* set the one-shot bit to load the LO values */
3509 tmpOneShot =
3510 pInfo->reg[MT2063_REG_LO2CQ_3] | 0xE0;
3511 status |=
3512 MT2063_WriteSub(pInfo->hUserData,
3513 pInfo->address,
3514 MT2063_REG_LO2CQ_3,
3515 &tmpOneShot, 1);
3516
3517 /* only restore LO1 queue value if they were different from the actual. */
3518 if (restore) {
3519 /* put previous LO1 queue value back into queue */
3520 status |=
3521 MT2063_WriteSub(pInfo->hUserData,
3522 pInfo->address,
3523 MT2063_REG_LO1CQ_1,
3524 &(tempLO1CQ[0]), 2);
3525
3526 /* cache the bytes just written. */
3527 pInfo->reg[MT2063_REG_LO1CQ_1] =
3528 tempLO1CQ[0];
3529 pInfo->reg[MT2063_REG_LO1CQ_2] =
3530 tempLO1CQ[1];
3531 }
3532
3533 MT2063_GetParam(pInfo->hUserData,
3534 MT2063_LO2_FREQ,
3535 &pInfo->AS_Data.f_LO2);
3536 }
3537 break;
3538
3539 /* LO2 minimum step size */
3540 case MT2063_LO2_STEPSIZE:
3541 pInfo->AS_Data.f_LO2_Step = nValue;
3542 break;
3543
3544 /* LO2 FracN keep-out region */
3545 case MT2063_LO2_FRACN_AVOID:
3546 pInfo->AS_Data.f_LO2_FracN_Avoid = nValue;
3547 break;
3548
3549 /* output center frequency */
3550 case MT2063_OUTPUT_FREQ:
3551 pInfo->AS_Data.f_out = nValue;
3552 break;
3553
3554 /* output bandwidth */
3555 case MT2063_OUTPUT_BW:
3556 pInfo->AS_Data.f_out_bw = nValue + 750000;
3557 break;
3558
3559 /* min inter-tuner LO separation */
3560 case MT2063_LO_SEPARATION:
3561 pInfo->AS_Data.f_min_LO_Separation = nValue;
3562 break;
3563
3564 /* max # of intra-tuner harmonics */
3565 case MT2063_MAX_HARM1:
3566 pInfo->AS_Data.maxH1 = nValue;
3567 break;
3568
3569 /* max # of inter-tuner harmonics */
3570 case MT2063_MAX_HARM2:
3571 pInfo->AS_Data.maxH2 = nValue;
3572 break;
3573
3574 case MT2063_RCVR_MODE:
3575 status |=
3576 MT2063_SetReceiverMode(pInfo,
3577 (enum MT2063_RCVR_MODES)
3578 nValue);
3579 break;
3580
3581 /* Set LNA Rin -- nValue is desired value */
3582 case MT2063_LNA_RIN:
3583 val =
3584 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003585 reg[MT2063_REG_CTRL_2C] & (u8) ~ 0x03) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003586 (nValue & 0x03);
3587 if (pInfo->reg[MT2063_REG_CTRL_2C] != val) {
3588 status |=
3589 MT2063_SetReg(pInfo, MT2063_REG_CTRL_2C,
3590 val);
3591 }
3592 break;
3593
3594 /* Set target power level at LNA -- nValue is desired value */
3595 case MT2063_LNA_TGT:
3596 val =
3597 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003598 reg[MT2063_REG_LNA_TGT] & (u8) ~ 0x3F) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003599 (nValue & 0x3F);
3600 if (pInfo->reg[MT2063_REG_LNA_TGT] != val) {
3601 status |=
3602 MT2063_SetReg(pInfo, MT2063_REG_LNA_TGT,
3603 val);
3604 }
3605 break;
3606
3607 /* Set target power level at PD1 -- nValue is desired value */
3608 case MT2063_PD1_TGT:
3609 val =
3610 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003611 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x3F) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003612 (nValue & 0x3F);
3613 if (pInfo->reg[MT2063_REG_PD1_TGT] != val) {
3614 status |=
3615 MT2063_SetReg(pInfo, MT2063_REG_PD1_TGT,
3616 val);
3617 }
3618 break;
3619
3620 /* Set target power level at PD2 -- nValue is desired value */
3621 case MT2063_PD2_TGT:
3622 val =
3623 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003624 reg[MT2063_REG_PD2_TGT] & (u8) ~ 0x3F) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003625 (nValue & 0x3F);
3626 if (pInfo->reg[MT2063_REG_PD2_TGT] != val) {
3627 status |=
3628 MT2063_SetReg(pInfo, MT2063_REG_PD2_TGT,
3629 val);
3630 }
3631 break;
3632
3633 /* Set LNA atten limit -- nValue is desired value */
3634 case MT2063_ACLNA_MAX:
3635 val =
3636 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003637 reg[MT2063_REG_LNA_OV] & (u8) ~ 0x1F) | (nValue
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003638 &
3639 0x1F);
3640 if (pInfo->reg[MT2063_REG_LNA_OV] != val) {
3641 status |=
3642 MT2063_SetReg(pInfo, MT2063_REG_LNA_OV,
3643 val);
3644 }
3645 break;
3646
3647 /* Set RF atten limit -- nValue is desired value */
3648 case MT2063_ACRF_MAX:
3649 val =
3650 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003651 reg[MT2063_REG_RF_OV] & (u8) ~ 0x1F) | (nValue
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003652 &
3653 0x1F);
3654 if (pInfo->reg[MT2063_REG_RF_OV] != val) {
3655 status |=
3656 MT2063_SetReg(pInfo, MT2063_REG_RF_OV, val);
3657 }
3658 break;
3659
3660 /* Set FIF atten limit -- nValue is desired value, max. 5 if no B3 */
3661 case MT2063_ACFIF_MAX:
3662 if (pInfo->reg[MT2063_REG_PART_REV] != MT2063_B3
3663 && nValue > 5)
3664 nValue = 5;
3665 val =
3666 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003667 reg[MT2063_REG_FIF_OV] & (u8) ~ 0x1F) | (nValue
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003668 &
3669 0x1F);
3670 if (pInfo->reg[MT2063_REG_FIF_OV] != val) {
3671 status |=
3672 MT2063_SetReg(pInfo, MT2063_REG_FIF_OV,
3673 val);
3674 }
3675 break;
3676
3677 case MT2063_DNC_OUTPUT_ENABLE:
3678 /* selects, which DNC output is used */
3679 switch ((enum MT2063_DNC_Output_Enable)nValue) {
3680 case MT2063_DNC_NONE:
3681 {
3682 val = (pInfo->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
3683 if (pInfo->reg[MT2063_REG_DNC_GAIN] !=
3684 val)
3685 status |=
3686 MT2063_SetReg(h,
3687 MT2063_REG_DNC_GAIN,
3688 val);
3689
3690 val = (pInfo->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
3691 if (pInfo->reg[MT2063_REG_VGA_GAIN] !=
3692 val)
3693 status |=
3694 MT2063_SetReg(h,
3695 MT2063_REG_VGA_GAIN,
3696 val);
3697
3698 val = (pInfo->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
3699 if (pInfo->reg[MT2063_REG_RSVD_20] !=
3700 val)
3701 status |=
3702 MT2063_SetReg(h,
3703 MT2063_REG_RSVD_20,
3704 val);
3705
3706 break;
3707 }
3708 case MT2063_DNC_1:
3709 {
3710 val = (pInfo->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[pInfo->rcvr_mode] & 0x03); /* Set DNC1GC=x */
3711 if (pInfo->reg[MT2063_REG_DNC_GAIN] !=
3712 val)
3713 status |=
3714 MT2063_SetReg(h,
3715 MT2063_REG_DNC_GAIN,
3716 val);
3717
3718 val = (pInfo->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
3719 if (pInfo->reg[MT2063_REG_VGA_GAIN] !=
3720 val)
3721 status |=
3722 MT2063_SetReg(h,
3723 MT2063_REG_VGA_GAIN,
3724 val);
3725
3726 val = (pInfo->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
3727 if (pInfo->reg[MT2063_REG_RSVD_20] !=
3728 val)
3729 status |=
3730 MT2063_SetReg(h,
3731 MT2063_REG_RSVD_20,
3732 val);
3733
3734 break;
3735 }
3736 case MT2063_DNC_2:
3737 {
3738 val = (pInfo->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
3739 if (pInfo->reg[MT2063_REG_DNC_GAIN] !=
3740 val)
3741 status |=
3742 MT2063_SetReg(h,
3743 MT2063_REG_DNC_GAIN,
3744 val);
3745
3746 val = (pInfo->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[pInfo->rcvr_mode] & 0x03); /* Set DNC2GC=x */
3747 if (pInfo->reg[MT2063_REG_VGA_GAIN] !=
3748 val)
3749 status |=
3750 MT2063_SetReg(h,
3751 MT2063_REG_VGA_GAIN,
3752 val);
3753
3754 val = (pInfo->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
3755 if (pInfo->reg[MT2063_REG_RSVD_20] !=
3756 val)
3757 status |=
3758 MT2063_SetReg(h,
3759 MT2063_REG_RSVD_20,
3760 val);
3761
3762 break;
3763 }
3764 case MT2063_DNC_BOTH:
3765 {
3766 val = (pInfo->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[pInfo->rcvr_mode] & 0x03); /* Set DNC1GC=x */
3767 if (pInfo->reg[MT2063_REG_DNC_GAIN] !=
3768 val)
3769 status |=
3770 MT2063_SetReg(h,
3771 MT2063_REG_DNC_GAIN,
3772 val);
3773
3774 val = (pInfo->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[pInfo->rcvr_mode] & 0x03); /* Set DNC2GC=x */
3775 if (pInfo->reg[MT2063_REG_VGA_GAIN] !=
3776 val)
3777 status |=
3778 MT2063_SetReg(h,
3779 MT2063_REG_VGA_GAIN,
3780 val);
3781
3782 val = (pInfo->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
3783 if (pInfo->reg[MT2063_REG_RSVD_20] !=
3784 val)
3785 status |=
3786 MT2063_SetReg(h,
3787 MT2063_REG_RSVD_20,
3788 val);
3789
3790 break;
3791 }
3792 default:
3793 break;
3794 }
3795 break;
3796
3797 case MT2063_VGAGC:
3798 /* Set VGA gain code */
3799 val =
3800 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003801 reg[MT2063_REG_VGA_GAIN] & (u8) ~ 0x0C) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003802 ((nValue & 0x03) << 2);
3803 if (pInfo->reg[MT2063_REG_VGA_GAIN] != val) {
3804 status |=
3805 MT2063_SetReg(pInfo, MT2063_REG_VGA_GAIN,
3806 val);
3807 }
3808 break;
3809
3810 case MT2063_VGAOI:
3811 /* Set VGA bias current */
3812 val =
3813 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003814 reg[MT2063_REG_RSVD_31] & (u8) ~ 0x07) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003815 (nValue & 0x07);
3816 if (pInfo->reg[MT2063_REG_RSVD_31] != val) {
3817 status |=
3818 MT2063_SetReg(pInfo, MT2063_REG_RSVD_31,
3819 val);
3820 }
3821 break;
3822
3823 case MT2063_TAGC:
3824 /* Set TAGC */
3825 val =
3826 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003827 reg[MT2063_REG_RSVD_1E] & (u8) ~ 0x03) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003828 (nValue & 0x03);
3829 if (pInfo->reg[MT2063_REG_RSVD_1E] != val) {
3830 status |=
3831 MT2063_SetReg(pInfo, MT2063_REG_RSVD_1E,
3832 val);
3833 }
3834 break;
3835
3836 case MT2063_AMPGC:
3837 /* Set Amp gain code */
3838 val =
3839 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003840 reg[MT2063_REG_TEMP_SEL] & (u8) ~ 0x03) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003841 (nValue & 0x03);
3842 if (pInfo->reg[MT2063_REG_TEMP_SEL] != val) {
3843 status |=
3844 MT2063_SetReg(pInfo, MT2063_REG_TEMP_SEL,
3845 val);
3846 }
3847 break;
3848
3849 /* Avoid DECT Frequencies */
3850 case MT2063_AVOID_DECT:
3851 {
3852 enum MT2063_DECT_Avoid_Type newAvoidSetting =
3853 (enum MT2063_DECT_Avoid_Type)nValue;
3854 if ((newAvoidSetting >=
3855 MT2063_NO_DECT_AVOIDANCE)
3856 && (newAvoidSetting <= MT2063_AVOID_BOTH)) {
3857 pInfo->AS_Data.avoidDECT =
3858 newAvoidSetting;
3859 }
3860 }
3861 break;
3862
3863 /* Cleartune filter selection: 0 - by IC (default), 1 - by software */
3864 case MT2063_CTFILT_SW:
3865 pInfo->ctfilt_sw = (nValue & 0x01);
3866 break;
3867
3868 /* These parameters are read-only */
3869 case MT2063_IC_ADDR:
3870 case MT2063_MAX_OPEN:
3871 case MT2063_NUM_OPEN:
3872 case MT2063_INPUT_FREQ:
3873 case MT2063_IF1_ACTUAL:
3874 case MT2063_IF1_CENTER:
3875 case MT2063_IF1_BW:
3876 case MT2063_AS_ALG:
3877 case MT2063_EXCL_ZONES:
3878 case MT2063_SPUR_AVOIDED:
3879 case MT2063_NUM_SPURS:
3880 case MT2063_SPUR_PRESENT:
3881 case MT2063_ACLNA:
3882 case MT2063_ACRF:
3883 case MT2063_ACFIF:
3884 case MT2063_EOP:
3885 default:
3886 status |= MT2063_ARG_RANGE;
3887 }
3888 }
3889 return (status);
3890}
3891
3892/****************************************************************************
3893**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003894** Name: MT2063_ClearPowerMaskBits
3895**
3896** Description: Clears the power-down mask bits for various sections of
3897** the MT2063
3898**
3899** Parameters: h - Tuner handle (returned by MT2063_Open)
3900** Bits - Mask bits to be cleared.
3901**
3902** See definition of MT2063_Mask_Bits type for description
3903** of each of the power bits.
3904**
3905** Returns: status:
3906** MT_OK - No errors
3907** MT_INV_HANDLE - Invalid tuner handle
3908** MT_COMM_ERR - Serial bus communications error
3909**
3910** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3911**
3912** Revision History:
3913**
3914** SCR Date Author Description
3915** -------------------------------------------------------------------------
3916** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3917**
3918****************************************************************************/
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -03003919static u32 MT2063_ClearPowerMaskBits(struct MT2063_Info_t *pInfo, enum MT2063_Mask_Bits Bits)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003920{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003921 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003922
3923 /* Verify that the handle passed points to a valid tuner */
3924 if (MT2063_IsValidHandle(pInfo) == 0)
3925 status = MT2063_INV_HANDLE;
3926 else {
3927 Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */
3928 if ((Bits & 0xFF00) != 0) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003929 pInfo->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003930 status |=
3931 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3932 MT2063_REG_PWR_2,
3933 &pInfo->reg[MT2063_REG_PWR_2], 1);
3934 }
3935 if ((Bits & 0xFF) != 0) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003936 pInfo->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003937 status |=
3938 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3939 MT2063_REG_PWR_1,
3940 &pInfo->reg[MT2063_REG_PWR_1], 1);
3941 }
3942 }
3943
3944 return (status);
3945}
3946
3947/****************************************************************************
3948**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003949** Name: MT2063_SoftwareShutdown
3950**
3951** Description: Enables or disables software shutdown function. When
3952** Shutdown==1, any section whose power mask is set will be
3953** shutdown.
3954**
3955** Parameters: h - Tuner handle (returned by MT2063_Open)
3956** Shutdown - 1 = shutdown the masked sections, otherwise
3957** power all sections on
3958**
3959** Returns: status:
3960** MT_OK - No errors
3961** MT_INV_HANDLE - Invalid tuner handle
3962** MT_COMM_ERR - Serial bus communications error
3963**
3964** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3965**
3966** Revision History:
3967**
3968** SCR Date Author Description
3969** -------------------------------------------------------------------------
3970** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3971** 01-03-2008 PINZ Ver 1.xx: Added a trigger of BYPATNUP for
3972** correct wakeup of the LNA
3973**
3974****************************************************************************/
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -03003975static u32 MT2063_SoftwareShutdown(struct MT2063_Info_t *pInfo, u8 Shutdown)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003976{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003977 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003978
3979 /* Verify that the handle passed points to a valid tuner */
3980 if (MT2063_IsValidHandle(pInfo) == 0) {
3981 status = MT2063_INV_HANDLE;
3982 } else {
3983 if (Shutdown == 1)
3984 pInfo->reg[MT2063_REG_PWR_1] |= 0x04; /* Turn the bit on */
3985 else
3986 pInfo->reg[MT2063_REG_PWR_1] &= ~0x04; /* Turn off the bit */
3987
3988 status |=
3989 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3990 MT2063_REG_PWR_1,
3991 &pInfo->reg[MT2063_REG_PWR_1], 1);
3992
3993 if (Shutdown != 1) {
3994 pInfo->reg[MT2063_REG_BYP_CTRL] =
3995 (pInfo->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40;
3996 status |=
3997 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3998 MT2063_REG_BYP_CTRL,
3999 &pInfo->reg[MT2063_REG_BYP_CTRL],
4000 1);
4001 pInfo->reg[MT2063_REG_BYP_CTRL] =
4002 (pInfo->reg[MT2063_REG_BYP_CTRL] & 0x9F);
4003 status |=
4004 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
4005 MT2063_REG_BYP_CTRL,
4006 &pInfo->reg[MT2063_REG_BYP_CTRL],
4007 1);
4008 }
4009 }
4010
4011 return (status);
4012}
4013
4014/****************************************************************************
4015**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004016** Name: MT2063_SetReg
4017**
4018** Description: Sets an MT2063 register.
4019**
4020** Parameters: h - Tuner handle (returned by MT2063_Open)
4021** reg - MT2063 register/subaddress location
4022** val - MT2063 register/subaddress value
4023**
4024** Returns: status:
4025** MT_OK - No errors
4026** MT_COMM_ERR - Serial bus communications error
4027** MT_INV_HANDLE - Invalid tuner handle
4028** MT_ARG_RANGE - Argument out of range
4029**
4030** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
4031**
4032** Use this function if you need to override a default
4033** register value
4034**
4035** Revision History:
4036**
4037** SCR Date Author Description
4038** -------------------------------------------------------------------------
4039** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
4040**
4041****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03004042static u32 MT2063_SetReg(void *h, u8 reg, u8 val)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004043{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004044 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004045 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
4046
4047 /* Verify that the handle passed points to a valid tuner */
4048 if (MT2063_IsValidHandle(pInfo) == 0)
4049 status |= MT2063_INV_HANDLE;
4050
4051 if (reg >= MT2063_REG_END_REGS)
4052 status |= MT2063_ARG_RANGE;
4053
4054 if (MT2063_NO_ERROR(status)) {
4055 status |=
4056 MT2063_WriteSub(pInfo->hUserData, pInfo->address, reg, &val,
4057 1);
4058 if (MT2063_NO_ERROR(status))
4059 pInfo->reg[reg] = val;
4060 }
4061
4062 return (status);
4063}
4064
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004065static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004066{
4067 return f_ref * (f_LO / f_ref)
4068 + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step);
4069}
4070
4071/****************************************************************************
4072**
4073** Name: fLO_FractionalTerm
4074**
4075** Description: Calculates the portion contributed by FracN / denom.
4076**
4077** This function preserves maximum precision without
4078** risk of overflow. It accurately calculates
4079** f_ref * num / denom to within 1 HZ with fixed math.
4080**
4081** Parameters: num - Fractional portion of the multiplier
4082** denom - denominator portion of the ratio
4083** This routine successfully handles denom values
4084** up to and including 2^18.
4085** f_Ref - SRO frequency. This calculation handles
4086** f_ref as two separate 14-bit fields.
4087** Therefore, a maximum value of 2^28-1
4088** may safely be used for f_ref. This is
4089** the genesis of the magic number "14" and the
4090** magic mask value of 0x03FFF.
4091**
4092** Returns: f_ref * num / denom
4093**
4094** Revision History:
4095**
4096** SCR Date Author Description
4097** -------------------------------------------------------------------------
4098** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
4099**
4100****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004101static u32 MT2063_fLO_FractionalTerm(u32 f_ref,
4102 u32 num, u32 denom)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004103{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004104 u32 t1 = (f_ref >> 14) * num;
4105 u32 term1 = t1 / denom;
4106 u32 loss = t1 % denom;
4107 u32 term2 =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004108 (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom;
4109 return ((term1 << 14) + term2);
4110}
4111
4112/****************************************************************************
4113**
4114** Name: CalcLO1Mult
4115**
4116** Description: Calculates Integer divider value and the numerator
4117** value for a FracN PLL.
4118**
4119** This function assumes that the f_LO and f_Ref are
4120** evenly divisible by f_LO_Step.
4121**
4122** Parameters: Div - OUTPUT: Whole number portion of the multiplier
4123** FracN - OUTPUT: Fractional portion of the multiplier
4124** f_LO - desired LO frequency.
4125** f_LO_Step - Minimum step size for the LO (in Hz).
4126** f_Ref - SRO frequency.
4127** f_Avoid - Range of PLL frequencies to avoid near
4128** integer multiples of f_Ref (in Hz).
4129**
4130** Returns: Recalculated LO frequency.
4131**
4132** Revision History:
4133**
4134** SCR Date Author Description
4135** -------------------------------------------------------------------------
4136** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
4137**
4138****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004139static u32 MT2063_CalcLO1Mult(u32 * Div,
4140 u32 * FracN,
4141 u32 f_LO,
4142 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004143{
4144 /* Calculate the whole number portion of the divider */
4145 *Div = f_LO / f_Ref;
4146
4147 /* Calculate the numerator value (round to nearest f_LO_Step) */
4148 *FracN =
4149 (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
4150 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
4151
4152 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64);
4153}
4154
4155/****************************************************************************
4156**
4157** Name: CalcLO2Mult
4158**
4159** Description: Calculates Integer divider value and the numerator
4160** value for a FracN PLL.
4161**
4162** This function assumes that the f_LO and f_Ref are
4163** evenly divisible by f_LO_Step.
4164**
4165** Parameters: Div - OUTPUT: Whole number portion of the multiplier
4166** FracN - OUTPUT: Fractional portion of the multiplier
4167** f_LO - desired LO frequency.
4168** f_LO_Step - Minimum step size for the LO (in Hz).
4169** f_Ref - SRO frequency.
4170** f_Avoid - Range of PLL frequencies to avoid near
4171** integer multiples of f_Ref (in Hz).
4172**
4173** Returns: Recalculated LO frequency.
4174**
4175** Revision History:
4176**
4177** SCR Date Author Description
4178** -------------------------------------------------------------------------
4179** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
4180**
4181****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004182static u32 MT2063_CalcLO2Mult(u32 * Div,
4183 u32 * FracN,
4184 u32 f_LO,
4185 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004186{
4187 /* Calculate the whole number portion of the divider */
4188 *Div = f_LO / f_Ref;
4189
4190 /* Calculate the numerator value (round to nearest f_LO_Step) */
4191 *FracN =
4192 (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
4193 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
4194
4195 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN,
4196 8191);
4197}
4198
4199/****************************************************************************
4200**
4201** Name: FindClearTuneFilter
4202**
4203** Description: Calculate the corrrect ClearTune filter to be used for
4204** a given input frequency.
4205**
4206** Parameters: pInfo - ptr to tuner data structure
4207** f_in - RF input center frequency (in Hz).
4208**
4209** Returns: ClearTune filter number (0-31)
4210**
4211** Dependencies: MUST CALL MT2064_Open BEFORE FindClearTuneFilter!
4212**
4213** Revision History:
4214**
4215** SCR Date Author Description
4216** -------------------------------------------------------------------------
4217** 04-10-2008 PINZ Ver 1.14: Use software-controlled ClearTune
4218** cross-over frequency values.
4219**
4220****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004221static u32 FindClearTuneFilter(struct MT2063_Info_t *pInfo, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004222{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004223 u32 RFBand;
4224 u32 idx; /* index loop */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004225
4226 /*
4227 ** Find RF Band setting
4228 */
4229 RFBand = 31; /* def when f_in > all */
4230 for (idx = 0; idx < 31; ++idx) {
4231 if (pInfo->CTFiltMax[idx] >= f_in) {
4232 RFBand = idx;
4233 break;
4234 }
4235 }
4236 return (RFBand);
4237}
4238
4239/****************************************************************************
4240**
4241** Name: MT2063_Tune
4242**
4243** Description: Change the tuner's tuned frequency to RFin.
4244**
4245** Parameters: h - Open handle to the tuner (from MT2063_Open).
4246** f_in - RF input center frequency (in Hz).
4247**
4248** Returns: status:
4249** MT_OK - No errors
4250** MT_INV_HANDLE - Invalid tuner handle
4251** MT_UPC_UNLOCK - Upconverter PLL unlocked
4252** MT_DNC_UNLOCK - Downconverter PLL unlocked
4253** MT_COMM_ERR - Serial bus communications error
4254** MT_SPUR_CNT_MASK - Count of avoided LO spurs
4255** MT_SPUR_PRESENT - LO spur possible in output
4256** MT_FIN_RANGE - Input freq out of range
4257** MT_FOUT_RANGE - Output freq out of range
4258** MT_UPC_RANGE - Upconverter freq out of range
4259** MT_DNC_RANGE - Downconverter freq out of range
4260**
4261** Dependencies: MUST CALL MT2063_Open BEFORE MT2063_Tune!
4262**
4263** MT_ReadSub - Read data from the two-wire serial bus
4264** MT_WriteSub - Write data to the two-wire serial bus
4265** MT_Sleep - Delay execution for x milliseconds
4266** MT2063_GetLocked - Checks to see if LO1 and LO2 are locked
4267**
4268** Revision History:
4269**
4270** SCR Date Author Description
4271** -------------------------------------------------------------------------
4272** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
4273** 04-10-2008 PINZ Ver 1.05: Use software-controlled ClearTune
4274** cross-over frequency values.
4275** 175 I 16-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
4276** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
4277** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
4278**
4279****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03004280static u32 MT2063_Tune(void *h, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004281{ /* RF input center frequency */
4282 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
4283
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004284 u32 status = MT2063_OK; /* status of operation */
4285 u32 LO1; /* 1st LO register value */
4286 u32 Num1; /* Numerator for LO1 reg. value */
4287 u32 f_IF1; /* 1st IF requested */
4288 u32 LO2; /* 2nd LO register value */
4289 u32 Num2; /* Numerator for LO2 reg. value */
4290 u32 ofLO1, ofLO2; /* last time's LO frequencies */
4291 u32 ofin, ofout; /* last time's I/O frequencies */
4292 u8 fiffc = 0x80; /* FIFF center freq from tuner */
4293 u32 fiffof; /* Offset from FIFF center freq */
4294 const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */
4295 u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */
4296 u8 val;
4297 u32 RFBand;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004298
4299 /* Verify that the handle passed points to a valid tuner */
4300 if (MT2063_IsValidHandle(pInfo) == 0)
4301 return MT2063_INV_HANDLE;
4302
4303 /* Check the input and output frequency ranges */
4304 if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ))
4305 status |= MT2063_FIN_RANGE;
4306
4307 if ((pInfo->AS_Data.f_out < MT2063_MIN_FOUT_FREQ)
4308 || (pInfo->AS_Data.f_out > MT2063_MAX_FOUT_FREQ))
4309 status |= MT2063_FOUT_RANGE;
4310
4311 /*
4312 ** Save original LO1 and LO2 register values
4313 */
4314 ofLO1 = pInfo->AS_Data.f_LO1;
4315 ofLO2 = pInfo->AS_Data.f_LO2;
4316 ofin = pInfo->AS_Data.f_in;
4317 ofout = pInfo->AS_Data.f_out;
4318
4319 /*
4320 ** Find and set RF Band setting
4321 */
4322 if (pInfo->ctfilt_sw == 1) {
4323 val = (pInfo->reg[MT2063_REG_CTUNE_CTRL] | 0x08);
4324 if (pInfo->reg[MT2063_REG_CTUNE_CTRL] != val) {
4325 status |=
4326 MT2063_SetReg(pInfo, MT2063_REG_CTUNE_CTRL, val);
4327 }
4328 val = pInfo->reg[MT2063_REG_CTUNE_OV];
4329 RFBand = FindClearTuneFilter(pInfo, f_in);
4330 pInfo->reg[MT2063_REG_CTUNE_OV] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004331 (u8) ((pInfo->reg[MT2063_REG_CTUNE_OV] & ~0x1F)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004332 | RFBand);
4333 if (pInfo->reg[MT2063_REG_CTUNE_OV] != val) {
4334 status |=
4335 MT2063_SetReg(pInfo, MT2063_REG_CTUNE_OV, val);
4336 }
4337 }
4338
4339 /*
4340 ** Read the FIFF Center Frequency from the tuner
4341 */
4342 if (MT2063_NO_ERROR(status)) {
4343 status |=
4344 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
4345 MT2063_REG_FIFFC,
4346 &pInfo->reg[MT2063_REG_FIFFC], 1);
4347 fiffc = pInfo->reg[MT2063_REG_FIFFC];
4348 }
4349 /*
4350 ** Assign in the requested values
4351 */
4352 pInfo->AS_Data.f_in = f_in;
4353 /* Request a 1st IF such that LO1 is on a step size */
4354 pInfo->AS_Data.f_if1_Request =
4355 MT2063_Round_fLO(pInfo->AS_Data.f_if1_Request + f_in,
4356 pInfo->AS_Data.f_LO1_Step,
4357 pInfo->AS_Data.f_ref) - f_in;
4358
4359 /*
4360 ** Calculate frequency settings. f_IF1_FREQ + f_in is the
4361 ** desired LO1 frequency
4362 */
4363 MT2063_ResetExclZones(&pInfo->AS_Data);
4364
4365 f_IF1 = MT2063_ChooseFirstIF(&pInfo->AS_Data);
4366
4367 pInfo->AS_Data.f_LO1 =
4368 MT2063_Round_fLO(f_IF1 + f_in, pInfo->AS_Data.f_LO1_Step,
4369 pInfo->AS_Data.f_ref);
4370
4371 pInfo->AS_Data.f_LO2 =
4372 MT2063_Round_fLO(pInfo->AS_Data.f_LO1 - pInfo->AS_Data.f_out - f_in,
4373 pInfo->AS_Data.f_LO2_Step, pInfo->AS_Data.f_ref);
4374
4375 /*
4376 ** Check for any LO spurs in the output bandwidth and adjust
4377 ** the LO settings to avoid them if needed
4378 */
4379 status |= MT2063_AvoidSpurs(h, &pInfo->AS_Data);
4380 /*
4381 ** MT_AvoidSpurs spurs may have changed the LO1 & LO2 values.
4382 ** Recalculate the LO frequencies and the values to be placed
4383 ** in the tuning registers.
4384 */
4385 pInfo->AS_Data.f_LO1 =
4386 MT2063_CalcLO1Mult(&LO1, &Num1, pInfo->AS_Data.f_LO1,
4387 pInfo->AS_Data.f_LO1_Step, pInfo->AS_Data.f_ref);
4388 pInfo->AS_Data.f_LO2 =
4389 MT2063_Round_fLO(pInfo->AS_Data.f_LO1 - pInfo->AS_Data.f_out - f_in,
4390 pInfo->AS_Data.f_LO2_Step, pInfo->AS_Data.f_ref);
4391 pInfo->AS_Data.f_LO2 =
4392 MT2063_CalcLO2Mult(&LO2, &Num2, pInfo->AS_Data.f_LO2,
4393 pInfo->AS_Data.f_LO2_Step, pInfo->AS_Data.f_ref);
4394
4395 /*
4396 ** Check the upconverter and downconverter frequency ranges
4397 */
4398 if ((pInfo->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ)
4399 || (pInfo->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ))
4400 status |= MT2063_UPC_RANGE;
4401 if ((pInfo->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ)
4402 || (pInfo->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ))
4403 status |= MT2063_DNC_RANGE;
4404 /* LO2 Lock bit was in a different place for B0 version */
4405 if (pInfo->tuner_id == MT2063_B0)
4406 LO2LK = 0x40;
4407
4408 /*
4409 ** If we have the same LO frequencies and we're already locked,
4410 ** then skip re-programming the LO registers.
4411 */
4412 if ((ofLO1 != pInfo->AS_Data.f_LO1)
4413 || (ofLO2 != pInfo->AS_Data.f_LO2)
4414 || ((pInfo->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) !=
4415 (LO1LK | LO2LK))) {
4416 /*
4417 ** Calculate the FIFFOF register value
4418 **
4419 ** IF1_Actual
4420 ** FIFFOF = ------------ - 8 * FIFFC - 4992
4421 ** f_ref/64
4422 */
4423 fiffof =
4424 (pInfo->AS_Data.f_LO1 -
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004425 f_in) / (pInfo->AS_Data.f_ref / 64) - 8 * (u32) fiffc -
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004426 4992;
4427 if (fiffof > 0xFF)
4428 fiffof = 0xFF;
4429
4430 /*
4431 ** Place all of the calculated values into the local tuner
4432 ** register fields.
4433 */
4434 if (MT2063_NO_ERROR(status)) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004435 pInfo->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */
4436 pInfo->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */
4437 pInfo->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004438 |(Num2 >> 12)); /* NUM2q (hi) */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004439 pInfo->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */
4440 pInfo->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004441
4442 /*
4443 ** Now write out the computed register values
4444 ** IMPORTANT: There is a required order for writing
4445 ** (0x05 must follow all the others).
4446 */
4447 status |= MT2063_WriteSub(pInfo->hUserData, pInfo->address, MT2063_REG_LO1CQ_1, &pInfo->reg[MT2063_REG_LO1CQ_1], 5); /* 0x01 - 0x05 */
4448 if (pInfo->tuner_id == MT2063_B0) {
4449 /* Re-write the one-shot bits to trigger the tune operation */
4450 status |= MT2063_WriteSub(pInfo->hUserData, pInfo->address, MT2063_REG_LO2CQ_3, &pInfo->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */
4451 }
4452 /* Write out the FIFF offset only if it's changing */
4453 if (pInfo->reg[MT2063_REG_FIFF_OFFSET] !=
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004454 (u8) fiffof) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004455 pInfo->reg[MT2063_REG_FIFF_OFFSET] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004456 (u8) fiffof;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004457 status |=
4458 MT2063_WriteSub(pInfo->hUserData,
4459 pInfo->address,
4460 MT2063_REG_FIFF_OFFSET,
4461 &pInfo->
4462 reg[MT2063_REG_FIFF_OFFSET],
4463 1);
4464 }
4465 }
4466
4467 /*
4468 ** Check for LO's locking
4469 */
4470
4471 if (MT2063_NO_ERROR(status)) {
4472 status |= MT2063_GetLocked(h);
4473 }
4474 /*
4475 ** If we locked OK, assign calculated data to MT2063_Info_t structure
4476 */
4477 if (MT2063_NO_ERROR(status)) {
4478 pInfo->f_IF1_actual = pInfo->AS_Data.f_LO1 - f_in;
4479 }
4480 }
4481
4482 return (status);
4483}
4484
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03004485static u32 MT_Tune_atv(void *h, u32 f_in, u32 bw_in,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004486 enum MTTune_atv_standard tv_type)
4487{
4488
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004489 u32 status = MT2063_OK;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004490
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004491 s32 pict_car = 0;
4492 s32 pict2chanb_vsb = 0;
4493 s32 pict2chanb_snd = 0;
4494 s32 pict2snd1 = 0;
4495 s32 pict2snd2 = 0;
4496 s32 ch_bw = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004497
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004498 s32 if_mid = 0;
4499 s32 rcvr_mode = 0;
4500 u32 mode_get = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004501
4502 switch (tv_type) {
4503 case MTTUNEA_PAL_B:{
4504 pict_car = 38900000;
4505 ch_bw = 8000000;
4506 pict2chanb_vsb = -1250000;
4507 pict2snd1 = 5500000;
4508 pict2snd2 = 5742000;
4509 rcvr_mode = 1;
4510 break;
4511 }
4512 case MTTUNEA_PAL_G:{
4513 pict_car = 38900000;
4514 ch_bw = 7000000;
4515 pict2chanb_vsb = -1250000;
4516 pict2snd1 = 5500000;
4517 pict2snd2 = 0;
4518 rcvr_mode = 1;
4519 break;
4520 }
4521 case MTTUNEA_PAL_I:{
4522 pict_car = 38900000;
4523 ch_bw = 8000000;
4524 pict2chanb_vsb = -1250000;
4525 pict2snd1 = 6000000;
4526 pict2snd2 = 0;
4527 rcvr_mode = 1;
4528 break;
4529 }
4530 case MTTUNEA_PAL_L:{
4531 pict_car = 38900000;
4532 ch_bw = 8000000;
4533 pict2chanb_vsb = -1250000;
4534 pict2snd1 = 6500000;
4535 pict2snd2 = 0;
4536 rcvr_mode = 1;
4537 break;
4538 }
4539 case MTTUNEA_PAL_MN:{
4540 pict_car = 38900000;
4541 ch_bw = 6000000;
4542 pict2chanb_vsb = -1250000;
4543 pict2snd1 = 4500000;
4544 pict2snd2 = 0;
4545 rcvr_mode = 1;
4546 break;
4547 }
4548 case MTTUNEA_PAL_DK:{
4549 pict_car = 38900000;
4550 ch_bw = 8000000;
4551 pict2chanb_vsb = -1250000;
4552 pict2snd1 = 6500000;
4553 pict2snd2 = 0;
4554 rcvr_mode = 1;
4555 break;
4556 }
4557 case MTTUNEA_DIGITAL:{
4558 pict_car = 36125000;
4559 ch_bw = 8000000;
4560 pict2chanb_vsb = -(ch_bw / 2);
4561 pict2snd1 = 0;
4562 pict2snd2 = 0;
4563 rcvr_mode = 2;
4564 break;
4565 }
4566 case MTTUNEA_FMRADIO:{
4567 pict_car = 38900000;
4568 ch_bw = 8000000;
4569 pict2chanb_vsb = -(ch_bw / 2);
4570 pict2snd1 = 0;
4571 pict2snd2 = 0;
4572 rcvr_mode = 4;
4573 //f_in -= 2900000;
4574 break;
4575 }
4576 case MTTUNEA_DVBC:{
4577 pict_car = 36125000;
4578 ch_bw = 8000000;
4579 pict2chanb_vsb = -(ch_bw / 2);
4580 pict2snd1 = 0;
4581 pict2snd2 = 0;
4582 rcvr_mode = MT2063_CABLE_QAM;
4583 break;
4584 }
4585 case MTTUNEA_DVBT:{
4586 pict_car = 36125000;
4587 ch_bw = bw_in; //8000000
4588 pict2chanb_vsb = -(ch_bw / 2);
4589 pict2snd1 = 0;
4590 pict2snd2 = 0;
4591 rcvr_mode = MT2063_OFFAIR_COFDM;
4592 break;
4593 }
4594 case MTTUNEA_UNKNOWN:
4595 break;
4596 default:
4597 break;
4598 }
4599
4600 pict2chanb_snd = pict2chanb_vsb - ch_bw;
4601 if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
4602
4603 status |= MT2063_SetParam(h, MT2063_STEPSIZE, 125000);
4604 status |= MT2063_SetParam(h, MT2063_OUTPUT_FREQ, if_mid);
4605 status |= MT2063_SetParam(h, MT2063_OUTPUT_BW, ch_bw);
4606 status |= MT2063_GetParam(h, MT2063_RCVR_MODE, &mode_get);
4607
4608 status |= MT2063_SetParam(h, MT2063_RCVR_MODE, rcvr_mode);
4609 status |= MT2063_Tune(h, (f_in + (pict2chanb_vsb + (ch_bw / 2))));
4610 status |= MT2063_GetParam(h, MT2063_RCVR_MODE, &mode_get);
4611
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004612 return (u32) status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004613}
4614
4615static int mt2063_init(struct dvb_frontend *fe)
4616{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004617 u32 status = MT2063_ERROR;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004618 struct mt2063_state *state = fe->tuner_priv;
4619
4620 status = MT2063_Open(0xC0, &(state->MT2063_ht), fe);
4621 status |= MT2063_SoftwareShutdown(state->MT2063_ht, 1);
4622 status |= MT2063_ClearPowerMaskBits(state->MT2063_ht, MT2063_ALL_SD);
4623
4624 if (MT2063_OK != status) {
4625 printk("%s %d error status = 0x%x!!\n", __func__, __LINE__,
4626 status);
4627 return -1;
4628 }
4629
4630 return 0;
4631}
4632
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004633static int mt2063_get_status(struct dvb_frontend *fe, u32 * status)
4634{
4635 int rc = 0;
4636
4637 //get tuner lock status
4638
4639 return rc;
4640}
4641
4642static int mt2063_get_state(struct dvb_frontend *fe,
4643 enum tuner_param param, struct tuner_state *state)
4644{
4645 struct mt2063_state *mt2063State = fe->tuner_priv;
4646
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004647 switch (param) {
4648 case DVBFE_TUNER_FREQUENCY:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004649 //get frequency
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004650 break;
4651 case DVBFE_TUNER_TUNERSTEP:
4652 break;
4653 case DVBFE_TUNER_IFFREQ:
4654 break;
4655 case DVBFE_TUNER_BANDWIDTH:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004656 //get bandwidth
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004657 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004658 case DVBFE_TUNER_REFCLOCK:
4659 state->refclock =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004660 (u32)
4661 MT2063_GetLocked((void *) (mt2063State->MT2063_ht));
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004662 break;
4663 default:
4664 break;
4665 }
4666
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004667 return (int)state->refclock;
4668}
4669
4670static int mt2063_set_state(struct dvb_frontend *fe,
4671 enum tuner_param param, struct tuner_state *state)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004672{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004673 struct mt2063_state *mt2063State = fe->tuner_priv;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004674 u32 status = MT2063_OK;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004675
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004676 switch (param) {
4677 case DVBFE_TUNER_FREQUENCY:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004678 //set frequency
4679
4680 status =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004681 MT_Tune_atv((void *) (mt2063State->MT2063_ht),
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004682 state->frequency, state->bandwidth,
4683 mt2063State->tv_type);
4684
4685 mt2063State->frequency = state->frequency;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004686 break;
4687 case DVBFE_TUNER_TUNERSTEP:
4688 break;
4689 case DVBFE_TUNER_IFFREQ:
4690 break;
4691 case DVBFE_TUNER_BANDWIDTH:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004692 //set bandwidth
4693 mt2063State->bandwidth = state->bandwidth;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004694 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004695 case DVBFE_TUNER_REFCLOCK:
4696
4697 break;
4698 case DVBFE_TUNER_OPEN:
4699 status = MT2063_Open(MT2063_I2C, &(mt2063State->MT2063_ht), fe);
4700 break;
4701 case DVBFE_TUNER_SOFTWARE_SHUTDOWN:
4702 status = MT2063_SoftwareShutdown(mt2063State->MT2063_ht, 1);
4703 break;
4704 case DVBFE_TUNER_CLEAR_POWER_MASKBITS:
4705 status =
4706 MT2063_ClearPowerMaskBits(mt2063State->MT2063_ht,
4707 MT2063_ALL_SD);
4708 break;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004709 default:
4710 break;
4711 }
4712
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004713 return (int)status;
4714}
4715
4716static int mt2063_release(struct dvb_frontend *fe)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004717{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004718 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004719
4720 fe->tuner_priv = NULL;
4721 kfree(state);
4722
4723 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004724}
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004725
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004726static struct dvb_tuner_ops mt2063_ops = {
4727 .info = {
4728 .name = "MT2063 Silicon Tuner",
4729 .frequency_min = 45000000,
4730 .frequency_max = 850000000,
4731 .frequency_step = 0,
4732 },
4733
4734 .init = mt2063_init,
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03004735 .sleep = MT2063_Sleep,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004736 .get_status = mt2063_get_status,
4737 .get_state = mt2063_get_state,
4738 .set_state = mt2063_set_state,
4739 .release = mt2063_release
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004740};
4741
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004742struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
4743 struct mt2063_config *config,
4744 struct i2c_adapter *i2c)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004745{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004746 struct mt2063_state *state = NULL;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004747
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004748 state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004749 if (state == NULL)
4750 goto error;
4751
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004752 state->config = config;
4753 state->i2c = i2c;
4754 state->frontend = fe;
4755 state->reference = config->refclock / 1000; /* kHz */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004756 state->MT2063_init = false;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004757 fe->tuner_priv = state;
4758 fe->ops.tuner_ops = mt2063_ops;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004759
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004760 printk("%s: Attaching MT2063 \n", __func__);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004761 return fe;
4762
4763error:
4764 kfree(state);
4765 return NULL;
4766}
4767
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004768EXPORT_SYMBOL(mt2063_attach);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004769MODULE_PARM_DESC(verbose, "Set Verbosity level");
4770
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004771MODULE_AUTHOR("Henry");
4772MODULE_DESCRIPTION("MT2063 Silicon tuner");
4773MODULE_LICENSE("GPL");