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