blob: 30c72c0423b17ac08e06e9a67f0e7fd75e61a4ff [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
Mauro Carvalho Chehab29a0a4f2011-07-20 23:44:10 -030019/* FIXME: Those two error codes need conversion*/
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030020/* Error: Upconverter PLL is not locked */
21#define MT2063_UPC_UNLOCK (0x80000002)
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030022/* Error: Downconverter PLL is not locked */
23#define MT2063_DNC_UNLOCK (0x80000004)
Mauro Carvalho Chehab29a0a4f2011-07-20 23:44:10 -030024
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -030025/* Info: Unavoidable LO-related spur may be present in the output */
Mauro Carvalho Chehab29a0a4f2011-07-20 23:44:10 -030026#define MT2063_SPUR_PRESENT_ERR (0x00800000)
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030027
28/* Info: Mask of bits used for # of LO-related spurs that were avoided during tuning */
29#define MT2063_SPUR_CNT_MASK (0x001f0000)
30#define MT2063_SPUR_SHIFT (16)
31
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030032/* Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */
33#define MT2063_UPC_RANGE (0x04000000)
34
35/* Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */
36#define MT2063_DNC_RANGE (0x08000000)
37
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030038#define MAX_UDATA (4294967295) /* max value storable in u32 */
39
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030040#define MT2063_TUNER_CNT (1) /* total num of MicroTuner tuners */
41#define MT2063_I2C (0xC0)
42
43/*
Mauro Carvalho Chehab29a0a4f2011-07-20 23:44:10 -030044 * Data Types
45 */
46
47/*
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030048 * Constant defining the version of the following structure
49 * and therefore the API for this code.
50 *
51 * When compiling the tuner driver, the preprocessor will
52 * check against this version number to make sure that
53 * it matches the version that the tuner driver knows about.
54 */
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030055
56/* DECT Frequency Avoidance */
57#define MT2063_DECT_AVOID_US_FREQS 0x00000001
58
59#define MT2063_DECT_AVOID_EURO_FREQS 0x00000002
60
61#define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0)
62
63#define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0)
64
65enum MT2063_DECT_Avoid_Type {
66 MT2063_NO_DECT_AVOIDANCE = 0, /* Do not create DECT exclusion zones. */
67 MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS, /* Avoid US DECT frequencies. */
68 MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS, /* Avoid European DECT frequencies. */
69 MT2063_AVOID_BOTH /* Avoid both regions. Not typically used. */
70};
71
72#define MT2063_MAX_ZONES 48
73
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030074struct MT2063_ExclZone_t {
75 u32 min_;
76 u32 max_;
77 struct MT2063_ExclZone_t *next_;
78};
79
80/*
81 * Structure of data needed for Spur Avoidance
82 */
83struct MT2063_AvoidSpursData_t {
84 u32 nAS_Algorithm;
85 u32 f_ref;
86 u32 f_in;
87 u32 f_LO1;
88 u32 f_if1_Center;
89 u32 f_if1_Request;
90 u32 f_if1_bw;
91 u32 f_LO2;
92 u32 f_out;
93 u32 f_out_bw;
94 u32 f_LO1_Step;
95 u32 f_LO2_Step;
96 u32 f_LO1_FracN_Avoid;
97 u32 f_LO2_FracN_Avoid;
98 u32 f_zif_bw;
99 u32 f_min_LO_Separation;
100 u32 maxH1;
101 u32 maxH2;
102 enum MT2063_DECT_Avoid_Type avoidDECT;
103 u32 bSpurPresent;
104 u32 bSpurAvoided;
105 u32 nSpursFound;
106 u32 nZones;
107 struct MT2063_ExclZone_t *freeZones;
108 struct MT2063_ExclZone_t *usedZones;
109 struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES];
110};
111
112/*
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300113 * Parameter for function MT2063_SetPowerMask that specifies the power down
114 * of various sections of the MT2063.
115 */
116enum MT2063_Mask_Bits {
117 MT2063_REG_SD = 0x0040, /* Shutdown regulator */
118 MT2063_SRO_SD = 0x0020, /* Shutdown SRO */
119 MT2063_AFC_SD = 0x0010, /* Shutdown AFC A/D */
120 MT2063_PD_SD = 0x0002, /* Enable power detector shutdown */
121 MT2063_PDADC_SD = 0x0001, /* Enable power detector A/D shutdown */
122 MT2063_VCO_SD = 0x8000, /* Enable VCO shutdown */
123 MT2063_LTX_SD = 0x4000, /* Enable LTX shutdown */
124 MT2063_LT1_SD = 0x2000, /* Enable LT1 shutdown */
125 MT2063_LNA_SD = 0x1000, /* Enable LNA shutdown */
126 MT2063_UPC_SD = 0x0800, /* Enable upconverter shutdown */
127 MT2063_DNC_SD = 0x0400, /* Enable downconverter shutdown */
128 MT2063_VGA_SD = 0x0200, /* Enable VGA shutdown */
129 MT2063_AMP_SD = 0x0100, /* Enable AMP shutdown */
130 MT2063_ALL_SD = 0xFF73, /* All shutdown bits for this tuner */
131 MT2063_NONE_SD = 0x0000 /* No shutdown bits */
132};
133
134/*
135 * Parameter for function MT2063_GetParam & MT2063_SetParam that
136 * specifies the tuning algorithm parameter to be read/written.
137 */
138enum MT2063_Param {
139 /* tuner address set by MT2063_Open() */
140 MT2063_IC_ADDR,
141
142 /* max number of MT2063 tuners set by MT_TUNER_CNT in mt_userdef.h */
143 MT2063_MAX_OPEN,
144
145 /* current number of open MT2063 tuners set by MT2063_Open() */
146 MT2063_NUM_OPEN,
147
148 /* crystal frequency (default: 16000000 Hz) */
149 MT2063_SRO_FREQ,
150
151 /* min tuning step size (default: 50000 Hz) */
152 MT2063_STEPSIZE,
153
154 /* input center frequency set by MT2063_Tune() */
155 MT2063_INPUT_FREQ,
156
157 /* LO1 Frequency set by MT2063_Tune() */
158 MT2063_LO1_FREQ,
159
160 /* LO1 minimum step size (default: 250000 Hz) */
161 MT2063_LO1_STEPSIZE,
162
163 /* LO1 FracN keep-out region (default: 999999 Hz) */
164 MT2063_LO1_FRACN_AVOID_PARAM,
165
166 /* Current 1st IF in use set by MT2063_Tune() */
167 MT2063_IF1_ACTUAL,
168
169 /* Requested 1st IF set by MT2063_Tune() */
170 MT2063_IF1_REQUEST,
171
172 /* Center of 1st IF SAW filter (default: 1218000000 Hz) */
173 MT2063_IF1_CENTER,
174
175 /* Bandwidth of 1st IF SAW filter (default: 20000000 Hz) */
176 MT2063_IF1_BW,
177
178 /* zero-IF bandwidth (default: 2000000 Hz) */
179 MT2063_ZIF_BW,
180
181 /* LO2 Frequency set by MT2063_Tune() */
182 MT2063_LO2_FREQ,
183
184 /* LO2 minimum step size (default: 50000 Hz) */
185 MT2063_LO2_STEPSIZE,
186
187 /* LO2 FracN keep-out region (default: 374999 Hz) */
188 MT2063_LO2_FRACN_AVOID,
189
190 /* output center frequency set by MT2063_Tune() */
191 MT2063_OUTPUT_FREQ,
192
193 /* output bandwidth set by MT2063_Tune() */
194 MT2063_OUTPUT_BW,
195
196 /* min inter-tuner LO separation (default: 1000000 Hz) */
197 MT2063_LO_SEPARATION,
198
199 /* ID of avoid-spurs algorithm in use compile-time constant */
200 MT2063_AS_ALG,
201
202 /* max # of intra-tuner harmonics (default: 15) */
203 MT2063_MAX_HARM1,
204
205 /* max # of inter-tuner harmonics (default: 7) */
206 MT2063_MAX_HARM2,
207
208 /* # of 1st IF exclusion zones used set by MT2063_Tune() */
209 MT2063_EXCL_ZONES,
210
211 /* # of spurs found/avoided set by MT2063_Tune() */
212 MT2063_NUM_SPURS,
213
214 /* >0 spurs avoided set by MT2063_Tune() */
215 MT2063_SPUR_AVOIDED,
216
217 /* >0 spurs in output (mathematically) set by MT2063_Tune() */
218 MT2063_SPUR_PRESENT,
219
220 /* Receiver Mode for some parameters. 1 is DVB-T */
221 MT2063_RCVR_MODE,
222
223 /* directly set LNA attenuation, parameter is value to set */
224 MT2063_ACLNA,
225
226 /* maximum LNA attenuation, parameter is value to set */
227 MT2063_ACLNA_MAX,
228
229 /* directly set ATN attenuation. Paremeter is value to set. */
230 MT2063_ACRF,
231
232 /* maxium ATN attenuation. Paremeter is value to set. */
233 MT2063_ACRF_MAX,
234
235 /* directly set FIF attenuation. Paremeter is value to set. */
236 MT2063_ACFIF,
237
238 /* maxium FIF attenuation. Paremeter is value to set. */
239 MT2063_ACFIF_MAX,
240
241 /* LNA Rin */
242 MT2063_LNA_RIN,
243
244 /* Power Detector LNA level target */
245 MT2063_LNA_TGT,
246
247 /* Power Detector 1 level */
248 MT2063_PD1,
249
250 /* Power Detector 1 level target */
251 MT2063_PD1_TGT,
252
253 /* Power Detector 2 level */
254 MT2063_PD2,
255
256 /* Power Detector 2 level target */
257 MT2063_PD2_TGT,
258
259 /* Selects, which DNC is activ */
260 MT2063_DNC_OUTPUT_ENABLE,
261
262 /* VGA gain code */
263 MT2063_VGAGC,
264
265 /* VGA bias current */
266 MT2063_VGAOI,
267
268 /* TAGC, determins the speed of the AGC */
269 MT2063_TAGC,
270
271 /* AMP gain code */
272 MT2063_AMPGC,
273
274 /* Control setting to avoid DECT freqs (default: MT_AVOID_BOTH) */
275 MT2063_AVOID_DECT,
276
277 /* Cleartune filter selection: 0 - by IC (default), 1 - by software */
278 MT2063_CTFILT_SW,
279
280 MT2063_EOP /* last entry in enumerated list */
281};
282
283/*
284 * Parameter for selecting tuner mode
285 */
286enum MT2063_RCVR_MODES {
287 MT2063_CABLE_QAM = 0, /* Digital cable */
288 MT2063_CABLE_ANALOG, /* Analog cable */
289 MT2063_OFFAIR_COFDM, /* Digital offair */
290 MT2063_OFFAIR_COFDM_SAWLESS, /* Digital offair without SAW */
291 MT2063_OFFAIR_ANALOG, /* Analog offair */
292 MT2063_OFFAIR_8VSB, /* Analog offair */
293 MT2063_NUM_RCVR_MODES
294};
295
296/*
297 * Possible values for MT2063_DNC_OUTPUT
298 */
299enum MT2063_DNC_Output_Enable {
300 MT2063_DNC_NONE = 0,
301 MT2063_DNC_1,
302 MT2063_DNC_2,
303 MT2063_DNC_BOTH
304};
305
306/*
307** Two-wire serial bus subaddresses of the tuner registers.
308** Also known as the tuner's register addresses.
309*/
310enum MT2063_Register_Offsets {
311 MT2063_REG_PART_REV = 0, /* 0x00: Part/Rev Code */
312 MT2063_REG_LO1CQ_1, /* 0x01: LO1C Queued Byte 1 */
313 MT2063_REG_LO1CQ_2, /* 0x02: LO1C Queued Byte 2 */
314 MT2063_REG_LO2CQ_1, /* 0x03: LO2C Queued Byte 1 */
315 MT2063_REG_LO2CQ_2, /* 0x04: LO2C Queued Byte 2 */
316 MT2063_REG_LO2CQ_3, /* 0x05: LO2C Queued Byte 3 */
317 MT2063_REG_RSVD_06, /* 0x06: Reserved */
318 MT2063_REG_LO_STATUS, /* 0x07: LO Status */
319 MT2063_REG_FIFFC, /* 0x08: FIFF Center */
320 MT2063_REG_CLEARTUNE, /* 0x09: ClearTune Filter */
321 MT2063_REG_ADC_OUT, /* 0x0A: ADC_OUT */
322 MT2063_REG_LO1C_1, /* 0x0B: LO1C Byte 1 */
323 MT2063_REG_LO1C_2, /* 0x0C: LO1C Byte 2 */
324 MT2063_REG_LO2C_1, /* 0x0D: LO2C Byte 1 */
325 MT2063_REG_LO2C_2, /* 0x0E: LO2C Byte 2 */
326 MT2063_REG_LO2C_3, /* 0x0F: LO2C Byte 3 */
327 MT2063_REG_RSVD_10, /* 0x10: Reserved */
328 MT2063_REG_PWR_1, /* 0x11: PWR Byte 1 */
329 MT2063_REG_PWR_2, /* 0x12: PWR Byte 2 */
330 MT2063_REG_TEMP_STATUS, /* 0x13: Temp Status */
331 MT2063_REG_XO_STATUS, /* 0x14: Crystal Status */
332 MT2063_REG_RF_STATUS, /* 0x15: RF Attn Status */
333 MT2063_REG_FIF_STATUS, /* 0x16: FIF Attn Status */
334 MT2063_REG_LNA_OV, /* 0x17: LNA Attn Override */
335 MT2063_REG_RF_OV, /* 0x18: RF Attn Override */
336 MT2063_REG_FIF_OV, /* 0x19: FIF Attn Override */
337 MT2063_REG_LNA_TGT, /* 0x1A: Reserved */
338 MT2063_REG_PD1_TGT, /* 0x1B: Pwr Det 1 Target */
339 MT2063_REG_PD2_TGT, /* 0x1C: Pwr Det 2 Target */
340 MT2063_REG_RSVD_1D, /* 0x1D: Reserved */
341 MT2063_REG_RSVD_1E, /* 0x1E: Reserved */
342 MT2063_REG_RSVD_1F, /* 0x1F: Reserved */
343 MT2063_REG_RSVD_20, /* 0x20: Reserved */
344 MT2063_REG_BYP_CTRL, /* 0x21: Bypass Control */
345 MT2063_REG_RSVD_22, /* 0x22: Reserved */
346 MT2063_REG_RSVD_23, /* 0x23: Reserved */
347 MT2063_REG_RSVD_24, /* 0x24: Reserved */
348 MT2063_REG_RSVD_25, /* 0x25: Reserved */
349 MT2063_REG_RSVD_26, /* 0x26: Reserved */
350 MT2063_REG_RSVD_27, /* 0x27: Reserved */
351 MT2063_REG_FIFF_CTRL, /* 0x28: FIFF Control */
352 MT2063_REG_FIFF_OFFSET, /* 0x29: FIFF Offset */
353 MT2063_REG_CTUNE_CTRL, /* 0x2A: Reserved */
354 MT2063_REG_CTUNE_OV, /* 0x2B: Reserved */
355 MT2063_REG_CTRL_2C, /* 0x2C: Reserved */
356 MT2063_REG_FIFF_CTRL2, /* 0x2D: Fiff Control */
357 MT2063_REG_RSVD_2E, /* 0x2E: Reserved */
358 MT2063_REG_DNC_GAIN, /* 0x2F: DNC Control */
359 MT2063_REG_VGA_GAIN, /* 0x30: VGA Gain Ctrl */
360 MT2063_REG_RSVD_31, /* 0x31: Reserved */
361 MT2063_REG_TEMP_SEL, /* 0x32: Temperature Selection */
362 MT2063_REG_RSVD_33, /* 0x33: Reserved */
363 MT2063_REG_RSVD_34, /* 0x34: Reserved */
364 MT2063_REG_RSVD_35, /* 0x35: Reserved */
365 MT2063_REG_RSVD_36, /* 0x36: Reserved */
366 MT2063_REG_RSVD_37, /* 0x37: Reserved */
367 MT2063_REG_RSVD_38, /* 0x38: Reserved */
368 MT2063_REG_RSVD_39, /* 0x39: Reserved */
369 MT2063_REG_RSVD_3A, /* 0x3A: Reserved */
370 MT2063_REG_RSVD_3B, /* 0x3B: Reserved */
371 MT2063_REG_RSVD_3C, /* 0x3C: Reserved */
372 MT2063_REG_END_REGS
373};
374
375struct MT2063_Info_t {
376 void *handle;
377 void *hUserData;
378 u32 address;
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300379 u32 tuner_id;
380 struct MT2063_AvoidSpursData_t AS_Data;
381 u32 f_IF1_actual;
382 u32 rcvr_mode;
383 u32 ctfilt_sw;
384 u32 CTFiltMax[31];
385 u32 num_regs;
386 u8 reg[MT2063_REG_END_REGS];
387};
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300388
389enum MTTune_atv_standard {
390 MTTUNEA_UNKNOWN = 0,
391 MTTUNEA_PAL_B,
392 MTTUNEA_PAL_G,
393 MTTUNEA_PAL_I,
394 MTTUNEA_PAL_L,
395 MTTUNEA_PAL_MN,
396 MTTUNEA_PAL_DK,
397 MTTUNEA_DIGITAL,
398 MTTUNEA_FMRADIO,
399 MTTUNEA_DVBC,
400 MTTUNEA_DVBT
401};
402
403
404struct mt2063_state {
405 struct i2c_adapter *i2c;
406
407 const struct mt2063_config *config;
408 struct dvb_tuner_ops ops;
409 struct dvb_frontend *frontend;
410 struct tuner_state status;
411 struct MT2063_Info_t *MT2063_ht;
412 bool MT2063_init;
413
414 enum MTTune_atv_standard tv_type;
415 u32 frequency;
416 u32 srate;
417 u32 bandwidth;
418 u32 reference;
419};
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300420
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300421/* Prototypes */
422static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
423 u32 f_min, u32 f_max);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300424static u32 MT2063_ReInit(struct MT2063_Info_t *pInfo);
425static u32 MT2063_Close(struct MT2063_Info_t *pInfo);
426static u32 MT2063_GetReg(struct MT2063_Info_t *pInfo, u8 reg, u8 * val);
427static u32 MT2063_GetParam(struct MT2063_Info_t *pInfo, enum MT2063_Param param, u32 * pValue);
428static u32 MT2063_SetReg(struct MT2063_Info_t *pInfo, u8 reg, u8 val);
Mauro Carvalho Chehab29a0a4f2011-07-20 23:44:10 -0300429static u32 MT2063_SetParam(struct MT2063_Info_t *pInfo, enum MT2063_Param param,
430 enum MT2063_DNC_Output_Enable nValue);
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300431
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300432/*****************/
433/* From drivers/media/common/tuners/mt2063_cfg.h */
434
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300435unsigned int mt2063_setTune(struct dvb_frontend *fe, u32 f_in,
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300436 u32 bw_in,
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300437 enum MTTune_atv_standard tv_type)
438{
439 //return (int)MT_Tune_atv(h, f_in, bw_in, tv_type);
440
441 struct dvb_frontend_ops *frontend_ops = NULL;
442 struct dvb_tuner_ops *tuner_ops = NULL;
443 struct tuner_state t_state;
444 struct mt2063_state *mt2063State = fe->tuner_priv;
445 int err = 0;
446
447 t_state.frequency = f_in;
448 t_state.bandwidth = bw_in;
449 mt2063State->tv_type = tv_type;
450 if (&fe->ops)
451 frontend_ops = &fe->ops;
452 if (&frontend_ops->tuner_ops)
453 tuner_ops = &frontend_ops->tuner_ops;
454 if (tuner_ops->set_state) {
455 if ((err =
456 tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY,
457 &t_state)) < 0) {
458 printk("%s: Invalid parameter\n", __func__);
459 return err;
460 }
461 }
462
463 return err;
464}
465
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300466unsigned int mt2063_lockStatus(struct dvb_frontend *fe)
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300467{
468 struct dvb_frontend_ops *frontend_ops = &fe->ops;
469 struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
470 struct tuner_state t_state;
471 int err = 0;
472
473 if (&fe->ops)
474 frontend_ops = &fe->ops;
475 if (&frontend_ops->tuner_ops)
476 tuner_ops = &frontend_ops->tuner_ops;
477 if (tuner_ops->get_state) {
478 if ((err =
479 tuner_ops->get_state(fe, DVBFE_TUNER_REFCLOCK,
480 &t_state)) < 0) {
481 printk("%s: Invalid parameter\n", __func__);
482 return err;
483 }
484 }
485 return err;
486}
487
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300488unsigned int tuner_MT2063_Open(struct dvb_frontend *fe)
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300489{
490 struct dvb_frontend_ops *frontend_ops = &fe->ops;
491 struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
492 struct tuner_state t_state;
493 int err = 0;
494
495 if (&fe->ops)
496 frontend_ops = &fe->ops;
497 if (&frontend_ops->tuner_ops)
498 tuner_ops = &frontend_ops->tuner_ops;
499 if (tuner_ops->set_state) {
500 if ((err =
501 tuner_ops->set_state(fe, DVBFE_TUNER_OPEN,
502 &t_state)) < 0) {
503 printk("%s: Invalid parameter\n", __func__);
504 return err;
505 }
506 }
507
508 return err;
509}
510
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300511unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe)
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300512{
513 struct dvb_frontend_ops *frontend_ops = &fe->ops;
514 struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
515 struct tuner_state t_state;
516 int err = 0;
517
518 if (&fe->ops)
519 frontend_ops = &fe->ops;
520 if (&frontend_ops->tuner_ops)
521 tuner_ops = &frontend_ops->tuner_ops;
522 if (tuner_ops->set_state) {
523 if ((err =
524 tuner_ops->set_state(fe, DVBFE_TUNER_SOFTWARE_SHUTDOWN,
525 &t_state)) < 0) {
526 printk("%s: Invalid parameter\n", __func__);
527 return err;
528 }
529 }
530
531 return err;
532}
533
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300534unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe)
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300535{
536 struct dvb_frontend_ops *frontend_ops = &fe->ops;
537 struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
538 struct tuner_state t_state;
539 int err = 0;
540
541 if (&fe->ops)
542 frontend_ops = &fe->ops;
543 if (&frontend_ops->tuner_ops)
544 tuner_ops = &frontend_ops->tuner_ops;
545 if (tuner_ops->set_state) {
546 if ((err =
547 tuner_ops->set_state(fe, DVBFE_TUNER_CLEAR_POWER_MASKBITS,
548 &t_state)) < 0) {
549 printk("%s: Invalid parameter\n", __func__);
550 return err;
551 }
552 }
553
554 return err;
555}
556
557/*****************/
558
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300559//i2c operation
560static int mt2063_writeregs(struct mt2063_state *state, u8 reg1,
561 u8 * data, int len)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300562{
563 int ret;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300564 u8 buf[60]; /* = { reg1, data }; */
565
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300566 struct i2c_msg msg = {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300567 .addr = state->config->tuner_address,
568 .flags = 0,
569 .buf = buf,
570 .len = len + 1
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300571 };
572
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300573 msg.buf[0] = reg1;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300574 memcpy(msg.buf + 1, data, len);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300575
576 //printk("mt2063_writeregs state->i2c=%p\n", state->i2c);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300577 ret = i2c_transfer(state->i2c, &msg, 1);
578
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300579 if (ret < 0)
580 printk("mt2063_writeregs error ret=%d\n", ret);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300581
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300582 return ret;
583}
584
585static int mt2063_read_regs(struct mt2063_state *state, u8 reg1, u8 * b, u8 len)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300586{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300587 int ret;
588 u8 b0[] = { reg1 };
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300589 struct i2c_msg msg[] = {
590 {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300591 .addr = state->config->tuner_address,
592 .flags = I2C_M_RD,
593 .buf = b0,
594 .len = 1}, {
595 .addr = state->config->tuner_address,
596 .flags = I2C_M_RD,
597 .buf = b,
598 .len = len}
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300599 };
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300600
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300601 //printk("mt2063_read_regs state->i2c=%p\n", state->i2c);
602 ret = i2c_transfer(state->i2c, msg, 2);
603 if (ret < 0)
604 printk("mt2063_readregs error ret=%d\n", ret);
605
606 return ret;
607}
608
609//context of mt2063_userdef.c <Henry> ======================================
610//#################################################################
611//=================================================================
612/*****************************************************************************
613**
614** Name: MT_WriteSub
615**
616** Description: Write values to device using a two-wire serial bus.
617**
618** Parameters: hUserData - User-specific I/O parameter that was
619** passed to tuner's Open function.
620** addr - device serial bus address (value passed
621** as parameter to MTxxxx_Open)
622** subAddress - serial bus sub-address (Register Address)
623** pData - pointer to the Data to be written to the
624** device
625** cnt - number of bytes/registers to be written
626**
627** Returns: status:
628** MT_OK - No errors
629** MT_COMM_ERR - Serial bus communications error
630** user-defined
631**
632** Notes: This is a callback function that is called from the
633** the tuning algorithm. You MUST provide code for this
634** function to write data using the tuner's 2-wire serial
635** bus.
636**
637** The hUserData parameter is a user-specific argument.
638** If additional arguments are needed for the user's
639** serial bus read/write functions, this argument can be
640** used to supply the necessary information.
641** The hUserData parameter is initialized in the tuner's Open
642** function.
643**
644** Revision History:
645**
646** SCR Date Author Description
647** -------------------------------------------------------------------------
648** N/A 03-25-2004 DAD Original
649**
650*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300651static u32 MT2063_WriteSub(void *hUserData,
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300652 u32 addr,
653 u8 subAddress, u8 * pData, u32 cnt)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300654{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300655 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300656 struct dvb_frontend *fe = hUserData;
657 struct mt2063_state *state = fe->tuner_priv;
658 /*
659 ** ToDo: Add code here to implement a serial-bus write
660 ** operation to the MTxxxx tuner. If successful,
661 ** return MT_OK.
662 */
663/* return status; */
664
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300665 fe->ops.i2c_gate_ctrl(fe, 1); //I2C bypass drxk3926 close i2c bridge
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300666
667 if (mt2063_writeregs(state, subAddress, pData, cnt) < 0) {
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300668 status = -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300669 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300670 fe->ops.i2c_gate_ctrl(fe, 0); //I2C bypass drxk3926 close i2c bridge
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300671
672 return (status);
673}
674
675/*****************************************************************************
676**
677** Name: MT_ReadSub
678**
679** Description: Read values from device using a two-wire serial bus.
680**
681** Parameters: hUserData - User-specific I/O parameter that was
682** passed to tuner's Open function.
683** addr - device serial bus address (value passed
684** as parameter to MTxxxx_Open)
685** subAddress - serial bus sub-address (Register Address)
686** pData - pointer to the Data to be written to the
687** device
688** cnt - number of bytes/registers to be written
689**
690** Returns: status:
691** MT_OK - No errors
692** MT_COMM_ERR - Serial bus communications error
693** user-defined
694**
695** Notes: This is a callback function that is called from the
696** the tuning algorithm. You MUST provide code for this
697** function to read data using the tuner's 2-wire serial
698** bus.
699**
700** The hUserData parameter is a user-specific argument.
701** If additional arguments are needed for the user's
702** serial bus read/write functions, this argument can be
703** used to supply the necessary information.
704** The hUserData parameter is initialized in the tuner's Open
705** function.
706**
707** Revision History:
708**
709** SCR Date Author Description
710** -------------------------------------------------------------------------
711** N/A 03-25-2004 DAD Original
712**
713*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300714static u32 MT2063_ReadSub(void *hUserData,
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300715 u32 addr,
716 u8 subAddress, u8 * pData, u32 cnt)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300717{
718 /*
719 ** ToDo: Add code here to implement a serial-bus read
720 ** operation to the MTxxxx tuner. If successful,
721 ** return MT_OK.
722 */
723/* return status; */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300724 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300725 struct dvb_frontend *fe = hUserData;
726 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300727 u32 i = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300728 fe->ops.i2c_gate_ctrl(fe, 1); //I2C bypass drxk3926 close i2c bridge
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300729
730 for (i = 0; i < cnt; i++) {
731 if (mt2063_read_regs(state, subAddress + i, pData + i, 1) < 0) {
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300732 status = -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300733 break;
734 }
735 }
736
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300737 fe->ops.i2c_gate_ctrl(fe, 0); //I2C bypass drxk3926 close i2c bridge
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300738
739 return (status);
740}
741
742/*****************************************************************************
743**
744** Name: MT_Sleep
745**
746** Description: Delay execution for "nMinDelayTime" milliseconds
747**
748** Parameters: hUserData - User-specific I/O parameter that was
749** passed to tuner's Open function.
750** nMinDelayTime - Delay time in milliseconds
751**
752** Returns: None.
753**
754** Notes: This is a callback function that is called from the
755** the tuning algorithm. You MUST provide code that
756** blocks execution for the specified period of time.
757**
758** Revision History:
759**
760** SCR Date Author Description
761** -------------------------------------------------------------------------
762** N/A 03-25-2004 DAD Original
763**
764*****************************************************************************/
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300765static int MT2063_Sleep(struct dvb_frontend *fe)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300766{
767 /*
768 ** ToDo: Add code here to implement a OS blocking
769 ** for a period of "nMinDelayTime" milliseconds.
770 */
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300771 msleep(10);
772
773 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300774}
775
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300776//end of mt2063_userdef.c
777//=================================================================
778//#################################################################
779//=================================================================
780
781//context of mt2063_spuravoid.c <Henry> ======================================
782//#################################################################
783//=================================================================
784
785/*****************************************************************************
786**
787** Name: mt_spuravoid.c
788**
789** Description: Microtune spur avoidance software module.
790** Supports Microtune tuner drivers.
791**
792** CVS ID: $Id: mt_spuravoid.c,v 1.3 2008/06/26 15:39:52 software Exp $
793** CVS Source: $Source: /export/home/cvsroot/software/tuners/MT2063/mt_spuravoid.c,v $
794**
795** Revision History:
796**
797** SCR Date Author Description
798** -------------------------------------------------------------------------
799** 082 03-25-2005 JWS Original multi-tuner support - requires
800** MTxxxx_CNT declarations
801** 096 04-06-2005 DAD Ver 1.11: Fix divide by 0 error if maxH==0.
802** 094 04-06-2005 JWS Ver 1.11 Added uceil and ufloor to get rid
803** of compiler warnings
804** N/A 04-07-2005 DAD Ver 1.13: Merged single- and multi-tuner spur
805** avoidance into a single module.
806** 103 01-31-2005 DAD Ver 1.14: In MT_AddExclZone(), if the range
807** (f_min, f_max) < 0, ignore the entry.
808** 115 03-23-2007 DAD Fix declaration of spur due to truncation
809** errors.
810** 117 03-29-2007 RSK Ver 1.15: Re-wrote to match search order from
811** tuner DLL.
812** 137 06-18-2007 DAD Ver 1.16: Fix possible divide-by-0 error for
813** multi-tuners that have
814** (delta IF1) > (f_out-f_outbw/2).
815** 147 07-27-2007 RSK Ver 1.17: Corrected calculation (-) to (+)
816** Added logic to force f_Center within 1/2 f_Step.
817** 177 S 02-26-2008 RSK Ver 1.18: Corrected calculation using LO1 > MAX/2
818** Type casts added to preserve correct sign.
819** N/A I 06-17-2008 RSK Ver 1.19: Refactoring avoidance of DECT
820** frequencies into MT_ResetExclZones().
821** N/A I 06-20-2008 RSK Ver 1.21: New VERSION number for ver checking.
822**
823*****************************************************************************/
824
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300825/* Version of this module */
826#define MT2063_SPUR_VERSION 10201 /* Version 01.21 */
827
828/* Implement ceiling, floor functions. */
829#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0))
830#define uceil(n, d) ((n)/(d) + ((n)%(d) != 0))
831#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d))
832#define ufloor(n, d) ((n)/(d))
833
834struct MT2063_FIFZone_t {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300835 s32 min_;
836 s32 max_;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300837};
838
839#if MT2063_TUNER_CNT > 1
840static struct MT2063_AvoidSpursData_t *TunerList[MT2063_TUNER_CNT];
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300841static u32 TunerCount = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300842#endif
843
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300844static u32 MT2063_RegisterTuner(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300845{
846#if MT2063_TUNER_CNT == 1
847 pAS_Info->nAS_Algorithm = 1;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300848 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300849#else
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300850 u32 index;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300851
852 pAS_Info->nAS_Algorithm = 2;
853
854 /*
855 ** Check to see if tuner is already registered
856 */
857 for (index = 0; index < TunerCount; index++) {
858 if (TunerList[index] == pAS_Info) {
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300859 return 0; /* Already here - no problem */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300860 }
861 }
862
863 /*
864 ** Add tuner to list - if there is room.
865 */
866 if (TunerCount < MT2063_TUNER_CNT) {
867 TunerList[TunerCount] = pAS_Info;
868 TunerCount++;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300869 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300870 } else
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300871 return -ENODEV;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300872#endif
873}
874
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300875static void MT2063_UnRegisterTuner(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300876{
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300877#if MT2063_TUNER_CNT > 1
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300878 u32 index;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300879
880 for (index = 0; index < TunerCount; index++) {
881 if (TunerList[index] == pAS_Info) {
882 TunerList[index] = TunerList[--TunerCount];
883 }
884 }
885#endif
886}
887
888/*
889** Reset all exclusion zones.
890** Add zones to protect the PLL FracN regions near zero
891**
892** N/A I 06-17-2008 RSK Ver 1.19: Refactoring avoidance of DECT
893** frequencies into MT_ResetExclZones().
894*/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300895static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300896{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300897 u32 center;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300898#if MT2063_TUNER_CNT > 1
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300899 u32 index;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300900 struct MT2063_AvoidSpursData_t *adj;
901#endif
902
903 pAS_Info->nZones = 0; /* this clears the used list */
904 pAS_Info->usedZones = NULL; /* reset ptr */
905 pAS_Info->freeZones = NULL; /* reset ptr */
906
907 center =
908 pAS_Info->f_ref *
909 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 +
910 pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in;
911 while (center <
912 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
913 pAS_Info->f_LO1_FracN_Avoid) {
914 /* Exclude LO1 FracN */
915 MT2063_AddExclZone(pAS_Info,
916 center - pAS_Info->f_LO1_FracN_Avoid,
917 center - 1);
918 MT2063_AddExclZone(pAS_Info, center + 1,
919 center + pAS_Info->f_LO1_FracN_Avoid);
920 center += pAS_Info->f_ref;
921 }
922
923 center =
924 pAS_Info->f_ref *
925 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 -
926 pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out;
927 while (center <
928 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
929 pAS_Info->f_LO2_FracN_Avoid) {
930 /* Exclude LO2 FracN */
931 MT2063_AddExclZone(pAS_Info,
932 center - pAS_Info->f_LO2_FracN_Avoid,
933 center - 1);
934 MT2063_AddExclZone(pAS_Info, center + 1,
935 center + pAS_Info->f_LO2_FracN_Avoid);
936 center += pAS_Info->f_ref;
937 }
938
939 if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
940 /* Exclude LO1 values that conflict with DECT channels */
941 MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */
942 MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */
943 MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */
944 MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */
945 MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */
946 }
947
948 if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
949 MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */
950 MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */
951 MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */
952 MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */
953 MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */
954 MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */
955 MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */
956 MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */
957 MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */
958 MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */
959 }
960#if MT2063_TUNER_CNT > 1
961 /*
962 ** Iterate through all adjacent tuners and exclude frequencies related to them
963 */
964 for (index = 0; index < TunerCount; ++index) {
965 adj = TunerList[index];
966 if (pAS_Info == adj) /* skip over our own data, don't process it */
967 continue;
968
969 /*
970 ** Add 1st IF exclusion zone covering adjacent tuner's LO2
971 ** at "adjfLO2 + f_out" +/- m_MinLOSpacing
972 */
973 if (adj->f_LO2 != 0)
974 MT2063_AddExclZone(pAS_Info,
975 (adj->f_LO2 + pAS_Info->f_out) -
976 pAS_Info->f_min_LO_Separation,
977 (adj->f_LO2 + pAS_Info->f_out) +
978 pAS_Info->f_min_LO_Separation);
979
980 /*
981 ** Add 1st IF exclusion zone covering adjacent tuner's LO1
982 ** at "adjfLO1 - f_in" +/- m_MinLOSpacing
983 */
984 if (adj->f_LO1 != 0)
985 MT2063_AddExclZone(pAS_Info,
986 (adj->f_LO1 - pAS_Info->f_in) -
987 pAS_Info->f_min_LO_Separation,
988 (adj->f_LO1 - pAS_Info->f_in) +
989 pAS_Info->f_min_LO_Separation);
990 }
991#endif
992}
993
994static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t
995 *pAS_Info,
996 struct MT2063_ExclZone_t *pPrevNode)
997{
998 struct MT2063_ExclZone_t *pNode;
999 /* Check for a node in the free list */
1000 if (pAS_Info->freeZones != NULL) {
1001 /* Use one from the free list */
1002 pNode = pAS_Info->freeZones;
1003 pAS_Info->freeZones = pNode->next_;
1004 } else {
1005 /* Grab a node from the array */
1006 pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones];
1007 }
1008
1009 if (pPrevNode != NULL) {
1010 pNode->next_ = pPrevNode->next_;
1011 pPrevNode->next_ = pNode;
1012 } else { /* insert at the beginning of the list */
1013
1014 pNode->next_ = pAS_Info->usedZones;
1015 pAS_Info->usedZones = pNode;
1016 }
1017
1018 pAS_Info->nZones++;
1019 return pNode;
1020}
1021
1022static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t
1023 *pAS_Info,
1024 struct MT2063_ExclZone_t *pPrevNode,
1025 struct MT2063_ExclZone_t
1026 *pNodeToRemove)
1027{
1028 struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_;
1029
1030 /* Make previous node point to the subsequent node */
1031 if (pPrevNode != NULL)
1032 pPrevNode->next_ = pNext;
1033
1034 /* Add pNodeToRemove to the beginning of the freeZones */
1035 pNodeToRemove->next_ = pAS_Info->freeZones;
1036 pAS_Info->freeZones = pNodeToRemove;
1037
1038 /* Decrement node count */
1039 pAS_Info->nZones--;
1040
1041 return pNext;
1042}
1043
1044/*****************************************************************************
1045**
1046** Name: MT_AddExclZone
1047**
1048** Description: Add (and merge) an exclusion zone into the list.
1049** If the range (f_min, f_max) is totally outside the
1050** 1st IF BW, ignore the entry.
1051** If the range (f_min, f_max) is negative, ignore the entry.
1052**
1053** Revision History:
1054**
1055** SCR Date Author Description
1056** -------------------------------------------------------------------------
1057** 103 01-31-2005 DAD Ver 1.14: In MT_AddExclZone(), if the range
1058** (f_min, f_max) < 0, ignore the entry.
1059**
1060*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001061static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001062 u32 f_min, u32 f_max)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001063{
1064 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
1065 struct MT2063_ExclZone_t *pPrev = NULL;
1066 struct MT2063_ExclZone_t *pNext = NULL;
1067
1068 /* Check to see if this overlaps the 1st IF filter */
1069 if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2)))
1070 && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2)))
1071 && (f_min < f_max)) {
1072 /*
1073 ** 1 2 3 4 5 6
1074 **
1075 ** New entry: |---| |--| |--| |-| |---| |--|
1076 ** or or or or or
1077 ** Existing: |--| |--| |--| |---| |-| |--|
1078 */
1079
1080 /* Check for our place in the list */
1081 while ((pNode != NULL) && (pNode->max_ < f_min)) {
1082 pPrev = pNode;
1083 pNode = pNode->next_;
1084 }
1085
1086 if ((pNode != NULL) && (pNode->min_ < f_max)) {
1087 /* Combine me with pNode */
1088 if (f_min < pNode->min_)
1089 pNode->min_ = f_min;
1090 if (f_max > pNode->max_)
1091 pNode->max_ = f_max;
1092 } else {
1093 pNode = InsertNode(pAS_Info, pPrev);
1094 pNode->min_ = f_min;
1095 pNode->max_ = f_max;
1096 }
1097
1098 /* Look for merging possibilities */
1099 pNext = pNode->next_;
1100 while ((pNext != NULL) && (pNext->min_ < pNode->max_)) {
1101 if (pNext->max_ > pNode->max_)
1102 pNode->max_ = pNext->max_;
1103 pNext = RemoveNode(pAS_Info, pNode, pNext); /* Remove pNext, return ptr to pNext->next */
1104 }
1105 }
1106}
1107
1108/*****************************************************************************
1109**
1110** Name: MT_ChooseFirstIF
1111**
1112** Description: Choose the best available 1st IF
1113** If f_Desired is not excluded, choose that first.
1114** Otherwise, return the value closest to f_Center that is
1115** not excluded
1116**
1117** Revision History:
1118**
1119** SCR Date Author Description
1120** -------------------------------------------------------------------------
1121** 117 03-29-2007 RSK Ver 1.15: Re-wrote to match search order from
1122** tuner DLL.
1123** 147 07-27-2007 RSK Ver 1.17: Corrected calculation (-) to (+)
1124** Added logic to force f_Center within 1/2 f_Step.
1125**
1126*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001127static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001128{
1129 /*
1130 ** Update "f_Desired" to be the nearest "combinational-multiple" of "f_LO1_Step".
1131 ** The resulting number, F_LO1 must be a multiple of f_LO1_Step. And F_LO1 is the arithmetic sum
1132 ** of f_in + f_Center. Neither f_in, nor f_Center must be a multiple of f_LO1_Step.
1133 ** However, the sum must be.
1134 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001135 const u32 f_Desired =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001136 pAS_Info->f_LO1_Step *
1137 ((pAS_Info->f_if1_Request + pAS_Info->f_in +
1138 pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) -
1139 pAS_Info->f_in;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001140 const u32 f_Step =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001141 (pAS_Info->f_LO1_Step >
1142 pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info->
1143 f_LO2_Step;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001144 u32 f_Center;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001145
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001146 s32 i;
1147 s32 j = 0;
1148 u32 bDesiredExcluded = 0;
1149 u32 bZeroExcluded = 0;
1150 s32 tmpMin, tmpMax;
1151 s32 bestDiff;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001152 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
1153 struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES];
1154
1155 if (pAS_Info->nZones == 0)
1156 return f_Desired;
1157
1158 /* f_Center needs to be an integer multiple of f_Step away from f_Desired */
1159 if (pAS_Info->f_if1_Center > f_Desired)
1160 f_Center =
1161 f_Desired +
1162 f_Step *
1163 ((pAS_Info->f_if1_Center - f_Desired +
1164 f_Step / 2) / f_Step);
1165 else
1166 f_Center =
1167 f_Desired -
1168 f_Step *
1169 ((f_Desired - pAS_Info->f_if1_Center +
1170 f_Step / 2) / f_Step);
1171
1172 //assert;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001173 //if (!abs((s32) f_Center - (s32) pAS_Info->f_if1_Center) <= (s32) (f_Step/2))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001174 // return 0;
1175
1176 /* Take MT_ExclZones, center around f_Center and change the resolution to f_Step */
1177 while (pNode != NULL) {
1178 /* floor function */
1179 tmpMin =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001180 floor((s32) (pNode->min_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001181
1182 /* ceil function */
1183 tmpMax =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001184 ceil((s32) (pNode->max_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001185
1186 if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired))
1187 bDesiredExcluded = 1;
1188
1189 if ((tmpMin < 0) && (tmpMax > 0))
1190 bZeroExcluded = 1;
1191
1192 /* See if this zone overlaps the previous */
1193 if ((j > 0) && (tmpMin < zones[j - 1].max_))
1194 zones[j - 1].max_ = tmpMax;
1195 else {
1196 /* Add new zone */
1197 //assert(j<MT2063_MAX_ZONES);
1198 //if (j>=MT2063_MAX_ZONES)
1199 //break;
1200
1201 zones[j].min_ = tmpMin;
1202 zones[j].max_ = tmpMax;
1203 j++;
1204 }
1205 pNode = pNode->next_;
1206 }
1207
1208 /*
1209 ** If the desired is okay, return with it
1210 */
1211 if (bDesiredExcluded == 0)
1212 return f_Desired;
1213
1214 /*
1215 ** If the desired is excluded and the center is okay, return with it
1216 */
1217 if (bZeroExcluded == 0)
1218 return f_Center;
1219
1220 /* Find the value closest to 0 (f_Center) */
1221 bestDiff = zones[0].min_;
1222 for (i = 0; i < j; i++) {
1223 if (abs(zones[i].min_) < abs(bestDiff))
1224 bestDiff = zones[i].min_;
1225 if (abs(zones[i].max_) < abs(bestDiff))
1226 bestDiff = zones[i].max_;
1227 }
1228
1229 if (bestDiff < 0)
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001230 return f_Center - ((u32) (-bestDiff) * f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001231
1232 return f_Center + (bestDiff * f_Step);
1233}
1234
1235/****************************************************************************
1236**
1237** Name: gcd
1238**
1239** Description: Uses Euclid's algorithm
1240**
1241** Parameters: u, v - unsigned values whose GCD is desired.
1242**
1243** Global: None
1244**
1245** Returns: greatest common divisor of u and v, if either value
1246** is 0, the other value is returned as the result.
1247**
1248** Dependencies: None.
1249**
1250** Revision History:
1251**
1252** SCR Date Author Description
1253** -------------------------------------------------------------------------
1254** N/A 06-01-2004 JWS Original
1255** N/A 08-03-2004 DAD Changed to Euclid's since it can handle
1256** unsigned numbers.
1257**
1258****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001259static u32 MT2063_gcd(u32 u, u32 v)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001260{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001261 u32 r;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001262
1263 while (v != 0) {
1264 r = u % v;
1265 u = v;
1266 v = r;
1267 }
1268
1269 return u;
1270}
1271
1272/****************************************************************************
1273**
1274** Name: umax
1275**
1276** Description: Implements a simple maximum function for unsigned numbers.
1277** Implemented as a function rather than a macro to avoid
1278** multiple evaluation of the calling parameters.
1279**
1280** Parameters: a, b - Values to be compared
1281**
1282** Global: None
1283**
1284** Returns: larger of the input values.
1285**
1286** Dependencies: None.
1287**
1288** Revision History:
1289**
1290** SCR Date Author Description
1291** -------------------------------------------------------------------------
1292** N/A 06-02-2004 JWS Original
1293**
1294****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001295static u32 MT2063_umax(u32 a, u32 b)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001296{
1297 return (a >= b) ? a : b;
1298}
1299
1300#if MT2063_TUNER_CNT > 1
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001301static s32 RoundAwayFromZero(s32 n, s32 d)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001302{
1303 return (n < 0) ? floor(n, d) : ceil(n, d);
1304}
1305
1306/****************************************************************************
1307**
1308** Name: IsSpurInAdjTunerBand
1309**
1310** Description: Checks to see if a spur will be present within the IF's
1311** bandwidth or near the zero IF.
1312** (fIFOut +/- fIFBW/2, -fIFOut +/- fIFBW/2)
1313** and
1314** (0 +/- fZIFBW/2)
1315**
1316** ma mb me mf mc md
1317** <--+-+-+-----------------+-+-+-----------------+-+-+-->
1318** | ^ 0 ^ |
1319** ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^
1320** a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2
1321**
1322** Note that some equations are doubled to prevent round-off
1323** problems when calculating fIFBW/2
1324**
1325** The spur frequencies are computed as:
1326**
1327** fSpur = n * f1 - m * f2 - fOffset
1328**
1329** Parameters: f1 - The 1st local oscillator (LO) frequency
1330** of the tuner whose output we are examining
1331** f2 - The 1st local oscillator (LO) frequency
1332** of the adjacent tuner
1333** fOffset - The 2nd local oscillator of the tuner whose
1334** output we are examining
1335** fIFOut - Output IF center frequency
1336** fIFBW - Output IF Bandwidth
1337** nMaxH - max # of LO harmonics to search
1338** fp - If spur, positive distance to spur-free band edge (returned)
1339** fm - If spur, negative distance to spur-free band edge (returned)
1340**
1341** Returns: 1 if an LO spur would be present, otherwise 0.
1342**
1343** Dependencies: None.
1344**
1345** Revision History:
1346**
1347** SCR Date Author Description
1348** -------------------------------------------------------------------------
1349** N/A 01-21-2005 JWS Original, adapted from MT_DoubleConversion.
1350** 115 03-23-2007 DAD Fix declaration of spur due to truncation
1351** errors.
1352** 137 06-18-2007 DAD Ver 1.16: Fix possible divide-by-0 error for
1353** multi-tuners that have
1354** (delta IF1) > (f_out-f_outbw/2).
1355** 177 S 02-26-2008 RSK Ver 1.18: Corrected calculation using LO1 > MAX/2
1356** Type casts added to preserve correct sign.
1357**
1358****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001359static u32 IsSpurInAdjTunerBand(u32 bIsMyOutput,
1360 u32 f1,
1361 u32 f2,
1362 u32 fOffset,
1363 u32 fIFOut,
1364 u32 fIFBW,
1365 u32 fZIFBW,
1366 u32 nMaxH, u32 * fp, u32 * fm)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001367{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001368 u32 bSpurFound = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001369
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001370 const u32 fHalf_IFBW = fIFBW / 2;
1371 const u32 fHalf_ZIFBW = fZIFBW / 2;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001372
1373 /* Calculate a scale factor for all frequencies, so that our
1374 calculations all stay within 31 bits */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001375 const u32 f_Scale =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001376 ((f1 +
1377 (fOffset + fIFOut +
1378 fHalf_IFBW) / nMaxH) / (MAX_UDATA / 2 / nMaxH)) + 1;
1379
1380 /*
1381 ** After this scaling, _f1, _f2, and _f3 are guaranteed to fit into
1382 ** signed data types (smaller than MAX_UDATA/2)
1383 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001384 const s32 _f1 = (s32) (f1 / f_Scale);
1385 const s32 _f2 = (s32) (f2 / f_Scale);
1386 const s32 _f3 = (s32) (fOffset / f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001387
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001388 const s32 c = (s32) (fIFOut - fHalf_IFBW) / (s32) f_Scale;
1389 const s32 d = (s32) ((fIFOut + fHalf_IFBW) / f_Scale);
1390 const s32 f = (s32) (fHalf_ZIFBW / f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001391
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001392 s32 ma, mb, mc, md, me, mf;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001393
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001394 s32 fp_ = 0;
1395 s32 fm_ = 0;
1396 s32 n;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001397
1398 /*
1399 ** If the other tuner does not have an LO frequency defined,
1400 ** assume that we cannot interfere with it
1401 */
1402 if (f2 == 0)
1403 return 0;
1404
1405 /* Check out all multiples of f1 from -nMaxH to +nMaxH */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001406 for (n = -(s32) nMaxH; n <= (s32) nMaxH; ++n) {
1407 const s32 nf1 = n * _f1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001408 md = (_f3 + d - nf1) / _f2;
1409
1410 /* If # f2 harmonics > nMaxH, then no spurs present */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001411 if (md <= -(s32) nMaxH)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001412 break;
1413
1414 ma = (_f3 - d - nf1) / _f2;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001415 if ((ma == md) || (ma >= (s32) (nMaxH)))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001416 continue;
1417
1418 mc = (_f3 + c - nf1) / _f2;
1419 if (mc != md) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001420 const s32 m = (n < 0) ? md : mc;
1421 const s32 fspur = (nf1 + m * _f2 - _f3);
1422 const s32 den = (bIsMyOutput ? n - 1 : n);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001423 if (den == 0) {
1424 fp_ = (d - fspur) * f_Scale;
1425 fm_ = (fspur - c) * f_Scale;
1426 } else {
1427 fp_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001428 (s32) RoundAwayFromZero((d - fspur) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001429 f_Scale, den);
1430 fm_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001431 (s32) RoundAwayFromZero((fspur - c) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001432 f_Scale, den);
1433 }
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001434 if (((u32) abs(fm_) >= f_Scale)
1435 && ((u32) abs(fp_) >= f_Scale)) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001436 bSpurFound = 1;
1437 break;
1438 }
1439 }
1440
1441 /* Location of Zero-IF-spur to be checked */
1442 mf = (_f3 + f - nf1) / _f2;
1443 me = (_f3 - f - nf1) / _f2;
1444 if (me != mf) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001445 const s32 m = (n < 0) ? mf : me;
1446 const s32 fspur = (nf1 + m * _f2 - _f3);
1447 const s32 den = (bIsMyOutput ? n - 1 : n);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001448 if (den == 0) {
1449 fp_ = (d - fspur) * f_Scale;
1450 fm_ = (fspur - c) * f_Scale;
1451 } else {
1452 fp_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001453 (s32) RoundAwayFromZero((f - fspur) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001454 f_Scale, den);
1455 fm_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001456 (s32) RoundAwayFromZero((fspur + f) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001457 f_Scale, den);
1458 }
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001459 if (((u32) abs(fm_) >= f_Scale)
1460 && ((u32) abs(fp_) >= f_Scale)) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001461 bSpurFound = 1;
1462 break;
1463 }
1464 }
1465
1466 mb = (_f3 - c - nf1) / _f2;
1467 if (ma != mb) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001468 const s32 m = (n < 0) ? mb : ma;
1469 const s32 fspur = (nf1 + m * _f2 - _f3);
1470 const s32 den = (bIsMyOutput ? n - 1 : n);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001471 if (den == 0) {
1472 fp_ = (d - fspur) * f_Scale;
1473 fm_ = (fspur - c) * f_Scale;
1474 } else {
1475 fp_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001476 (s32) RoundAwayFromZero((-c - fspur) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001477 f_Scale, den);
1478 fm_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001479 (s32) RoundAwayFromZero((fspur + d) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001480 f_Scale, den);
1481 }
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001482 if (((u32) abs(fm_) >= f_Scale)
1483 && ((u32) abs(fp_) >= f_Scale)) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001484 bSpurFound = 1;
1485 break;
1486 }
1487 }
1488 }
1489
1490 /*
1491 ** Verify that fm & fp are both positive
1492 ** Add one to ensure next 1st IF choice is not right on the edge
1493 */
1494 if (fp_ < 0) {
1495 *fp = -fm_ + 1;
1496 *fm = -fp_ + 1;
1497 } else if (fp_ > 0) {
1498 *fp = fp_ + 1;
1499 *fm = fm_ + 1;
1500 } else {
1501 *fp = 1;
1502 *fm = abs(fm_) + 1;
1503 }
1504
1505 return bSpurFound;
1506}
1507#endif
1508
1509/****************************************************************************
1510**
1511** Name: IsSpurInBand
1512**
1513** Description: Checks to see if a spur will be present within the IF's
1514** bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW)
1515**
1516** ma mb mc md
1517** <--+-+-+-------------------+-------------------+-+-+-->
1518** | ^ 0 ^ |
1519** ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^
1520** a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2
1521**
1522** Note that some equations are doubled to prevent round-off
1523** problems when calculating fIFBW/2
1524**
1525** Parameters: pAS_Info - Avoid Spurs information block
1526** fm - If spur, amount f_IF1 has to move negative
1527** fp - If spur, amount f_IF1 has to move positive
1528**
1529** Global: None
1530**
1531** Returns: 1 if an LO spur would be present, otherwise 0.
1532**
1533** Dependencies: None.
1534**
1535** Revision History:
1536**
1537** SCR Date Author Description
1538** -------------------------------------------------------------------------
1539** N/A 11-28-2002 DAD Implemented algorithm from applied patent
1540**
1541****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001542static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info,
1543 u32 * fm, u32 * fp)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001544{
1545 /*
1546 ** Calculate LO frequency settings.
1547 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001548 u32 n, n0;
1549 const u32 f_LO1 = pAS_Info->f_LO1;
1550 const u32 f_LO2 = pAS_Info->f_LO2;
1551 const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2;
1552 const u32 c = d - pAS_Info->f_out_bw;
1553 const u32 f = pAS_Info->f_zif_bw / 2;
1554 const u32 f_Scale = (f_LO1 / (MAX_UDATA / 2 / pAS_Info->maxH1)) + 1;
1555 s32 f_nsLO1, f_nsLO2;
1556 s32 f_Spur;
1557 u32 ma, mb, mc, md, me, mf;
1558 u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001559#if MT2063_TUNER_CNT > 1
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001560 u32 index;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001561
1562 struct MT2063_AvoidSpursData_t *adj;
1563#endif
1564 *fm = 0;
1565
1566 /*
1567 ** For each edge (d, c & f), calculate a scale, based on the gcd
1568 ** of f_LO1, f_LO2 and the edge value. Use the larger of this
1569 ** gcd-based scale factor or f_Scale.
1570 */
1571 lo_gcd = MT2063_gcd(f_LO1, f_LO2);
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001572 gd_Scale = MT2063_umax((u32) MT2063_gcd(lo_gcd, d), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001573 hgds = gd_Scale / 2;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001574 gc_Scale = MT2063_umax((u32) MT2063_gcd(lo_gcd, c), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001575 hgcs = gc_Scale / 2;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001576 gf_Scale = MT2063_umax((u32) MT2063_gcd(lo_gcd, f), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001577 hgfs = gf_Scale / 2;
1578
1579 n0 = uceil(f_LO2 - d, f_LO1 - f_LO2);
1580
1581 /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */
1582 for (n = n0; n <= pAS_Info->maxH1; ++n) {
1583 md = (n * ((f_LO1 + hgds) / gd_Scale) -
1584 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
1585
1586 /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */
1587 if (md >= pAS_Info->maxH1)
1588 break;
1589
1590 ma = (n * ((f_LO1 + hgds) / gd_Scale) +
1591 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
1592
1593 /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */
1594 if (md == ma)
1595 continue;
1596
1597 mc = (n * ((f_LO1 + hgcs) / gc_Scale) -
1598 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
1599 if (mc != md) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001600 f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale));
1601 f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale));
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001602 f_Spur =
1603 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
1604 n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale);
1605
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001606 *fp = ((f_Spur - (s32) c) / (mc - n)) + 1;
1607 *fm = (((s32) d - f_Spur) / (mc - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001608 return 1;
1609 }
1610
1611 /* Location of Zero-IF-spur to be checked */
1612 me = (n * ((f_LO1 + hgfs) / gf_Scale) +
1613 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
1614 mf = (n * ((f_LO1 + hgfs) / gf_Scale) -
1615 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
1616 if (me != mf) {
1617 f_nsLO1 = n * (f_LO1 / gf_Scale);
1618 f_nsLO2 = me * (f_LO2 / gf_Scale);
1619 f_Spur =
1620 (gf_Scale * (f_nsLO1 - f_nsLO2)) +
1621 n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale);
1622
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001623 *fp = ((f_Spur + (s32) f) / (me - n)) + 1;
1624 *fm = (((s32) f - f_Spur) / (me - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001625 return 1;
1626 }
1627
1628 mb = (n * ((f_LO1 + hgcs) / gc_Scale) +
1629 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
1630 if (ma != mb) {
1631 f_nsLO1 = n * (f_LO1 / gc_Scale);
1632 f_nsLO2 = ma * (f_LO2 / gc_Scale);
1633 f_Spur =
1634 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
1635 n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale);
1636
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001637 *fp = (((s32) d + f_Spur) / (ma - n)) + 1;
1638 *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001639 return 1;
1640 }
1641 }
1642
1643#if MT2063_TUNER_CNT > 1
1644 /* If no spur found, see if there are more tuners on the same board */
1645 for (index = 0; index < TunerCount; ++index) {
1646 adj = TunerList[index];
1647 if (pAS_Info == adj) /* skip over our own data, don't process it */
1648 continue;
1649
1650 /* Look for LO-related spurs from the adjacent tuner generated into my IF output */
1651 if (IsSpurInAdjTunerBand(1, /* check my IF output */
1652 pAS_Info->f_LO1, /* my fLO1 */
1653 adj->f_LO1, /* the other tuner's fLO1 */
1654 pAS_Info->f_LO2, /* my fLO2 */
1655 pAS_Info->f_out, /* my fOut */
1656 pAS_Info->f_out_bw, /* my output IF bandwidth */
1657 pAS_Info->f_zif_bw, /* my Zero-IF bandwidth */
1658 pAS_Info->maxH2, fp, /* minimum amount to move LO's positive */
1659 fm)) /* miminum amount to move LO's negative */
1660 return 1;
1661 /* Look for LO-related spurs from my tuner generated into the adjacent tuner's IF output */
1662 if (IsSpurInAdjTunerBand(0, /* check his IF output */
1663 pAS_Info->f_LO1, /* my fLO1 */
1664 adj->f_LO1, /* the other tuner's fLO1 */
1665 adj->f_LO2, /* the other tuner's fLO2 */
1666 adj->f_out, /* the other tuner's fOut */
1667 adj->f_out_bw, /* the other tuner's output IF bandwidth */
1668 pAS_Info->f_zif_bw, /* the other tuner's Zero-IF bandwidth */
1669 adj->maxH2, fp, /* minimum amount to move LO's positive */
1670 fm)) /* miminum amount to move LO's negative */
1671 return 1;
1672 }
1673#endif
1674 /* No spurs found */
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001675 return 0;
1676}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001677
1678/*****************************************************************************
1679**
1680** Name: MT_AvoidSpurs
1681**
1682** Description: Main entry point to avoid spurs.
1683** Checks for existing spurs in present LO1, LO2 freqs
1684** and if present, chooses spur-free LO1, LO2 combination
1685** that tunes the same input/output frequencies.
1686**
1687** Revision History:
1688**
1689** SCR Date Author Description
1690** -------------------------------------------------------------------------
1691** 096 04-06-2005 DAD Ver 1.11: Fix divide by 0 error if maxH==0.
1692**
1693*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001694static u32 MT2063_AvoidSpurs(void *h, struct MT2063_AvoidSpursData_t * pAS_Info)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001695{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001696 u32 status = 0;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001697 u32 fm, fp; /* restricted range on LO's */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001698 pAS_Info->bSpurAvoided = 0;
1699 pAS_Info->nSpursFound = 0;
1700
1701 if (pAS_Info->maxH1 == 0)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001702 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001703
1704 /*
1705 ** Avoid LO Generated Spurs
1706 **
1707 ** Make sure that have no LO-related spurs within the IF output
1708 ** bandwidth.
1709 **
1710 ** If there is an LO spur in this band, start at the current IF1 frequency
1711 ** and work out until we find a spur-free frequency or run up against the
1712 ** 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they
1713 ** will be unchanged if a spur-free setting is not found.
1714 */
1715 pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
1716 if (pAS_Info->bSpurPresent) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001717 u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */
1718 u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */
1719 u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */
1720 u32 delta_IF1;
1721 u32 new_IF1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001722
1723 /*
1724 ** Spur was found, attempt to find a spur-free 1st IF
1725 */
1726 do {
1727 pAS_Info->nSpursFound++;
1728
1729 /* Raise f_IF1_upper, if needed */
1730 MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp);
1731
1732 /* Choose next IF1 that is closest to f_IF1_CENTER */
1733 new_IF1 = MT2063_ChooseFirstIF(pAS_Info);
1734
1735 if (new_IF1 > zfIF1) {
1736 pAS_Info->f_LO1 += (new_IF1 - zfIF1);
1737 pAS_Info->f_LO2 += (new_IF1 - zfIF1);
1738 } else {
1739 pAS_Info->f_LO1 -= (zfIF1 - new_IF1);
1740 pAS_Info->f_LO2 -= (zfIF1 - new_IF1);
1741 }
1742 zfIF1 = new_IF1;
1743
1744 if (zfIF1 > pAS_Info->f_if1_Center)
1745 delta_IF1 = zfIF1 - pAS_Info->f_if1_Center;
1746 else
1747 delta_IF1 = pAS_Info->f_if1_Center - zfIF1;
1748 }
1749 /*
1750 ** Continue while the new 1st IF is still within the 1st IF bandwidth
1751 ** and there is a spur in the band (again)
1752 */
1753 while ((2 * delta_IF1 + pAS_Info->f_out_bw <=
1754 pAS_Info->f_if1_bw)
1755 && (pAS_Info->bSpurPresent =
1756 IsSpurInBand(pAS_Info, &fm, &fp)));
1757
1758 /*
1759 ** Use the LO-spur free values found. If the search went all the way to
1760 ** the 1st IF band edge and always found spurs, just leave the original
1761 ** choice. It's as "good" as any other.
1762 */
1763 if (pAS_Info->bSpurPresent == 1) {
1764 status |= MT2063_SPUR_PRESENT_ERR;
1765 pAS_Info->f_LO1 = zfLO1;
1766 pAS_Info->f_LO2 = zfLO2;
1767 } else
1768 pAS_Info->bSpurAvoided = 1;
1769 }
1770
1771 status |=
1772 ((pAS_Info->
1773 nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK);
1774
1775 return (status);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001776}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001777
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001778//end of mt2063_spuravoid.c
1779//=================================================================
1780//#################################################################
1781//=================================================================
1782
1783/*
1784** The expected version of MT_AvoidSpursData_t
1785** If the version is different, an updated file is needed from Microtune
1786*/
1787/* Expecting version 1.21 of the Spur Avoidance API */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001788
1789typedef enum {
1790 MT2063_SET_ATTEN,
1791 MT2063_INCR_ATTEN,
1792 MT2063_DECR_ATTEN
1793} MT2063_ATTEN_CNTL_MODE;
1794
1795//#define TUNER_MT2063_OPTIMIZATION
1796/*
1797** Constants used by the tuning algorithm
1798*/
1799#define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */
1800#define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */
1801#define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */
1802#define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */
1803#define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */
1804#define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */
1805#define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */
1806#define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */
1807#define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */
1808#define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */
1809#define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */
1810#define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */
1811#define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */
1812#define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */
1813#define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */
1814#define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */
1815#define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */
1816#define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */
1817
1818/*
1819** Define the supported Part/Rev codes for the MT2063
1820*/
1821#define MT2063_B0 (0x9B)
1822#define MT2063_B1 (0x9C)
1823#define MT2063_B2 (0x9D)
1824#define MT2063_B3 (0x9E)
1825
1826/*
1827** The number of Tuner Registers
1828*/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001829static const u32 MT2063_Num_Registers = MT2063_REG_END_REGS;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001830
1831#define USE_GLOBAL_TUNER 0
1832
Mauro Carvalho Chehaba0813ea2011-07-20 21:19:08 -03001833static u32 nMT2063MaxTuners = 1;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001834static u32 nMT2063OpenTuners = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001835
1836/*
1837** Constants for setting receiver modes.
1838** (6 modes defined at this time, enumerated by MT2063_RCVR_MODES)
1839** (DNC1GC & DNC2GC are the values, which are used, when the specific
1840** DNC Output is selected, the other is always off)
1841**
1842** If PAL-L or L' is received, set:
1843** MT2063_SetParam(hMT2063,MT2063_TAGC,1);
1844**
1845** --------------+----------------------------------------------
1846** Mode 0 : | MT2063_CABLE_QAM
1847** Mode 1 : | MT2063_CABLE_ANALOG
1848** Mode 2 : | MT2063_OFFAIR_COFDM
1849** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
1850** Mode 4 : | MT2063_OFFAIR_ANALOG
1851** Mode 5 : | MT2063_OFFAIR_8VSB
1852** --------------+----+----+----+----+-----+-----+--------------
1853** Mode | 0 | 1 | 2 | 3 | 4 | 5 |
1854** --------------+----+----+----+----+-----+-----+
1855**
1856**
1857*/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001858static const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 };
1859static const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 };
1860static const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 };
1861static const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 };
1862static const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 };
1863static const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 };
1864static const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 };
1865static const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 };
1866static const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
1867static const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 };
1868static const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 };
1869static const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
1870static const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 };
1871static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 };
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001872
1873/*
1874** Local Function Prototypes - not available for external access.
1875*/
1876
1877/* Forward declaration(s): */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001878static u32 MT2063_CalcLO1Mult(u32 * Div, u32 * FracN, u32 f_LO,
1879 u32 f_LO_Step, u32 f_Ref);
1880static u32 MT2063_CalcLO2Mult(u32 * Div, u32 * FracN, u32 f_LO,
1881 u32 f_LO_Step, u32 f_Ref);
1882static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num,
1883 u32 denom);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001884
1885/******************************************************************************
1886**
1887** Name: MT2063_Open
1888**
1889** Description: Initialize the tuner's register values.
1890**
1891** Parameters: MT2063_Addr - Serial bus address of the tuner.
1892** hMT2063 - Tuner handle passed back.
1893** hUserData - User-defined data, if needed for the
1894** MT_ReadSub() & MT_WriteSub functions.
1895**
1896** Returns: status:
1897** MT_OK - No errors
1898** MT_TUNER_ID_ERR - Tuner Part/Rev code mismatch
1899** MT_TUNER_INIT_ERR - Tuner initialization failed
1900** MT_COMM_ERR - Serial bus communications error
1901** MT_ARG_NULL - Null pointer argument passed
1902** MT_TUNER_CNT_ERR - Too many tuners open
1903**
1904** Dependencies: MT_ReadSub - Read byte(s) of data from the two-wire bus
1905** MT_WriteSub - Write byte(s) of data to the two-wire bus
1906**
1907** Revision History:
1908**
1909** SCR Date Author Description
1910** -------------------------------------------------------------------------
1911** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1912**
1913******************************************************************************/
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -03001914static u32 MT2063_Open(u32 MT2063_Addr, struct MT2063_Info_t **hMT2063, void *hUserData)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001915{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001916 u32 status = 0; /* Status to be returned. */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001917 struct MT2063_Info_t *pInfo = NULL;
1918 struct dvb_frontend *fe = (struct dvb_frontend *)hUserData;
1919 struct mt2063_state *state = fe->tuner_priv;
1920
1921 /* Check the argument before using */
1922 if (hMT2063 == NULL) {
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001923 return -ENODEV;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001924 }
1925
1926 /* Default tuner handle to NULL. If successful, it will be reassigned */
1927
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001928 if (state->MT2063_init == false) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001929 pInfo = kzalloc(sizeof(struct MT2063_Info_t), GFP_KERNEL);
1930 if (pInfo == NULL) {
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001931 return -ENOMEM;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001932 }
1933 pInfo->handle = NULL;
1934 pInfo->address = MAX_UDATA;
1935 pInfo->rcvr_mode = MT2063_CABLE_QAM;
1936 pInfo->hUserData = NULL;
1937 } else {
1938 pInfo = *hMT2063;
1939 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001940
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001941 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001942 status |= MT2063_RegisterTuner(&pInfo->AS_Data);
1943 }
1944
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001945 if (status >= 0) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001946 pInfo->handle = (void *) pInfo;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001947
1948 pInfo->hUserData = hUserData;
1949 pInfo->address = MT2063_Addr;
1950 pInfo->rcvr_mode = MT2063_CABLE_QAM;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001951 status |= MT2063_ReInit((void *) pInfo);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001952 }
1953
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001954 if (status < 0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001955 /* MT2063_Close handles the un-registration of the tuner */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001956 MT2063_Close((void *) pInfo);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001957 else {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001958 state->MT2063_init = true;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001959 *hMT2063 = pInfo->handle;
1960
1961 }
1962
1963 return (status);
1964}
1965
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001966static u32 MT2063_IsValidHandle(struct MT2063_Info_t *handle)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001967{
1968 return ((handle != NULL) && (handle->handle == handle)) ? 1 : 0;
1969}
1970
1971/******************************************************************************
1972**
1973** Name: MT2063_Close
1974**
1975** Description: Release the handle to the tuner.
1976**
1977** Parameters: hMT2063 - Handle to the MT2063 tuner
1978**
1979** Returns: status:
1980** MT_OK - No errors
1981** MT_INV_HANDLE - Invalid tuner handle
1982**
1983** Dependencies: mt_errordef.h - definition of error codes
1984**
1985** Revision History:
1986**
1987** SCR Date Author Description
1988** -------------------------------------------------------------------------
1989** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1990**
1991******************************************************************************/
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001992static u32 MT2063_Close(struct MT2063_Info_t *pInfo)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001993{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001994 if (!MT2063_IsValidHandle(pInfo))
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001995 return -ENODEV;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001996
1997 /* Unregister tuner with SpurAvoidance routines (if needed) */
1998 MT2063_UnRegisterTuner(&pInfo->AS_Data);
1999 /* Now remove the tuner from our own list of tuners */
2000 pInfo->handle = NULL;
2001 pInfo->address = MAX_UDATA;
2002 pInfo->hUserData = NULL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002003 //kfree(pInfo);
2004 //pInfo = NULL;
Mauro Carvalho Chehaba0813ea2011-07-20 21:19:08 -03002005
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002006 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002007}
2008
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002009/****************************************************************************
2010**
2011** Name: MT2063_GetLocked
2012**
2013** Description: Checks to see if LO1 and LO2 are locked.
2014**
2015** Parameters: h - Open handle to the tuner (from MT2063_Open).
2016**
2017** Returns: status:
2018** MT_OK - No errors
2019** MT_UPC_UNLOCK - Upconverter PLL unlocked
2020** MT_DNC_UNLOCK - Downconverter PLL unlocked
2021** MT_COMM_ERR - Serial bus communications error
2022** MT_INV_HANDLE - Invalid tuner handle
2023**
2024** Dependencies: MT_ReadSub - Read byte(s) of data from the serial bus
2025** MT_Sleep - Delay execution for x milliseconds
2026**
2027** Revision History:
2028**
2029** SCR Date Author Description
2030** -------------------------------------------------------------------------
2031** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2032**
2033****************************************************************************/
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002034static u32 MT2063_GetLocked(struct MT2063_Info_t *pInfo)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002035{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002036 const u32 nMaxWait = 100; /* wait a maximum of 100 msec */
2037 const u32 nPollRate = 2; /* poll status bits every 2 ms */
2038 const u32 nMaxLoops = nMaxWait / nPollRate;
2039 const u8 LO1LK = 0x80;
2040 u8 LO2LK = 0x08;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002041 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002042 u32 nDelays = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002043
2044 if (MT2063_IsValidHandle(pInfo) == 0)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002045 return -ENODEV;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002046
2047 /* LO2 Lock bit was in a different place for B0 version */
2048 if (pInfo->tuner_id == MT2063_B0)
2049 LO2LK = 0x40;
2050
2051 do {
2052 status |=
2053 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
2054 MT2063_REG_LO_STATUS,
2055 &pInfo->reg[MT2063_REG_LO_STATUS], 1);
2056
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002057 if (status < 0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002058 return (status);
2059
2060 if ((pInfo->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) ==
2061 (LO1LK | LO2LK)) {
2062 return (status);
2063 }
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002064 msleep(nPollRate); /* Wait between retries */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002065 }
2066 while (++nDelays < nMaxLoops);
2067
2068 if ((pInfo->reg[MT2063_REG_LO_STATUS] & LO1LK) == 0x00)
2069 status |= MT2063_UPC_UNLOCK;
2070 if ((pInfo->reg[MT2063_REG_LO_STATUS] & LO2LK) == 0x00)
2071 status |= MT2063_DNC_UNLOCK;
2072
2073 return (status);
2074}
2075
2076/****************************************************************************
2077**
2078** Name: MT2063_GetParam
2079**
2080** Description: Gets a tuning algorithm parameter.
2081**
2082** This function provides access to the internals of the
2083** tuning algorithm - mostly for testing purposes.
2084**
2085** Parameters: h - Tuner handle (returned by MT2063_Open)
2086** param - Tuning algorithm parameter
2087** (see enum MT2063_Param)
2088** pValue - ptr to returned value
2089**
2090** param Description
2091** ---------------------- --------------------------------
2092** MT2063_IC_ADDR Serial Bus address of this tuner
2093** MT2063_MAX_OPEN Max # of MT2063's allowed open
2094** MT2063_NUM_OPEN # of MT2063's open
2095** MT2063_SRO_FREQ crystal frequency
2096** MT2063_STEPSIZE minimum tuning step size
2097** MT2063_INPUT_FREQ input center frequency
2098** MT2063_LO1_FREQ LO1 Frequency
2099** MT2063_LO1_STEPSIZE LO1 minimum step size
2100** MT2063_LO1_FRACN_AVOID LO1 FracN keep-out region
2101** MT2063_IF1_ACTUAL Current 1st IF in use
2102** MT2063_IF1_REQUEST Requested 1st IF
2103** MT2063_IF1_CENTER Center of 1st IF SAW filter
2104** MT2063_IF1_BW Bandwidth of 1st IF SAW filter
2105** MT2063_ZIF_BW zero-IF bandwidth
2106** MT2063_LO2_FREQ LO2 Frequency
2107** MT2063_LO2_STEPSIZE LO2 minimum step size
2108** MT2063_LO2_FRACN_AVOID LO2 FracN keep-out region
2109** MT2063_OUTPUT_FREQ output center frequency
2110** MT2063_OUTPUT_BW output bandwidth
2111** MT2063_LO_SEPARATION min inter-tuner LO separation
2112** MT2063_AS_ALG ID of avoid-spurs algorithm in use
2113** MT2063_MAX_HARM1 max # of intra-tuner harmonics
2114** MT2063_MAX_HARM2 max # of inter-tuner harmonics
2115** MT2063_EXCL_ZONES # of 1st IF exclusion zones
2116** MT2063_NUM_SPURS # of spurs found/avoided
2117** MT2063_SPUR_AVOIDED >0 spurs avoided
2118** MT2063_SPUR_PRESENT >0 spurs in output (mathematically)
2119** MT2063_RCVR_MODE Predefined modes.
2120** MT2063_ACLNA LNA attenuator gain code
2121** MT2063_ACRF RF attenuator gain code
2122** MT2063_ACFIF FIF attenuator gain code
2123** MT2063_ACLNA_MAX LNA attenuator limit
2124** MT2063_ACRF_MAX RF attenuator limit
2125** MT2063_ACFIF_MAX FIF attenuator limit
2126** MT2063_PD1 Actual value of PD1
2127** MT2063_PD2 Actual value of PD2
2128** MT2063_DNC_OUTPUT_ENABLE DNC output selection
2129** MT2063_VGAGC VGA gain code
2130** MT2063_VGAOI VGA output current
2131** MT2063_TAGC TAGC setting
2132** MT2063_AMPGC AMP gain code
2133** MT2063_AVOID_DECT Avoid DECT Frequencies
2134** MT2063_CTFILT_SW Cleartune filter selection
2135**
2136** Usage: status |= MT2063_GetParam(hMT2063,
2137** MT2063_IF1_ACTUAL,
2138** &f_IF1_Actual);
2139**
2140** Returns: status:
2141** MT_OK - No errors
2142** MT_INV_HANDLE - Invalid tuner handle
2143** MT_ARG_NULL - Null pointer argument passed
2144** MT_ARG_RANGE - Invalid parameter requested
2145**
2146** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
2147**
2148** See Also: MT2063_SetParam, MT2063_Open
2149**
2150** Revision History:
2151**
2152** SCR Date Author Description
2153** -------------------------------------------------------------------------
2154** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2155** 154 09-13-2007 RSK Ver 1.05: Get/SetParam changes for LOx_FREQ
2156** 10-31-2007 PINZ Ver 1.08: Get/SetParam add VGAGC, VGAOI, AMPGC, TAGC
2157** 173 M 01-23-2008 RSK Ver 1.12: Read LO1C and LO2C registers from HW
2158** in GetParam.
2159** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
2160** Split SetParam up to ACLNA / ACLNA_MAX
2161** removed ACLNA_INRC/DECR (+RF & FIF)
2162** removed GCUAUTO / BYPATNDN/UP
2163** 175 I 16-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
2164** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
2165** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
2166**
2167****************************************************************************/
Mauro Carvalho Chehab29a0a4f2011-07-20 23:44:10 -03002168static u32 MT2063_GetParam(struct MT2063_Info_t *pInfo, enum MT2063_Param param, u32 *pValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002169{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002170 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002171 u32 Div;
2172 u32 Num;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002173
2174 if (pValue == NULL)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002175 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002176
2177 /* Verify that the handle passed points to a valid tuner */
2178 if (MT2063_IsValidHandle(pInfo) == 0)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002179 return -ENODEV;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002180
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002181 switch (param) {
2182 /* Serial Bus address of this tuner */
2183 case MT2063_IC_ADDR:
2184 *pValue = pInfo->address;
2185 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002186
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002187 /* Max # of MT2063's allowed to be open */
2188 case MT2063_MAX_OPEN:
2189 *pValue = nMT2063MaxTuners;
2190 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002191
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002192 /* # of MT2063's open */
2193 case MT2063_NUM_OPEN:
2194 *pValue = nMT2063OpenTuners;
2195 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002196
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002197 /* crystal frequency */
2198 case MT2063_SRO_FREQ:
2199 *pValue = pInfo->AS_Data.f_ref;
2200 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002201
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002202 /* minimum tuning step size */
2203 case MT2063_STEPSIZE:
2204 *pValue = pInfo->AS_Data.f_LO2_Step;
2205 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002206
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002207 /* input center frequency */
2208 case MT2063_INPUT_FREQ:
2209 *pValue = pInfo->AS_Data.f_in;
2210 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002211
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002212 /* LO1 Frequency */
2213 case MT2063_LO1_FREQ:
2214 {
2215 /* read the actual tuner register values for LO1C_1 and LO1C_2 */
2216 status |=
2217 MT2063_ReadSub(pInfo->hUserData,
2218 pInfo->address,
2219 MT2063_REG_LO1C_1,
2220 &pInfo->
2221 reg[MT2063_REG_LO1C_1], 2);
2222 Div = pInfo->reg[MT2063_REG_LO1C_1];
2223 Num = pInfo->reg[MT2063_REG_LO1C_2] & 0x3F;
2224 pInfo->AS_Data.f_LO1 =
2225 (pInfo->AS_Data.f_ref * Div) +
2226 MT2063_fLO_FractionalTerm(pInfo->AS_Data.
2227 f_ref, Num, 64);
2228 }
2229 *pValue = pInfo->AS_Data.f_LO1;
2230 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002231
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002232 /* LO1 minimum step size */
2233 case MT2063_LO1_STEPSIZE:
2234 *pValue = pInfo->AS_Data.f_LO1_Step;
2235 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002236
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002237 /* LO1 FracN keep-out region */
2238 case MT2063_LO1_FRACN_AVOID_PARAM:
2239 *pValue = pInfo->AS_Data.f_LO1_FracN_Avoid;
2240 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002241
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002242 /* Current 1st IF in use */
2243 case MT2063_IF1_ACTUAL:
2244 *pValue = pInfo->f_IF1_actual;
2245 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002246
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002247 /* Requested 1st IF */
2248 case MT2063_IF1_REQUEST:
2249 *pValue = pInfo->AS_Data.f_if1_Request;
2250 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002251
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002252 /* Center of 1st IF SAW filter */
2253 case MT2063_IF1_CENTER:
2254 *pValue = pInfo->AS_Data.f_if1_Center;
2255 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002256
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002257 /* Bandwidth of 1st IF SAW filter */
2258 case MT2063_IF1_BW:
2259 *pValue = pInfo->AS_Data.f_if1_bw;
2260 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002261
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002262 /* zero-IF bandwidth */
2263 case MT2063_ZIF_BW:
2264 *pValue = pInfo->AS_Data.f_zif_bw;
2265 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002266
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002267 /* LO2 Frequency */
2268 case MT2063_LO2_FREQ:
2269 {
2270 /* Read the actual tuner register values for LO2C_1, LO2C_2 and LO2C_3 */
2271 status |=
2272 MT2063_ReadSub(pInfo->hUserData,
2273 pInfo->address,
2274 MT2063_REG_LO2C_1,
2275 &pInfo->
2276 reg[MT2063_REG_LO2C_1], 3);
2277 Div =
2278 (pInfo->reg[MT2063_REG_LO2C_1] & 0xFE) >> 1;
2279 Num =
2280 ((pInfo->
2281 reg[MT2063_REG_LO2C_1] & 0x01) << 12) |
2282 (pInfo->
2283 reg[MT2063_REG_LO2C_2] << 4) | (pInfo->
2284 reg
2285 [MT2063_REG_LO2C_3]
2286 & 0x00F);
2287 pInfo->AS_Data.f_LO2 =
2288 (pInfo->AS_Data.f_ref * Div) +
2289 MT2063_fLO_FractionalTerm(pInfo->AS_Data.
2290 f_ref, Num, 8191);
2291 }
2292 *pValue = pInfo->AS_Data.f_LO2;
2293 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002294
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002295 /* LO2 minimum step size */
2296 case MT2063_LO2_STEPSIZE:
2297 *pValue = pInfo->AS_Data.f_LO2_Step;
2298 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002299
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002300 /* LO2 FracN keep-out region */
2301 case MT2063_LO2_FRACN_AVOID:
2302 *pValue = pInfo->AS_Data.f_LO2_FracN_Avoid;
2303 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002304
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002305 /* output center frequency */
2306 case MT2063_OUTPUT_FREQ:
2307 *pValue = pInfo->AS_Data.f_out;
2308 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002309
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002310 /* output bandwidth */
2311 case MT2063_OUTPUT_BW:
2312 *pValue = pInfo->AS_Data.f_out_bw - 750000;
2313 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002314
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002315 /* min inter-tuner LO separation */
2316 case MT2063_LO_SEPARATION:
2317 *pValue = pInfo->AS_Data.f_min_LO_Separation;
2318 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002319
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002320 /* ID of avoid-spurs algorithm in use */
2321 case MT2063_AS_ALG:
2322 *pValue = pInfo->AS_Data.nAS_Algorithm;
2323 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002324
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002325 /* max # of intra-tuner harmonics */
2326 case MT2063_MAX_HARM1:
2327 *pValue = pInfo->AS_Data.maxH1;
2328 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002329
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002330 /* max # of inter-tuner harmonics */
2331 case MT2063_MAX_HARM2:
2332 *pValue = pInfo->AS_Data.maxH2;
2333 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002334
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002335 /* # of 1st IF exclusion zones */
2336 case MT2063_EXCL_ZONES:
2337 *pValue = pInfo->AS_Data.nZones;
2338 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002339
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002340 /* # of spurs found/avoided */
2341 case MT2063_NUM_SPURS:
2342 *pValue = pInfo->AS_Data.nSpursFound;
2343 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002344
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002345 /* >0 spurs avoided */
2346 case MT2063_SPUR_AVOIDED:
2347 *pValue = pInfo->AS_Data.bSpurAvoided;
2348 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002349
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002350 /* >0 spurs in output (mathematically) */
2351 case MT2063_SPUR_PRESENT:
2352 *pValue = pInfo->AS_Data.bSpurPresent;
2353 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002354
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002355 /* Predefined receiver setup combination */
2356 case MT2063_RCVR_MODE:
2357 *pValue = pInfo->rcvr_mode;
2358 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002359
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002360 case MT2063_PD1:
2361 case MT2063_PD2:
2362 {
2363 u8 mask = (param == MT2063_PD1 ? 0x01 : 0x03); /* PD1 vs PD2 */
2364 u8 orig = (pInfo->reg[MT2063_REG_BYP_CTRL]);
2365 u8 reg = (orig & 0xF1) | mask; /* Only set 3 bits (not 5) */
2366 int i;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002367
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002368 *pValue = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002369
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002370 /* Initiate ADC output to reg 0x0A */
2371 if (reg != orig)
2372 status |=
2373 MT2063_WriteSub(pInfo->hUserData,
2374 pInfo->address,
2375 MT2063_REG_BYP_CTRL,
2376 &reg, 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002377
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002378 if (status < 0)
2379 return (status);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002380
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002381 for (i = 0; i < 8; i++) {
2382 status |=
2383 MT2063_ReadSub(pInfo->hUserData,
2384 pInfo->address,
2385 MT2063_REG_ADC_OUT,
2386 &pInfo->
2387 reg
2388 [MT2063_REG_ADC_OUT],
2389 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002390
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002391 if (status >= 0)
2392 *pValue +=
2393 pInfo->
2394 reg[MT2063_REG_ADC_OUT];
2395 else {
2396 if (i)
2397 *pValue /= i;
2398 return (status);
2399 }
2400 }
2401 *pValue /= 8; /* divide by number of reads */
2402 *pValue >>= 2; /* only want 6 MSB's out of 8 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002403
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002404 /* Restore value of Register BYP_CTRL */
2405 if (reg != orig)
2406 status |=
2407 MT2063_WriteSub(pInfo->hUserData,
2408 pInfo->address,
2409 MT2063_REG_BYP_CTRL,
2410 &orig, 1);
2411 }
2412 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002413
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002414 /* Get LNA attenuator code */
2415 case MT2063_ACLNA:
2416 {
2417 u8 val;
2418 status |=
2419 MT2063_GetReg(pInfo, MT2063_REG_XO_STATUS,
2420 &val);
2421 *pValue = val & 0x1f;
2422 }
2423 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002424
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002425 /* Get RF attenuator code */
2426 case MT2063_ACRF:
2427 {
2428 u8 val;
2429 status |=
2430 MT2063_GetReg(pInfo, MT2063_REG_RF_STATUS,
2431 &val);
2432 *pValue = val & 0x1f;
2433 }
2434 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002435
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002436 /* Get FIF attenuator code */
2437 case MT2063_ACFIF:
2438 {
2439 u8 val;
2440 status |=
2441 MT2063_GetReg(pInfo, MT2063_REG_FIF_STATUS,
2442 &val);
2443 *pValue = val & 0x1f;
2444 }
2445 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002446
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002447 /* Get LNA attenuator limit */
2448 case MT2063_ACLNA_MAX:
2449 {
2450 u8 val;
2451 status |=
2452 MT2063_GetReg(pInfo, MT2063_REG_LNA_OV,
2453 &val);
2454 *pValue = val & 0x1f;
2455 }
2456 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002457
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002458 /* Get RF attenuator limit */
2459 case MT2063_ACRF_MAX:
2460 {
2461 u8 val;
2462 status |=
2463 MT2063_GetReg(pInfo, MT2063_REG_RF_OV,
2464 &val);
2465 *pValue = val & 0x1f;
2466 }
2467 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002468
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002469 /* Get FIF attenuator limit */
2470 case MT2063_ACFIF_MAX:
2471 {
2472 u8 val;
2473 status |=
2474 MT2063_GetReg(pInfo, MT2063_REG_FIF_OV,
2475 &val);
2476 *pValue = val & 0x1f;
2477 }
2478 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002479
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002480 /* Get current used DNC output */
2481 case MT2063_DNC_OUTPUT_ENABLE:
2482 {
2483 if ((pInfo->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */
2484 if ((pInfo->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
2485 *pValue =
2486 (u32) MT2063_DNC_NONE;
2487 else
2488 *pValue =
2489 (u32) MT2063_DNC_2;
2490 } else { /* DNC1 is on */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002491
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002492 if ((pInfo->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
2493 *pValue =
2494 (u32) MT2063_DNC_1;
2495 else
2496 *pValue =
2497 (u32) MT2063_DNC_BOTH;
2498 }
2499 }
2500 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002501
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002502 /* Get VGA Gain Code */
2503 case MT2063_VGAGC:
2504 *pValue =
2505 ((pInfo->reg[MT2063_REG_VGA_GAIN] & 0x0C) >> 2);
2506 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002507
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002508 /* Get VGA bias current */
2509 case MT2063_VGAOI:
2510 *pValue = (pInfo->reg[MT2063_REG_RSVD_31] & 0x07);
2511 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002512
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002513 /* Get TAGC setting */
2514 case MT2063_TAGC:
2515 *pValue = (pInfo->reg[MT2063_REG_RSVD_1E] & 0x03);
2516 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002517
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002518 /* Get AMP Gain Code */
2519 case MT2063_AMPGC:
2520 *pValue = (pInfo->reg[MT2063_REG_TEMP_SEL] & 0x03);
2521 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002522
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002523 /* Avoid DECT Frequencies */
2524 case MT2063_AVOID_DECT:
2525 *pValue = pInfo->AS_Data.avoidDECT;
2526 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002527
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002528 /* Cleartune filter selection: 0 - by IC (default), 1 - by software */
2529 case MT2063_CTFILT_SW:
2530 *pValue = pInfo->ctfilt_sw;
2531 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002532
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002533 case MT2063_EOP:
2534 default:
2535 status |= -ERANGE;
2536 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002537 return (status);
2538}
2539
2540/****************************************************************************
2541**
2542** Name: MT2063_GetReg
2543**
2544** Description: Gets an MT2063 register.
2545**
2546** Parameters: h - Tuner handle (returned by MT2063_Open)
2547** reg - MT2063 register/subaddress location
2548** *val - MT2063 register/subaddress value
2549**
2550** Returns: status:
2551** MT_OK - No errors
2552** MT_COMM_ERR - Serial bus communications error
2553** MT_INV_HANDLE - Invalid tuner handle
2554** MT_ARG_NULL - Null pointer argument passed
2555** MT_ARG_RANGE - Argument out of range
2556**
2557** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
2558**
2559** Use this function if you need to read a register from
2560** the MT2063.
2561**
2562** Revision History:
2563**
2564** SCR Date Author Description
2565** -------------------------------------------------------------------------
2566** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2567**
2568****************************************************************************/
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002569static u32 MT2063_GetReg(struct MT2063_Info_t *pInfo, u8 reg, u8 * val)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002570{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002571 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002572
2573 /* Verify that the handle passed points to a valid tuner */
2574 if (MT2063_IsValidHandle(pInfo) == 0)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002575 return -ENODEV;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002576
2577 if (val == NULL)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002578 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002579
2580 if (reg >= MT2063_REG_END_REGS)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002581 return -ERANGE;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002582
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002583 status = MT2063_ReadSub(pInfo->hUserData, pInfo->address, reg,
2584 &pInfo->reg[reg], 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002585
2586 return (status);
2587}
2588
2589/******************************************************************************
2590**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002591** Name: MT2063_SetReceiverMode
2592**
2593** Description: Set the MT2063 receiver mode
2594**
2595** --------------+----------------------------------------------
2596** Mode 0 : | MT2063_CABLE_QAM
2597** Mode 1 : | MT2063_CABLE_ANALOG
2598** Mode 2 : | MT2063_OFFAIR_COFDM
2599** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
2600** Mode 4 : | MT2063_OFFAIR_ANALOG
2601** Mode 5 : | MT2063_OFFAIR_8VSB
2602** --------------+----+----+----+----+-----+--------------------
2603** (DNC1GC & DNC2GC are the values, which are used, when the specific
2604** DNC Output is selected, the other is always off)
2605**
2606** |<---------- Mode -------------->|
2607** Reg Field | 0 | 1 | 2 | 3 | 4 | 5 |
2608** ------------+-----+-----+-----+-----+-----+-----+
2609** RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF
2610** LNARin | 0 | 0 | 3 | 3 | 3 | 3
2611** FIFFQen | 1 | 1 | 1 | 1 | 1 | 1
2612** FIFFq | 0 | 0 | 0 | 0 | 0 | 0
2613** DNC1gc | 0 | 0 | 0 | 0 | 0 | 0
2614** DNC2gc | 0 | 0 | 0 | 0 | 0 | 0
2615** GCU Auto | 1 | 1 | 1 | 1 | 1 | 1
2616** LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31
2617** LNA Target | 44 | 43 | 43 | 43 | 43 | 43
2618** ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0
2619** RF max Atn | 31 | 31 | 31 | 31 | 31 | 31
2620** PD1 Target | 36 | 36 | 38 | 38 | 36 | 38
2621** ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0
2622** FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5
2623** PD2 Target | 40 | 33 | 42 | 42 | 33 | 42
2624**
2625**
2626** Parameters: pInfo - ptr to MT2063_Info_t structure
2627** Mode - desired reciever mode
2628**
2629** Usage: status = MT2063_SetReceiverMode(hMT2063, Mode);
2630**
2631** Returns: status:
2632** MT_OK - No errors
2633** MT_COMM_ERR - Serial bus communications error
2634**
2635** Dependencies: MT2063_SetReg - Write a byte of data to a HW register.
2636** Assumes that the tuner cache is valid.
2637**
2638** Revision History:
2639**
2640** SCR Date Author Description
2641** -------------------------------------------------------------------------
2642** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2643** N/A 01-10-2007 PINZ Added additional GCU Settings, FIFF Calib will be triggered
2644** 155 10-01-2007 DAD Ver 1.06: Add receiver mode for SECAM positive
2645** modulation
2646** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
2647** N/A 10-22-2007 PINZ Ver 1.07: Changed some Registers at init to have
2648** the same settings as with MT Launcher
2649** N/A 10-30-2007 PINZ Add SetParam VGAGC & VGAOI
2650** Add SetParam DNC_OUTPUT_ENABLE
2651** Removed VGAGC from receiver mode,
2652** default now 1
2653** N/A 10-31-2007 PINZ Ver 1.08: Add SetParam TAGC, removed from rcvr-mode
2654** Add SetParam AMPGC, removed from rcvr-mode
2655** Corrected names of GCU values
2656** reorganized receiver modes, removed,
2657** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
2658** Actualized Receiver-Mode values
2659** N/A 11-12-2007 PINZ Ver 1.09: Actualized Receiver-Mode values
2660** N/A 11-27-2007 PINZ Improved buffered writing
2661** 01-03-2008 PINZ Ver 1.10: Added a trigger of BYPATNUP for
2662** correct wakeup of the LNA after shutdown
2663** Set AFCsd = 1 as default
2664** Changed CAP1sel default
2665** 01-14-2008 PINZ Ver 1.11: Updated gain settings
2666** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
2667** Split SetParam up to ACLNA / ACLNA_MAX
2668** removed ACLNA_INRC/DECR (+RF & FIF)
2669** removed GCUAUTO / BYPATNDN/UP
2670**
2671******************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002672static u32 MT2063_SetReceiverMode(struct MT2063_Info_t *pInfo,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002673 enum MT2063_RCVR_MODES Mode)
2674{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002675 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002676 u8 val;
2677 u32 longval;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002678
2679 if (Mode >= MT2063_NUM_RCVR_MODES)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002680 status = -ERANGE;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002681
2682 /* RFAGCen */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002683 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002684 val =
2685 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002686 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x40) | (RFAGCEN[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002687 ? 0x40 :
2688 0x00);
2689 if (pInfo->reg[MT2063_REG_PD1_TGT] != val) {
2690 status |= MT2063_SetReg(pInfo, MT2063_REG_PD1_TGT, val);
2691 }
2692 }
2693
2694 /* LNARin */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002695 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002696 status |= MT2063_SetParam(pInfo, MT2063_LNA_RIN, LNARIN[Mode]);
2697 }
2698
2699 /* FIFFQEN and FIFFQ */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002700 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002701 val =
2702 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002703 reg[MT2063_REG_FIFF_CTRL2] & (u8) ~ 0xF0) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002704 (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
2705 if (pInfo->reg[MT2063_REG_FIFF_CTRL2] != val) {
2706 status |=
2707 MT2063_SetReg(pInfo, MT2063_REG_FIFF_CTRL2, val);
2708 /* trigger FIFF calibration, needed after changing FIFFQ */
2709 val =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002710 (pInfo->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002711 status |=
2712 MT2063_SetReg(pInfo, MT2063_REG_FIFF_CTRL, val);
2713 val =
2714 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002715 reg[MT2063_REG_FIFF_CTRL] & (u8) ~ 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002716 status |=
2717 MT2063_SetReg(pInfo, MT2063_REG_FIFF_CTRL, val);
2718 }
2719 }
2720
2721 /* DNC1GC & DNC2GC */
2722 status |= MT2063_GetParam(pInfo, MT2063_DNC_OUTPUT_ENABLE, &longval);
2723 status |= MT2063_SetParam(pInfo, MT2063_DNC_OUTPUT_ENABLE, longval);
2724
2725 /* acLNAmax */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002726 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002727 status |=
2728 MT2063_SetParam(pInfo, MT2063_ACLNA_MAX, ACLNAMAX[Mode]);
2729 }
2730
2731 /* LNATGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002732 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002733 status |= MT2063_SetParam(pInfo, MT2063_LNA_TGT, LNATGT[Mode]);
2734 }
2735
2736 /* ACRF */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002737 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002738 status |=
2739 MT2063_SetParam(pInfo, MT2063_ACRF_MAX, ACRFMAX[Mode]);
2740 }
2741
2742 /* PD1TGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002743 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002744 status |= MT2063_SetParam(pInfo, MT2063_PD1_TGT, PD1TGT[Mode]);
2745 }
2746
2747 /* FIFATN */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002748 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002749 status |=
2750 MT2063_SetParam(pInfo, MT2063_ACFIF_MAX, ACFIFMAX[Mode]);
2751 }
2752
2753 /* PD2TGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002754 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002755 status |= MT2063_SetParam(pInfo, MT2063_PD2_TGT, PD2TGT[Mode]);
2756 }
2757
2758 /* Ignore ATN Overload */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002759 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002760 val =
2761 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002762 reg[MT2063_REG_LNA_TGT] & (u8) ~ 0x80) | (RFOVDIS[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002763 ? 0x80 :
2764 0x00);
2765 if (pInfo->reg[MT2063_REG_LNA_TGT] != val) {
2766 status |= MT2063_SetReg(pInfo, MT2063_REG_LNA_TGT, val);
2767 }
2768 }
2769
2770 /* Ignore FIF Overload */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002771 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002772 val =
2773 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002774 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x80) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002775 (FIFOVDIS[Mode] ? 0x80 : 0x00);
2776 if (pInfo->reg[MT2063_REG_PD1_TGT] != val) {
2777 status |= MT2063_SetReg(pInfo, MT2063_REG_PD1_TGT, val);
2778 }
2779 }
2780
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002781 if (status >= 0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002782 pInfo->rcvr_mode = Mode;
2783
2784 return (status);
2785}
2786
2787/******************************************************************************
2788**
2789** Name: MT2063_ReInit
2790**
2791** Description: Initialize the tuner's register values.
2792**
2793** Parameters: h - Tuner handle (returned by MT2063_Open)
2794**
2795** Returns: status:
2796** MT_OK - No errors
2797** MT_TUNER_ID_ERR - Tuner Part/Rev code mismatch
2798** MT_INV_HANDLE - Invalid tuner handle
2799** MT_COMM_ERR - Serial bus communications error
2800**
2801** Dependencies: MT_ReadSub - Read byte(s) of data from the two-wire bus
2802** MT_WriteSub - Write byte(s) of data to the two-wire bus
2803**
2804** Revision History:
2805**
2806** SCR Date Author Description
2807** -------------------------------------------------------------------------
2808** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2809** 148 09-04-2007 RSK Ver 1.02: Corrected logic of Reg 3B Reference
2810** 153 09-07-2007 RSK Ver 1.03: Lock Time improvements
2811** N/A 10-31-2007 PINZ Ver 1.08: Changed values suitable to rcvr-mode 0
2812** N/A 11-12-2007 PINZ Ver 1.09: Changed values suitable to rcvr-mode 0
2813** N/A 01-03-2007 PINZ Ver 1.10: Added AFCsd = 1 into defaults
2814** N/A 01-04-2007 PINZ Ver 1.10: Changed CAP1sel default
2815** 01-14-2008 PINZ Ver 1.11: Updated gain settings
2816** 03-18-2008 PINZ Ver 1.13: Added Support for B3
2817** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
2818** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
2819**
2820******************************************************************************/
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002821static u32 MT2063_ReInit(struct MT2063_Info_t *pInfo)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002822{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002823 u8 all_resets = 0xF0; /* reset/load bits */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002824 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -03002825 u8 *def = NULL;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002826 u32 FCRUN;
2827 s32 maxReads;
2828 u32 fcu_osc;
2829 u32 i;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002830 u8 MT2063B0_defaults[] = { /* Reg, Value */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002831 0x19, 0x05,
2832 0x1B, 0x1D,
2833 0x1C, 0x1F,
2834 0x1D, 0x0F,
2835 0x1E, 0x3F,
2836 0x1F, 0x0F,
2837 0x20, 0x3F,
2838 0x22, 0x21,
2839 0x23, 0x3F,
2840 0x24, 0x20,
2841 0x25, 0x3F,
2842 0x27, 0xEE,
2843 0x2C, 0x27, /* bit at 0x20 is cleared below */
2844 0x30, 0x03,
2845 0x2C, 0x07, /* bit at 0x20 is cleared here */
2846 0x2D, 0x87,
2847 0x2E, 0xAA,
2848 0x28, 0xE1, /* Set the FIFCrst bit here */
2849 0x28, 0xE0, /* Clear the FIFCrst bit here */
2850 0x00
2851 };
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002852 /* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002853 u8 MT2063B1_defaults[] = { /* Reg, Value */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002854 0x05, 0xF0,
2855 0x11, 0x10, /* New Enable AFCsd */
2856 0x19, 0x05,
2857 0x1A, 0x6C,
2858 0x1B, 0x24,
2859 0x1C, 0x28,
2860 0x1D, 0x8F,
2861 0x1E, 0x14,
2862 0x1F, 0x8F,
2863 0x20, 0x57,
2864 0x22, 0x21, /* New - ver 1.03 */
2865 0x23, 0x3C, /* New - ver 1.10 */
2866 0x24, 0x20, /* New - ver 1.03 */
2867 0x2C, 0x24, /* bit at 0x20 is cleared below */
2868 0x2D, 0x87, /* FIFFQ=0 */
2869 0x2F, 0xF3,
2870 0x30, 0x0C, /* New - ver 1.11 */
2871 0x31, 0x1B, /* New - ver 1.11 */
2872 0x2C, 0x04, /* bit at 0x20 is cleared here */
2873 0x28, 0xE1, /* Set the FIFCrst bit here */
2874 0x28, 0xE0, /* Clear the FIFCrst bit here */
2875 0x00
2876 };
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002877 /* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002878 u8 MT2063B3_defaults[] = { /* Reg, Value */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002879 0x05, 0xF0,
2880 0x19, 0x3D,
2881 0x2C, 0x24, /* bit at 0x20 is cleared below */
2882 0x2C, 0x04, /* bit at 0x20 is cleared here */
2883 0x28, 0xE1, /* Set the FIFCrst bit here */
2884 0x28, 0xE0, /* Clear the FIFCrst bit here */
2885 0x00
2886 };
2887
2888 /* Verify that the handle passed points to a valid tuner */
2889 if (MT2063_IsValidHandle(pInfo) == 0)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002890 return -ENODEV;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002891
2892 /* Read the Part/Rev code from the tuner */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002893 status = MT2063_ReadSub(pInfo->hUserData, pInfo->address,
2894 MT2063_REG_PART_REV, pInfo->reg, 1);
2895 if (status < 0)
2896 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002897
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002898 /* Check the part/rev code */
2899 if (((pInfo->reg[MT2063_REG_PART_REV] != MT2063_B0) /* MT2063 B0 */
2900 &&(pInfo->reg[MT2063_REG_PART_REV] != MT2063_B1) /* MT2063 B1 */
2901 &&(pInfo->reg[MT2063_REG_PART_REV] != MT2063_B3))) /* MT2063 B3 */
2902 return -ENODEV; /* Wrong tuner Part/Rev code */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002903
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002904 /* Check the 2nd byte of the Part/Rev code from the tuner */
2905 status = MT2063_ReadSub(pInfo->hUserData, pInfo->address,
2906 MT2063_REG_RSVD_3B,
2907 &pInfo->reg[MT2063_REG_RSVD_3B], 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002908
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002909 if (status >= 0
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002910 &&((pInfo->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) /* b7 != 0 ==> NOT MT2063 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002911 return -ENODEV; /* Wrong tuner Part/Rev code */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002912
2913 /* Reset the tuner */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002914 status = MT2063_WriteSub(pInfo->hUserData,
2915 pInfo->address,
2916 MT2063_REG_LO2CQ_3, &all_resets, 1);
2917 if (status < 0)
2918 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002919
2920 /* change all of the default values that vary from the HW reset values */
2921 /* def = (pInfo->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */
2922 switch (pInfo->reg[MT2063_REG_PART_REV]) {
2923 case MT2063_B3:
2924 def = MT2063B3_defaults;
2925 break;
2926
2927 case MT2063_B1:
2928 def = MT2063B1_defaults;
2929 break;
2930
2931 case MT2063_B0:
2932 def = MT2063B0_defaults;
2933 break;
2934
2935 default:
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002936 return -ENODEV;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002937 break;
2938 }
2939
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002940 while (status >= 0 && *def) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002941 u8 reg = *def++;
2942 u8 val = *def++;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002943 status = MT2063_WriteSub(pInfo->hUserData, pInfo->address, reg,
2944 &val, 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002945 }
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002946 if (status < 0)
2947 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002948
2949 /* Wait for FIFF location to complete. */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002950 FCRUN = 1;
2951 maxReads = 10;
2952 while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) {
2953 msleep(2);
2954 status = MT2063_ReadSub(pInfo->hUserData,
2955 pInfo->address,
2956 MT2063_REG_XO_STATUS,
2957 &pInfo->
2958 reg[MT2063_REG_XO_STATUS], 1);
2959 FCRUN = (pInfo->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002960 }
2961
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002962 if (FCRUN != 0)
2963 return -ENODEV;
2964
2965 status = MT2063_ReadSub(pInfo->hUserData, pInfo->address,
2966 MT2063_REG_FIFFC,
2967 &pInfo->reg[MT2063_REG_FIFFC], 1);
2968 if (status < 0)
2969 return status;
2970
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002971 /* Read back all the registers from the tuner */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002972 status = MT2063_ReadSub(pInfo->hUserData,
2973 pInfo->address,
2974 MT2063_REG_PART_REV,
2975 pInfo->reg, MT2063_REG_END_REGS);
2976 if (status < 0)
2977 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002978
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002979 /* Initialize the tuner state. */
2980 pInfo->tuner_id = pInfo->reg[MT2063_REG_PART_REV];
2981 pInfo->AS_Data.f_ref = MT2063_REF_FREQ;
2982 pInfo->AS_Data.f_if1_Center = (pInfo->AS_Data.f_ref / 8) *
2983 ((u32) pInfo->reg[MT2063_REG_FIFFC] + 640);
2984 pInfo->AS_Data.f_if1_bw = MT2063_IF1_BW;
2985 pInfo->AS_Data.f_out = 43750000UL;
2986 pInfo->AS_Data.f_out_bw = 6750000UL;
2987 pInfo->AS_Data.f_zif_bw = MT2063_ZIF_BW;
2988 pInfo->AS_Data.f_LO1_Step = pInfo->AS_Data.f_ref / 64;
2989 pInfo->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE;
2990 pInfo->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1;
2991 pInfo->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2;
2992 pInfo->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP;
2993 pInfo->AS_Data.f_if1_Request = pInfo->AS_Data.f_if1_Center;
2994 pInfo->AS_Data.f_LO1 = 2181000000UL;
2995 pInfo->AS_Data.f_LO2 = 1486249786UL;
2996 pInfo->f_IF1_actual = pInfo->AS_Data.f_if1_Center;
2997 pInfo->AS_Data.f_in = pInfo->AS_Data.f_LO1 - pInfo->f_IF1_actual;
2998 pInfo->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID;
2999 pInfo->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID;
3000 pInfo->num_regs = MT2063_REG_END_REGS;
3001 pInfo->AS_Data.avoidDECT = MT2063_AVOID_BOTH;
3002 pInfo->ctfilt_sw = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003003
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003004 pInfo->CTFiltMax[0] = 69230000;
3005 pInfo->CTFiltMax[1] = 105770000;
3006 pInfo->CTFiltMax[2] = 140350000;
3007 pInfo->CTFiltMax[3] = 177110000;
3008 pInfo->CTFiltMax[4] = 212860000;
3009 pInfo->CTFiltMax[5] = 241130000;
3010 pInfo->CTFiltMax[6] = 274370000;
3011 pInfo->CTFiltMax[7] = 309820000;
3012 pInfo->CTFiltMax[8] = 342450000;
3013 pInfo->CTFiltMax[9] = 378870000;
3014 pInfo->CTFiltMax[10] = 416210000;
3015 pInfo->CTFiltMax[11] = 456500000;
3016 pInfo->CTFiltMax[12] = 495790000;
3017 pInfo->CTFiltMax[13] = 534530000;
3018 pInfo->CTFiltMax[14] = 572610000;
3019 pInfo->CTFiltMax[15] = 598970000;
3020 pInfo->CTFiltMax[16] = 635910000;
3021 pInfo->CTFiltMax[17] = 672130000;
3022 pInfo->CTFiltMax[18] = 714840000;
3023 pInfo->CTFiltMax[19] = 739660000;
3024 pInfo->CTFiltMax[20] = 770410000;
3025 pInfo->CTFiltMax[21] = 814660000;
3026 pInfo->CTFiltMax[22] = 846950000;
3027 pInfo->CTFiltMax[23] = 867820000;
3028 pInfo->CTFiltMax[24] = 915980000;
3029 pInfo->CTFiltMax[25] = 947450000;
3030 pInfo->CTFiltMax[26] = 983110000;
3031 pInfo->CTFiltMax[27] = 1021630000;
3032 pInfo->CTFiltMax[28] = 1061870000;
3033 pInfo->CTFiltMax[29] = 1098330000;
3034 pInfo->CTFiltMax[30] = 1138990000;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003035
3036 /*
3037 ** Fetch the FCU osc value and use it and the fRef value to
3038 ** scale all of the Band Max values
3039 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003040
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003041 pInfo->reg[MT2063_REG_CTUNE_CTRL] = 0x0A;
3042 status = MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3043 MT2063_REG_CTUNE_CTRL,
3044 &pInfo->reg[MT2063_REG_CTUNE_CTRL], 1);
3045 if (status < 0)
3046 return status;
3047 /* Read the ClearTune filter calibration value */
3048 status = MT2063_ReadSub(pInfo->hUserData, pInfo->address,
3049 MT2063_REG_FIFFC,
3050 &pInfo->reg[MT2063_REG_FIFFC], 1);
3051 if (status < 0)
3052 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003053
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003054 fcu_osc = pInfo->reg[MT2063_REG_FIFFC];
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003055
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003056 pInfo->reg[MT2063_REG_CTUNE_CTRL] = 0x00;
3057 status = MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3058 MT2063_REG_CTUNE_CTRL,
3059 &pInfo->reg[MT2063_REG_CTUNE_CTRL], 1);
3060 if (status < 0)
3061 return status;
3062
3063 /* Adjust each of the values in the ClearTune filter cross-over table */
3064 for (i = 0; i < 31; i++)
3065 pInfo->CTFiltMax[i] =(pInfo->CTFiltMax[i] / 768) * (fcu_osc + 640);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003066
3067 return (status);
3068}
3069
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003070/****************************************************************************
3071**
3072** Name: MT2063_SetParam
3073**
3074** Description: Sets a tuning algorithm parameter.
3075**
3076** This function provides access to the internals of the
3077** tuning algorithm. You can override many of the tuning
3078** algorithm defaults using this function.
3079**
3080** Parameters: h - Tuner handle (returned by MT2063_Open)
3081** param - Tuning algorithm parameter
3082** (see enum MT2063_Param)
3083** nValue - value to be set
3084**
3085** param Description
3086** ---------------------- --------------------------------
3087** MT2063_SRO_FREQ crystal frequency
3088** MT2063_STEPSIZE minimum tuning step size
3089** MT2063_LO1_FREQ LO1 frequency
3090** MT2063_LO1_STEPSIZE LO1 minimum step size
3091** MT2063_LO1_FRACN_AVOID LO1 FracN keep-out region
3092** MT2063_IF1_REQUEST Requested 1st IF
3093** MT2063_ZIF_BW zero-IF bandwidth
3094** MT2063_LO2_FREQ LO2 frequency
3095** MT2063_LO2_STEPSIZE LO2 minimum step size
3096** MT2063_LO2_FRACN_AVOID LO2 FracN keep-out region
3097** MT2063_OUTPUT_FREQ output center frequency
3098** MT2063_OUTPUT_BW output bandwidth
3099** MT2063_LO_SEPARATION min inter-tuner LO separation
3100** MT2063_MAX_HARM1 max # of intra-tuner harmonics
3101** MT2063_MAX_HARM2 max # of inter-tuner harmonics
3102** MT2063_RCVR_MODE Predefined modes
3103** MT2063_LNA_RIN Set LNA Rin (*)
3104** MT2063_LNA_TGT Set target power level at LNA (*)
3105** MT2063_PD1_TGT Set target power level at PD1 (*)
3106** MT2063_PD2_TGT Set target power level at PD2 (*)
3107** MT2063_ACLNA_MAX LNA attenuator limit (*)
3108** MT2063_ACRF_MAX RF attenuator limit (*)
3109** MT2063_ACFIF_MAX FIF attenuator limit (*)
3110** MT2063_DNC_OUTPUT_ENABLE DNC output selection
3111** MT2063_VGAGC VGA gain code
3112** MT2063_VGAOI VGA output current
3113** MT2063_TAGC TAGC setting
3114** MT2063_AMPGC AMP gain code
3115** MT2063_AVOID_DECT Avoid DECT Frequencies
3116** MT2063_CTFILT_SW Cleartune filter selection
3117**
3118** (*) This parameter is set by MT2063_RCVR_MODE, do not call
3119** additionally.
3120**
3121** Usage: status |= MT2063_SetParam(hMT2063,
3122** MT2063_STEPSIZE,
3123** 50000);
3124**
3125** Returns: status:
3126** MT_OK - No errors
3127** MT_INV_HANDLE - Invalid tuner handle
3128** MT_ARG_NULL - Null pointer argument passed
3129** MT_ARG_RANGE - Invalid parameter requested
3130** or set value out of range
3131** or non-writable parameter
3132**
3133** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3134**
3135** See Also: MT2063_GetParam, MT2063_Open
3136**
3137** Revision History:
3138**
3139** SCR Date Author Description
3140** -------------------------------------------------------------------------
3141** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3142** 154 09-13-2007 RSK Ver 1.05: Get/SetParam changes for LOx_FREQ
3143** 10-31-2007 PINZ Ver 1.08: Get/SetParam add VGAGC, VGAOI, AMPGC, TAGC
3144** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
3145** Split SetParam up to ACLNA / ACLNA_MAX
3146** removed ACLNA_INRC/DECR (+RF & FIF)
3147** removed GCUAUTO / BYPATNDN/UP
3148** 175 I 06-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
3149** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
3150** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
3151**
3152****************************************************************************/
Mauro Carvalho Chehab29a0a4f2011-07-20 23:44:10 -03003153static u32 MT2063_SetParam(struct MT2063_Info_t *pInfo,
3154 enum MT2063_Param param,
3155 enum MT2063_DNC_Output_Enable nValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003156{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003157 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003158 u8 val = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003159
3160 /* Verify that the handle passed points to a valid tuner */
3161 if (MT2063_IsValidHandle(pInfo) == 0)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003162 return -ENODEV;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003163
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003164 switch (param) {
3165 /* crystal frequency */
3166 case MT2063_SRO_FREQ:
3167 pInfo->AS_Data.f_ref = nValue;
3168 pInfo->AS_Data.f_LO1_FracN_Avoid = 0;
3169 pInfo->AS_Data.f_LO2_FracN_Avoid = nValue / 80 - 1;
3170 pInfo->AS_Data.f_LO1_Step = nValue / 64;
3171 pInfo->AS_Data.f_if1_Center =
3172 (pInfo->AS_Data.f_ref / 8) *
3173 (pInfo->reg[MT2063_REG_FIFFC] + 640);
3174 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003175
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003176 /* minimum tuning step size */
3177 case MT2063_STEPSIZE:
3178 pInfo->AS_Data.f_LO2_Step = nValue;
3179 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003180
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003181 /* LO1 frequency */
3182 case MT2063_LO1_FREQ:
3183 {
3184 /* Note: LO1 and LO2 are BOTH written at toggle of LDLOos */
3185 /* Capture the Divider and Numerator portions of other LO */
3186 u8 tempLO2CQ[3];
3187 u8 tempLO2C[3];
3188 u8 tmpOneShot;
3189 u32 Div, FracN;
3190 u8 restore = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003191
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003192 /* Buffer the queue for restoration later and get actual LO2 values. */
3193 status |=
3194 MT2063_ReadSub(pInfo->hUserData,
3195 pInfo->address,
3196 MT2063_REG_LO2CQ_1,
3197 &(tempLO2CQ[0]), 3);
3198 status |=
3199 MT2063_ReadSub(pInfo->hUserData,
3200 pInfo->address,
3201 MT2063_REG_LO2C_1,
3202 &(tempLO2C[0]), 3);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003203
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003204 /* clear the one-shot bits */
3205 tempLO2CQ[2] = tempLO2CQ[2] & 0x0F;
3206 tempLO2C[2] = tempLO2C[2] & 0x0F;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003207
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003208 /* only write the queue values if they are different from the actual. */
3209 if ((tempLO2CQ[0] != tempLO2C[0]) ||
3210 (tempLO2CQ[1] != tempLO2C[1]) ||
3211 (tempLO2CQ[2] != tempLO2C[2])) {
3212 /* put actual LO2 value into queue (with 0 in one-shot bits) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003213 status |=
3214 MT2063_WriteSub(pInfo->hUserData,
3215 pInfo->address,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003216 MT2063_REG_LO2CQ_1,
3217 &(tempLO2C[0]), 3);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003218
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003219 if (status == 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003220 /* cache the bytes just written. */
3221 pInfo->reg[MT2063_REG_LO2CQ_1] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003222 tempLO2C[0];
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003223 pInfo->reg[MT2063_REG_LO2CQ_2] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003224 tempLO2C[1];
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003225 pInfo->reg[MT2063_REG_LO2CQ_3] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003226 tempLO2C[2];
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003227 }
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003228 restore = 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003229 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003230
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003231 /* Calculate the Divider and Numberator components of LO1 */
3232 status =
3233 MT2063_CalcLO1Mult(&Div, &FracN, nValue,
3234 pInfo->AS_Data.f_ref /
3235 64,
3236 pInfo->AS_Data.f_ref);
3237 pInfo->reg[MT2063_REG_LO1CQ_1] =
3238 (u8) (Div & 0x00FF);
3239 pInfo->reg[MT2063_REG_LO1CQ_2] =
3240 (u8) (FracN);
3241 status |=
3242 MT2063_WriteSub(pInfo->hUserData,
3243 pInfo->address,
3244 MT2063_REG_LO1CQ_1,
3245 &pInfo->
3246 reg[MT2063_REG_LO1CQ_1], 2);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003247
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003248 /* set the one-shot bit to load the pair of LO values */
3249 tmpOneShot = tempLO2CQ[2] | 0xE0;
3250 status |=
3251 MT2063_WriteSub(pInfo->hUserData,
3252 pInfo->address,
3253 MT2063_REG_LO2CQ_3,
3254 &tmpOneShot, 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003255
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003256 /* only restore the queue values if they were different from the actual. */
3257 if (restore) {
3258 /* put actual LO2 value into queue (0 in one-shot bits) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003259 status |=
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003260 MT2063_WriteSub(pInfo->hUserData,
3261 pInfo->address,
3262 MT2063_REG_LO2CQ_1,
3263 &(tempLO2CQ[0]), 3);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003264
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003265 /* cache the bytes just written. */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003266 pInfo->reg[MT2063_REG_LO2CQ_1] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003267 tempLO2CQ[0];
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003268 pInfo->reg[MT2063_REG_LO2CQ_2] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003269 tempLO2CQ[1];
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003270 pInfo->reg[MT2063_REG_LO2CQ_3] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003271 tempLO2CQ[2];
3272 }
3273
3274 MT2063_GetParam(pInfo->hUserData,
3275 MT2063_LO1_FREQ,
3276 &pInfo->AS_Data.f_LO1);
3277 }
3278 break;
3279
3280 /* LO1 minimum step size */
3281 case MT2063_LO1_STEPSIZE:
3282 pInfo->AS_Data.f_LO1_Step = nValue;
3283 break;
3284
3285 /* LO1 FracN keep-out region */
3286 case MT2063_LO1_FRACN_AVOID_PARAM:
3287 pInfo->AS_Data.f_LO1_FracN_Avoid = nValue;
3288 break;
3289
3290 /* Requested 1st IF */
3291 case MT2063_IF1_REQUEST:
3292 pInfo->AS_Data.f_if1_Request = nValue;
3293 break;
3294
3295 /* zero-IF bandwidth */
3296 case MT2063_ZIF_BW:
3297 pInfo->AS_Data.f_zif_bw = nValue;
3298 break;
3299
3300 /* LO2 frequency */
3301 case MT2063_LO2_FREQ:
3302 {
3303 /* Note: LO1 and LO2 are BOTH written at toggle of LDLOos */
3304 /* Capture the Divider and Numerator portions of other LO */
3305 u8 tempLO1CQ[2];
3306 u8 tempLO1C[2];
3307 u32 Div2;
3308 u32 FracN2;
3309 u8 tmpOneShot;
3310 u8 restore = 0;
3311
3312 /* Buffer the queue for restoration later and get actual LO2 values. */
3313 status |=
3314 MT2063_ReadSub(pInfo->hUserData,
3315 pInfo->address,
3316 MT2063_REG_LO1CQ_1,
3317 &(tempLO1CQ[0]), 2);
3318 status |=
3319 MT2063_ReadSub(pInfo->hUserData,
3320 pInfo->address,
3321 MT2063_REG_LO1C_1,
3322 &(tempLO1C[0]), 2);
3323
3324 /* only write the queue values if they are different from the actual. */
3325 if ((tempLO1CQ[0] != tempLO1C[0])
3326 || (tempLO1CQ[1] != tempLO1C[1])) {
3327 /* put actual LO1 value into queue */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003328 status |=
3329 MT2063_WriteSub(pInfo->hUserData,
3330 pInfo->address,
3331 MT2063_REG_LO1CQ_1,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003332 &(tempLO1C[0]), 2);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003333
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003334 /* cache the bytes just written. */
3335 pInfo->reg[MT2063_REG_LO1CQ_1] =
3336 tempLO1C[0];
3337 pInfo->reg[MT2063_REG_LO1CQ_2] =
3338 tempLO1C[1];
3339 restore = 1;
3340 }
3341
3342 /* Calculate the Divider and Numberator components of LO2 */
3343 status =
3344 MT2063_CalcLO2Mult(&Div2, &FracN2, nValue,
3345 pInfo->AS_Data.f_ref /
3346 8191,
3347 pInfo->AS_Data.f_ref);
3348 pInfo->reg[MT2063_REG_LO2CQ_1] =
3349 (u8) ((Div2 << 1) |
3350 ((FracN2 >> 12) & 0x01)) & 0xFF;
3351 pInfo->reg[MT2063_REG_LO2CQ_2] =
3352 (u8) ((FracN2 >> 4) & 0xFF);
3353 pInfo->reg[MT2063_REG_LO2CQ_3] =
3354 (u8) ((FracN2 & 0x0F));
3355 status |=
3356 MT2063_WriteSub(pInfo->hUserData,
3357 pInfo->address,
3358 MT2063_REG_LO1CQ_1,
3359 &pInfo->
3360 reg[MT2063_REG_LO1CQ_1], 3);
3361
3362 /* set the one-shot bit to load the LO values */
3363 tmpOneShot =
3364 pInfo->reg[MT2063_REG_LO2CQ_3] | 0xE0;
3365 status |=
3366 MT2063_WriteSub(pInfo->hUserData,
3367 pInfo->address,
3368 MT2063_REG_LO2CQ_3,
3369 &tmpOneShot, 1);
3370
3371 /* only restore LO1 queue value if they were different from the actual. */
3372 if (restore) {
3373 /* put previous LO1 queue value back into queue */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003374 status |=
3375 MT2063_WriteSub(pInfo->hUserData,
3376 pInfo->address,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003377 MT2063_REG_LO1CQ_1,
3378 &(tempLO1CQ[0]), 2);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003379
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003380 /* cache the bytes just written. */
3381 pInfo->reg[MT2063_REG_LO1CQ_1] =
3382 tempLO1CQ[0];
3383 pInfo->reg[MT2063_REG_LO1CQ_2] =
3384 tempLO1CQ[1];
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003385 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003386
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003387 MT2063_GetParam(pInfo->hUserData,
3388 MT2063_LO2_FREQ,
3389 &pInfo->AS_Data.f_LO2);
3390 }
3391 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003392
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003393 /* LO2 minimum step size */
3394 case MT2063_LO2_STEPSIZE:
3395 pInfo->AS_Data.f_LO2_Step = nValue;
3396 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003397
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003398 /* LO2 FracN keep-out region */
3399 case MT2063_LO2_FRACN_AVOID:
3400 pInfo->AS_Data.f_LO2_FracN_Avoid = nValue;
3401 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003402
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003403 /* output center frequency */
3404 case MT2063_OUTPUT_FREQ:
3405 pInfo->AS_Data.f_out = nValue;
3406 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003407
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003408 /* output bandwidth */
3409 case MT2063_OUTPUT_BW:
3410 pInfo->AS_Data.f_out_bw = nValue + 750000;
3411 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003412
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003413 /* min inter-tuner LO separation */
3414 case MT2063_LO_SEPARATION:
3415 pInfo->AS_Data.f_min_LO_Separation = nValue;
3416 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003417
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003418 /* max # of intra-tuner harmonics */
3419 case MT2063_MAX_HARM1:
3420 pInfo->AS_Data.maxH1 = nValue;
3421 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003422
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003423 /* max # of inter-tuner harmonics */
3424 case MT2063_MAX_HARM2:
3425 pInfo->AS_Data.maxH2 = nValue;
3426 break;
3427
3428 case MT2063_RCVR_MODE:
3429 status |=
3430 MT2063_SetReceiverMode(pInfo,
3431 (enum MT2063_RCVR_MODES)
3432 nValue);
3433 break;
3434
3435 /* Set LNA Rin -- nValue is desired value */
3436 case MT2063_LNA_RIN:
3437 val =
3438 (pInfo->
3439 reg[MT2063_REG_CTRL_2C] & (u8) ~ 0x03) |
3440 (nValue & 0x03);
3441 if (pInfo->reg[MT2063_REG_CTRL_2C] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003442 status |=
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003443 MT2063_SetReg(pInfo, MT2063_REG_CTRL_2C,
3444 val);
3445 }
3446 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003447
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003448 /* Set target power level at LNA -- nValue is desired value */
3449 case MT2063_LNA_TGT:
3450 val =
3451 (pInfo->
3452 reg[MT2063_REG_LNA_TGT] & (u8) ~ 0x3F) |
3453 (nValue & 0x3F);
3454 if (pInfo->reg[MT2063_REG_LNA_TGT] != val) {
3455 status |=
3456 MT2063_SetReg(pInfo, MT2063_REG_LNA_TGT,
3457 val);
3458 }
3459 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003460
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003461 /* Set target power level at PD1 -- nValue is desired value */
3462 case MT2063_PD1_TGT:
3463 val =
3464 (pInfo->
3465 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x3F) |
3466 (nValue & 0x3F);
3467 if (pInfo->reg[MT2063_REG_PD1_TGT] != val) {
3468 status |=
3469 MT2063_SetReg(pInfo, MT2063_REG_PD1_TGT,
3470 val);
3471 }
3472 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003473
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003474 /* Set target power level at PD2 -- nValue is desired value */
3475 case MT2063_PD2_TGT:
3476 val =
3477 (pInfo->
3478 reg[MT2063_REG_PD2_TGT] & (u8) ~ 0x3F) |
3479 (nValue & 0x3F);
3480 if (pInfo->reg[MT2063_REG_PD2_TGT] != val) {
3481 status |=
3482 MT2063_SetReg(pInfo, MT2063_REG_PD2_TGT,
3483 val);
3484 }
3485 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003486
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003487 /* Set LNA atten limit -- nValue is desired value */
3488 case MT2063_ACLNA_MAX:
3489 val =
3490 (pInfo->
3491 reg[MT2063_REG_LNA_OV] & (u8) ~ 0x1F) | (nValue
3492 &
3493 0x1F);
3494 if (pInfo->reg[MT2063_REG_LNA_OV] != val) {
3495 status |=
3496 MT2063_SetReg(pInfo, MT2063_REG_LNA_OV,
3497 val);
3498 }
3499 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003500
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003501 /* Set RF atten limit -- nValue is desired value */
3502 case MT2063_ACRF_MAX:
3503 val =
3504 (pInfo->
3505 reg[MT2063_REG_RF_OV] & (u8) ~ 0x1F) | (nValue
3506 &
3507 0x1F);
3508 if (pInfo->reg[MT2063_REG_RF_OV] != val) {
3509 status |=
3510 MT2063_SetReg(pInfo, MT2063_REG_RF_OV, val);
3511 }
3512 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003513
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003514 /* Set FIF atten limit -- nValue is desired value, max. 5 if no B3 */
3515 case MT2063_ACFIF_MAX:
3516 if (pInfo->reg[MT2063_REG_PART_REV] != MT2063_B3
3517 && nValue > 5)
3518 nValue = 5;
3519 val =
3520 (pInfo->
3521 reg[MT2063_REG_FIF_OV] & (u8) ~ 0x1F) | (nValue
3522 &
3523 0x1F);
3524 if (pInfo->reg[MT2063_REG_FIF_OV] != val) {
3525 status |=
3526 MT2063_SetReg(pInfo, MT2063_REG_FIF_OV,
3527 val);
3528 }
3529 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003530
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003531 case MT2063_DNC_OUTPUT_ENABLE:
3532 /* selects, which DNC output is used */
Mauro Carvalho Chehab29a0a4f2011-07-20 23:44:10 -03003533 switch (nValue) {
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003534 case MT2063_DNC_NONE:
3535 {
3536 val = (pInfo->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
3537 if (pInfo->reg[MT2063_REG_DNC_GAIN] !=
3538 val)
3539 status |=
3540 MT2063_SetReg(pInfo,
3541 MT2063_REG_DNC_GAIN,
3542 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003543
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003544 val = (pInfo->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
3545 if (pInfo->reg[MT2063_REG_VGA_GAIN] !=
3546 val)
3547 status |=
3548 MT2063_SetReg(pInfo,
3549 MT2063_REG_VGA_GAIN,
3550 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003551
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003552 val = (pInfo->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
3553 if (pInfo->reg[MT2063_REG_RSVD_20] !=
3554 val)
3555 status |=
3556 MT2063_SetReg(pInfo,
3557 MT2063_REG_RSVD_20,
3558 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003559
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003560 break;
3561 }
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003562 case MT2063_DNC_1:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003563 {
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003564 val = (pInfo->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[pInfo->rcvr_mode] & 0x03); /* Set DNC1GC=x */
3565 if (pInfo->reg[MT2063_REG_DNC_GAIN] !=
3566 val)
3567 status |=
3568 MT2063_SetReg(pInfo,
3569 MT2063_REG_DNC_GAIN,
3570 val);
3571
3572 val = (pInfo->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
3573 if (pInfo->reg[MT2063_REG_VGA_GAIN] !=
3574 val)
3575 status |=
3576 MT2063_SetReg(pInfo,
3577 MT2063_REG_VGA_GAIN,
3578 val);
3579
3580 val = (pInfo->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
3581 if (pInfo->reg[MT2063_REG_RSVD_20] !=
3582 val)
3583 status |=
3584 MT2063_SetReg(pInfo,
3585 MT2063_REG_RSVD_20,
3586 val);
3587
3588 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003589 }
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003590 case MT2063_DNC_2:
3591 {
3592 val = (pInfo->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
3593 if (pInfo->reg[MT2063_REG_DNC_GAIN] !=
3594 val)
3595 status |=
3596 MT2063_SetReg(pInfo,
3597 MT2063_REG_DNC_GAIN,
3598 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003599
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003600 val = (pInfo->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[pInfo->rcvr_mode] & 0x03); /* Set DNC2GC=x */
3601 if (pInfo->reg[MT2063_REG_VGA_GAIN] !=
3602 val)
3603 status |=
3604 MT2063_SetReg(pInfo,
3605 MT2063_REG_VGA_GAIN,
3606 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003607
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003608 val = (pInfo->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
3609 if (pInfo->reg[MT2063_REG_RSVD_20] !=
3610 val)
3611 status |=
3612 MT2063_SetReg(pInfo,
3613 MT2063_REG_RSVD_20,
3614 val);
3615
3616 break;
3617 }
3618 case MT2063_DNC_BOTH:
3619 {
3620 val = (pInfo->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[pInfo->rcvr_mode] & 0x03); /* Set DNC1GC=x */
3621 if (pInfo->reg[MT2063_REG_DNC_GAIN] !=
3622 val)
3623 status |=
3624 MT2063_SetReg(pInfo,
3625 MT2063_REG_DNC_GAIN,
3626 val);
3627
3628 val = (pInfo->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[pInfo->rcvr_mode] & 0x03); /* Set DNC2GC=x */
3629 if (pInfo->reg[MT2063_REG_VGA_GAIN] !=
3630 val)
3631 status |=
3632 MT2063_SetReg(pInfo,
3633 MT2063_REG_VGA_GAIN,
3634 val);
3635
3636 val = (pInfo->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
3637 if (pInfo->reg[MT2063_REG_RSVD_20] !=
3638 val)
3639 status |=
3640 MT2063_SetReg(pInfo,
3641 MT2063_REG_RSVD_20,
3642 val);
3643
3644 break;
3645 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003646 default:
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003647 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003648 }
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003649 break;
3650
3651 case MT2063_VGAGC:
3652 /* Set VGA gain code */
3653 val =
3654 (pInfo->
3655 reg[MT2063_REG_VGA_GAIN] & (u8) ~ 0x0C) |
3656 ((nValue & 0x03) << 2);
3657 if (pInfo->reg[MT2063_REG_VGA_GAIN] != val) {
3658 status |=
3659 MT2063_SetReg(pInfo, MT2063_REG_VGA_GAIN,
3660 val);
3661 }
3662 break;
3663
3664 case MT2063_VGAOI:
3665 /* Set VGA bias current */
3666 val =
3667 (pInfo->
3668 reg[MT2063_REG_RSVD_31] & (u8) ~ 0x07) |
3669 (nValue & 0x07);
3670 if (pInfo->reg[MT2063_REG_RSVD_31] != val) {
3671 status |=
3672 MT2063_SetReg(pInfo, MT2063_REG_RSVD_31,
3673 val);
3674 }
3675 break;
3676
3677 case MT2063_TAGC:
3678 /* Set TAGC */
3679 val =
3680 (pInfo->
3681 reg[MT2063_REG_RSVD_1E] & (u8) ~ 0x03) |
3682 (nValue & 0x03);
3683 if (pInfo->reg[MT2063_REG_RSVD_1E] != val) {
3684 status |=
3685 MT2063_SetReg(pInfo, MT2063_REG_RSVD_1E,
3686 val);
3687 }
3688 break;
3689
3690 case MT2063_AMPGC:
3691 /* Set Amp gain code */
3692 val =
3693 (pInfo->
3694 reg[MT2063_REG_TEMP_SEL] & (u8) ~ 0x03) |
3695 (nValue & 0x03);
3696 if (pInfo->reg[MT2063_REG_TEMP_SEL] != val) {
3697 status |=
3698 MT2063_SetReg(pInfo, MT2063_REG_TEMP_SEL,
3699 val);
3700 }
3701 break;
3702
3703 /* Avoid DECT Frequencies */
3704 case MT2063_AVOID_DECT:
3705 {
3706 enum MT2063_DECT_Avoid_Type newAvoidSetting =
3707 (enum MT2063_DECT_Avoid_Type)nValue;
3708 if ((newAvoidSetting >=
3709 MT2063_NO_DECT_AVOIDANCE)
3710 && (newAvoidSetting <= MT2063_AVOID_BOTH)) {
3711 pInfo->AS_Data.avoidDECT =
3712 newAvoidSetting;
3713 }
3714 }
3715 break;
3716
3717 /* Cleartune filter selection: 0 - by IC (default), 1 - by software */
3718 case MT2063_CTFILT_SW:
3719 pInfo->ctfilt_sw = (nValue & 0x01);
3720 break;
3721
3722 /* These parameters are read-only */
3723 case MT2063_IC_ADDR:
3724 case MT2063_MAX_OPEN:
3725 case MT2063_NUM_OPEN:
3726 case MT2063_INPUT_FREQ:
3727 case MT2063_IF1_ACTUAL:
3728 case MT2063_IF1_CENTER:
3729 case MT2063_IF1_BW:
3730 case MT2063_AS_ALG:
3731 case MT2063_EXCL_ZONES:
3732 case MT2063_SPUR_AVOIDED:
3733 case MT2063_NUM_SPURS:
3734 case MT2063_SPUR_PRESENT:
3735 case MT2063_ACLNA:
3736 case MT2063_ACRF:
3737 case MT2063_ACFIF:
3738 case MT2063_EOP:
3739 default:
3740 status |= -ERANGE;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003741 }
3742 return (status);
3743}
3744
3745/****************************************************************************
3746**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003747** Name: MT2063_ClearPowerMaskBits
3748**
3749** Description: Clears the power-down mask bits for various sections of
3750** the MT2063
3751**
3752** Parameters: h - Tuner handle (returned by MT2063_Open)
3753** Bits - Mask bits to be cleared.
3754**
3755** See definition of MT2063_Mask_Bits type for description
3756** of each of the power bits.
3757**
3758** Returns: status:
3759** MT_OK - No errors
3760** MT_INV_HANDLE - Invalid tuner handle
3761** MT_COMM_ERR - Serial bus communications error
3762**
3763** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3764**
3765** Revision History:
3766**
3767** SCR Date Author Description
3768** -------------------------------------------------------------------------
3769** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3770**
3771****************************************************************************/
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -03003772static u32 MT2063_ClearPowerMaskBits(struct MT2063_Info_t *pInfo, enum MT2063_Mask_Bits Bits)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003773{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003774 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003775
3776 /* Verify that the handle passed points to a valid tuner */
3777 if (MT2063_IsValidHandle(pInfo) == 0)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003778 return -ENODEV;
3779 Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */
3780 if ((Bits & 0xFF00) != 0) {
3781 pInfo->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8);
3782 status |=
3783 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3784 MT2063_REG_PWR_2,
3785 &pInfo->reg[MT2063_REG_PWR_2], 1);
3786 }
3787 if ((Bits & 0xFF) != 0) {
3788 pInfo->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF);
3789 status |=
3790 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3791 MT2063_REG_PWR_1,
3792 &pInfo->reg[MT2063_REG_PWR_1], 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003793 }
3794
3795 return (status);
3796}
3797
3798/****************************************************************************
3799**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003800** Name: MT2063_SoftwareShutdown
3801**
3802** Description: Enables or disables software shutdown function. When
3803** Shutdown==1, any section whose power mask is set will be
3804** shutdown.
3805**
3806** Parameters: h - Tuner handle (returned by MT2063_Open)
3807** Shutdown - 1 = shutdown the masked sections, otherwise
3808** power all sections on
3809**
3810** Returns: status:
3811** MT_OK - No errors
3812** MT_INV_HANDLE - Invalid tuner handle
3813** MT_COMM_ERR - Serial bus communications error
3814**
3815** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3816**
3817** Revision History:
3818**
3819** SCR Date Author Description
3820** -------------------------------------------------------------------------
3821** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3822** 01-03-2008 PINZ Ver 1.xx: Added a trigger of BYPATNUP for
3823** correct wakeup of the LNA
3824**
3825****************************************************************************/
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -03003826static u32 MT2063_SoftwareShutdown(struct MT2063_Info_t *pInfo, u8 Shutdown)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003827{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003828 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003829
3830 /* Verify that the handle passed points to a valid tuner */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003831 if (MT2063_IsValidHandle(pInfo) == 0)
3832 return -ENODEV;
3833 if (Shutdown == 1)
3834 pInfo->reg[MT2063_REG_PWR_1] |= 0x04; /* Turn the bit on */
3835 else
3836 pInfo->reg[MT2063_REG_PWR_1] &= ~0x04; /* Turn off the bit */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003837
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003838 status |=
3839 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3840 MT2063_REG_PWR_1,
3841 &pInfo->reg[MT2063_REG_PWR_1], 1);
3842
3843 if (Shutdown != 1) {
3844 pInfo->reg[MT2063_REG_BYP_CTRL] =
3845 (pInfo->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003846 status |=
3847 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003848 MT2063_REG_BYP_CTRL,
3849 &pInfo->reg[MT2063_REG_BYP_CTRL],
3850 1);
3851 pInfo->reg[MT2063_REG_BYP_CTRL] =
3852 (pInfo->reg[MT2063_REG_BYP_CTRL] & 0x9F);
3853 status |=
3854 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3855 MT2063_REG_BYP_CTRL,
3856 &pInfo->reg[MT2063_REG_BYP_CTRL],
3857 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003858 }
3859
3860 return (status);
3861}
3862
3863/****************************************************************************
3864**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003865** Name: MT2063_SetReg
3866**
3867** Description: Sets an MT2063 register.
3868**
3869** Parameters: h - Tuner handle (returned by MT2063_Open)
3870** reg - MT2063 register/subaddress location
3871** val - MT2063 register/subaddress value
3872**
3873** Returns: status:
3874** MT_OK - No errors
3875** MT_COMM_ERR - Serial bus communications error
3876** MT_INV_HANDLE - Invalid tuner handle
3877** MT_ARG_RANGE - Argument out of range
3878**
3879** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3880**
3881** Use this function if you need to override a default
3882** register value
3883**
3884** Revision History:
3885**
3886** SCR Date Author Description
3887** -------------------------------------------------------------------------
3888** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3889**
3890****************************************************************************/
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003891static u32 MT2063_SetReg(struct MT2063_Info_t *pInfo, u8 reg, u8 val)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003892{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003893 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003894
3895 /* Verify that the handle passed points to a valid tuner */
3896 if (MT2063_IsValidHandle(pInfo) == 0)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003897 return -ENODEV;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003898
3899 if (reg >= MT2063_REG_END_REGS)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003900 status |= -ERANGE;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003901
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003902 status = MT2063_WriteSub(pInfo->hUserData, pInfo->address, reg, &val,
3903 1);
3904 if (status >= 0)
3905 pInfo->reg[reg] = val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003906
3907 return (status);
3908}
3909
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003910static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003911{
3912 return f_ref * (f_LO / f_ref)
3913 + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step);
3914}
3915
3916/****************************************************************************
3917**
3918** Name: fLO_FractionalTerm
3919**
3920** Description: Calculates the portion contributed by FracN / denom.
3921**
3922** This function preserves maximum precision without
3923** risk of overflow. It accurately calculates
3924** f_ref * num / denom to within 1 HZ with fixed math.
3925**
3926** Parameters: num - Fractional portion of the multiplier
3927** denom - denominator portion of the ratio
3928** This routine successfully handles denom values
3929** up to and including 2^18.
3930** f_Ref - SRO frequency. This calculation handles
3931** f_ref as two separate 14-bit fields.
3932** Therefore, a maximum value of 2^28-1
3933** may safely be used for f_ref. This is
3934** the genesis of the magic number "14" and the
3935** magic mask value of 0x03FFF.
3936**
3937** Returns: f_ref * num / denom
3938**
3939** Revision History:
3940**
3941** SCR Date Author Description
3942** -------------------------------------------------------------------------
3943** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3944**
3945****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003946static u32 MT2063_fLO_FractionalTerm(u32 f_ref,
3947 u32 num, u32 denom)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003948{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003949 u32 t1 = (f_ref >> 14) * num;
3950 u32 term1 = t1 / denom;
3951 u32 loss = t1 % denom;
3952 u32 term2 =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003953 (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom;
3954 return ((term1 << 14) + term2);
3955}
3956
3957/****************************************************************************
3958**
3959** Name: CalcLO1Mult
3960**
3961** Description: Calculates Integer divider value and the numerator
3962** value for a FracN PLL.
3963**
3964** This function assumes that the f_LO and f_Ref are
3965** evenly divisible by f_LO_Step.
3966**
3967** Parameters: Div - OUTPUT: Whole number portion of the multiplier
3968** FracN - OUTPUT: Fractional portion of the multiplier
3969** f_LO - desired LO frequency.
3970** f_LO_Step - Minimum step size for the LO (in Hz).
3971** f_Ref - SRO frequency.
3972** f_Avoid - Range of PLL frequencies to avoid near
3973** integer multiples of f_Ref (in Hz).
3974**
3975** Returns: Recalculated LO frequency.
3976**
3977** Revision History:
3978**
3979** SCR Date Author Description
3980** -------------------------------------------------------------------------
3981** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3982**
3983****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003984static u32 MT2063_CalcLO1Mult(u32 * Div,
3985 u32 * FracN,
3986 u32 f_LO,
3987 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003988{
3989 /* Calculate the whole number portion of the divider */
3990 *Div = f_LO / f_Ref;
3991
3992 /* Calculate the numerator value (round to nearest f_LO_Step) */
3993 *FracN =
3994 (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
3995 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
3996
3997 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64);
3998}
3999
4000/****************************************************************************
4001**
4002** Name: CalcLO2Mult
4003**
4004** Description: Calculates Integer divider value and the numerator
4005** value for a FracN PLL.
4006**
4007** This function assumes that the f_LO and f_Ref are
4008** evenly divisible by f_LO_Step.
4009**
4010** Parameters: Div - OUTPUT: Whole number portion of the multiplier
4011** FracN - OUTPUT: Fractional portion of the multiplier
4012** f_LO - desired LO frequency.
4013** f_LO_Step - Minimum step size for the LO (in Hz).
4014** f_Ref - SRO frequency.
4015** f_Avoid - Range of PLL frequencies to avoid near
4016** integer multiples of f_Ref (in Hz).
4017**
4018** Returns: Recalculated LO frequency.
4019**
4020** Revision History:
4021**
4022** SCR Date Author Description
4023** -------------------------------------------------------------------------
4024** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
4025**
4026****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004027static u32 MT2063_CalcLO2Mult(u32 * Div,
4028 u32 * FracN,
4029 u32 f_LO,
4030 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004031{
4032 /* Calculate the whole number portion of the divider */
4033 *Div = f_LO / f_Ref;
4034
4035 /* Calculate the numerator value (round to nearest f_LO_Step) */
4036 *FracN =
4037 (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
4038 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
4039
4040 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN,
4041 8191);
4042}
4043
4044/****************************************************************************
4045**
4046** Name: FindClearTuneFilter
4047**
4048** Description: Calculate the corrrect ClearTune filter to be used for
4049** a given input frequency.
4050**
4051** Parameters: pInfo - ptr to tuner data structure
4052** f_in - RF input center frequency (in Hz).
4053**
4054** Returns: ClearTune filter number (0-31)
4055**
4056** Dependencies: MUST CALL MT2064_Open BEFORE FindClearTuneFilter!
4057**
4058** Revision History:
4059**
4060** SCR Date Author Description
4061** -------------------------------------------------------------------------
4062** 04-10-2008 PINZ Ver 1.14: Use software-controlled ClearTune
4063** cross-over frequency values.
4064**
4065****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004066static u32 FindClearTuneFilter(struct MT2063_Info_t *pInfo, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004067{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004068 u32 RFBand;
4069 u32 idx; /* index loop */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004070
4071 /*
4072 ** Find RF Band setting
4073 */
4074 RFBand = 31; /* def when f_in > all */
4075 for (idx = 0; idx < 31; ++idx) {
4076 if (pInfo->CTFiltMax[idx] >= f_in) {
4077 RFBand = idx;
4078 break;
4079 }
4080 }
4081 return (RFBand);
4082}
4083
4084/****************************************************************************
4085**
4086** Name: MT2063_Tune
4087**
4088** Description: Change the tuner's tuned frequency to RFin.
4089**
4090** Parameters: h - Open handle to the tuner (from MT2063_Open).
4091** f_in - RF input center frequency (in Hz).
4092**
4093** Returns: status:
4094** MT_OK - No errors
4095** MT_INV_HANDLE - Invalid tuner handle
4096** MT_UPC_UNLOCK - Upconverter PLL unlocked
4097** MT_DNC_UNLOCK - Downconverter PLL unlocked
4098** MT_COMM_ERR - Serial bus communications error
4099** MT_SPUR_CNT_MASK - Count of avoided LO spurs
4100** MT_SPUR_PRESENT - LO spur possible in output
4101** MT_FIN_RANGE - Input freq out of range
4102** MT_FOUT_RANGE - Output freq out of range
4103** MT_UPC_RANGE - Upconverter freq out of range
4104** MT_DNC_RANGE - Downconverter freq out of range
4105**
4106** Dependencies: MUST CALL MT2063_Open BEFORE MT2063_Tune!
4107**
4108** MT_ReadSub - Read data from the two-wire serial bus
4109** MT_WriteSub - Write data to the two-wire serial bus
4110** MT_Sleep - Delay execution for x milliseconds
4111** MT2063_GetLocked - Checks to see if LO1 and LO2 are locked
4112**
4113** Revision History:
4114**
4115** SCR Date Author Description
4116** -------------------------------------------------------------------------
4117** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
4118** 04-10-2008 PINZ Ver 1.05: Use software-controlled ClearTune
4119** cross-over frequency values.
4120** 175 I 16-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
4121** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
4122** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
4123**
4124****************************************************************************/
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03004125static u32 MT2063_Tune(struct MT2063_Info_t *pInfo, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004126{ /* RF input center frequency */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004127
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03004128 u32 status = 0; /* status of operation */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004129 u32 LO1; /* 1st LO register value */
4130 u32 Num1; /* Numerator for LO1 reg. value */
4131 u32 f_IF1; /* 1st IF requested */
4132 u32 LO2; /* 2nd LO register value */
4133 u32 Num2; /* Numerator for LO2 reg. value */
4134 u32 ofLO1, ofLO2; /* last time's LO frequencies */
4135 u32 ofin, ofout; /* last time's I/O frequencies */
4136 u8 fiffc = 0x80; /* FIFF center freq from tuner */
4137 u32 fiffof; /* Offset from FIFF center freq */
4138 const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */
4139 u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */
4140 u8 val;
4141 u32 RFBand;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004142
4143 /* Verify that the handle passed points to a valid tuner */
4144 if (MT2063_IsValidHandle(pInfo) == 0)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03004145 return -ENODEV;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004146
4147 /* Check the input and output frequency ranges */
4148 if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ))
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03004149 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004150
4151 if ((pInfo->AS_Data.f_out < MT2063_MIN_FOUT_FREQ)
4152 || (pInfo->AS_Data.f_out > MT2063_MAX_FOUT_FREQ))
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03004153 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004154
4155 /*
4156 ** Save original LO1 and LO2 register values
4157 */
4158 ofLO1 = pInfo->AS_Data.f_LO1;
4159 ofLO2 = pInfo->AS_Data.f_LO2;
4160 ofin = pInfo->AS_Data.f_in;
4161 ofout = pInfo->AS_Data.f_out;
4162
4163 /*
4164 ** Find and set RF Band setting
4165 */
4166 if (pInfo->ctfilt_sw == 1) {
4167 val = (pInfo->reg[MT2063_REG_CTUNE_CTRL] | 0x08);
4168 if (pInfo->reg[MT2063_REG_CTUNE_CTRL] != val) {
4169 status |=
4170 MT2063_SetReg(pInfo, MT2063_REG_CTUNE_CTRL, val);
4171 }
4172 val = pInfo->reg[MT2063_REG_CTUNE_OV];
4173 RFBand = FindClearTuneFilter(pInfo, f_in);
4174 pInfo->reg[MT2063_REG_CTUNE_OV] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004175 (u8) ((pInfo->reg[MT2063_REG_CTUNE_OV] & ~0x1F)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004176 | RFBand);
4177 if (pInfo->reg[MT2063_REG_CTUNE_OV] != val) {
4178 status |=
4179 MT2063_SetReg(pInfo, MT2063_REG_CTUNE_OV, val);
4180 }
4181 }
4182
4183 /*
4184 ** Read the FIFF Center Frequency from the tuner
4185 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03004186 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004187 status |=
4188 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
4189 MT2063_REG_FIFFC,
4190 &pInfo->reg[MT2063_REG_FIFFC], 1);
4191 fiffc = pInfo->reg[MT2063_REG_FIFFC];
4192 }
4193 /*
4194 ** Assign in the requested values
4195 */
4196 pInfo->AS_Data.f_in = f_in;
4197 /* Request a 1st IF such that LO1 is on a step size */
4198 pInfo->AS_Data.f_if1_Request =
4199 MT2063_Round_fLO(pInfo->AS_Data.f_if1_Request + f_in,
4200 pInfo->AS_Data.f_LO1_Step,
4201 pInfo->AS_Data.f_ref) - f_in;
4202
4203 /*
4204 ** Calculate frequency settings. f_IF1_FREQ + f_in is the
4205 ** desired LO1 frequency
4206 */
4207 MT2063_ResetExclZones(&pInfo->AS_Data);
4208
4209 f_IF1 = MT2063_ChooseFirstIF(&pInfo->AS_Data);
4210
4211 pInfo->AS_Data.f_LO1 =
4212 MT2063_Round_fLO(f_IF1 + f_in, pInfo->AS_Data.f_LO1_Step,
4213 pInfo->AS_Data.f_ref);
4214
4215 pInfo->AS_Data.f_LO2 =
4216 MT2063_Round_fLO(pInfo->AS_Data.f_LO1 - pInfo->AS_Data.f_out - f_in,
4217 pInfo->AS_Data.f_LO2_Step, pInfo->AS_Data.f_ref);
4218
4219 /*
4220 ** Check for any LO spurs in the output bandwidth and adjust
4221 ** the LO settings to avoid them if needed
4222 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03004223 status |= MT2063_AvoidSpurs(pInfo, &pInfo->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004224 /*
4225 ** MT_AvoidSpurs spurs may have changed the LO1 & LO2 values.
4226 ** Recalculate the LO frequencies and the values to be placed
4227 ** in the tuning registers.
4228 */
4229 pInfo->AS_Data.f_LO1 =
4230 MT2063_CalcLO1Mult(&LO1, &Num1, pInfo->AS_Data.f_LO1,
4231 pInfo->AS_Data.f_LO1_Step, pInfo->AS_Data.f_ref);
4232 pInfo->AS_Data.f_LO2 =
4233 MT2063_Round_fLO(pInfo->AS_Data.f_LO1 - pInfo->AS_Data.f_out - f_in,
4234 pInfo->AS_Data.f_LO2_Step, pInfo->AS_Data.f_ref);
4235 pInfo->AS_Data.f_LO2 =
4236 MT2063_CalcLO2Mult(&LO2, &Num2, pInfo->AS_Data.f_LO2,
4237 pInfo->AS_Data.f_LO2_Step, pInfo->AS_Data.f_ref);
4238
4239 /*
4240 ** Check the upconverter and downconverter frequency ranges
4241 */
4242 if ((pInfo->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ)
4243 || (pInfo->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ))
4244 status |= MT2063_UPC_RANGE;
4245 if ((pInfo->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ)
4246 || (pInfo->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ))
4247 status |= MT2063_DNC_RANGE;
4248 /* LO2 Lock bit was in a different place for B0 version */
4249 if (pInfo->tuner_id == MT2063_B0)
4250 LO2LK = 0x40;
4251
4252 /*
4253 ** If we have the same LO frequencies and we're already locked,
4254 ** then skip re-programming the LO registers.
4255 */
4256 if ((ofLO1 != pInfo->AS_Data.f_LO1)
4257 || (ofLO2 != pInfo->AS_Data.f_LO2)
4258 || ((pInfo->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) !=
4259 (LO1LK | LO2LK))) {
4260 /*
4261 ** Calculate the FIFFOF register value
4262 **
4263 ** IF1_Actual
4264 ** FIFFOF = ------------ - 8 * FIFFC - 4992
4265 ** f_ref/64
4266 */
4267 fiffof =
4268 (pInfo->AS_Data.f_LO1 -
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004269 f_in) / (pInfo->AS_Data.f_ref / 64) - 8 * (u32) fiffc -
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004270 4992;
4271 if (fiffof > 0xFF)
4272 fiffof = 0xFF;
4273
4274 /*
4275 ** Place all of the calculated values into the local tuner
4276 ** register fields.
4277 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03004278 if (status >= 0) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004279 pInfo->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */
4280 pInfo->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */
4281 pInfo->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004282 |(Num2 >> 12)); /* NUM2q (hi) */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004283 pInfo->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */
4284 pInfo->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004285
4286 /*
4287 ** Now write out the computed register values
4288 ** IMPORTANT: There is a required order for writing
4289 ** (0x05 must follow all the others).
4290 */
4291 status |= MT2063_WriteSub(pInfo->hUserData, pInfo->address, MT2063_REG_LO1CQ_1, &pInfo->reg[MT2063_REG_LO1CQ_1], 5); /* 0x01 - 0x05 */
4292 if (pInfo->tuner_id == MT2063_B0) {
4293 /* Re-write the one-shot bits to trigger the tune operation */
4294 status |= MT2063_WriteSub(pInfo->hUserData, pInfo->address, MT2063_REG_LO2CQ_3, &pInfo->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */
4295 }
4296 /* Write out the FIFF offset only if it's changing */
4297 if (pInfo->reg[MT2063_REG_FIFF_OFFSET] !=
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004298 (u8) fiffof) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004299 pInfo->reg[MT2063_REG_FIFF_OFFSET] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004300 (u8) fiffof;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004301 status |=
4302 MT2063_WriteSub(pInfo->hUserData,
4303 pInfo->address,
4304 MT2063_REG_FIFF_OFFSET,
4305 &pInfo->
4306 reg[MT2063_REG_FIFF_OFFSET],
4307 1);
4308 }
4309 }
4310
4311 /*
4312 ** Check for LO's locking
4313 */
4314
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03004315 if (status >= 0) {
4316 status |= MT2063_GetLocked(pInfo);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004317 }
4318 /*
4319 ** If we locked OK, assign calculated data to MT2063_Info_t structure
4320 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03004321 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004322 pInfo->f_IF1_actual = pInfo->AS_Data.f_LO1 - f_in;
4323 }
4324 }
4325
4326 return (status);
4327}
4328
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03004329static u32 MT_Tune_atv(void *h, u32 f_in, u32 bw_in,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004330 enum MTTune_atv_standard tv_type)
4331{
4332
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03004333 u32 status = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004334
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004335 s32 pict_car = 0;
4336 s32 pict2chanb_vsb = 0;
4337 s32 pict2chanb_snd = 0;
4338 s32 pict2snd1 = 0;
4339 s32 pict2snd2 = 0;
4340 s32 ch_bw = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004341
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004342 s32 if_mid = 0;
4343 s32 rcvr_mode = 0;
4344 u32 mode_get = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004345
4346 switch (tv_type) {
4347 case MTTUNEA_PAL_B:{
4348 pict_car = 38900000;
4349 ch_bw = 8000000;
4350 pict2chanb_vsb = -1250000;
4351 pict2snd1 = 5500000;
4352 pict2snd2 = 5742000;
4353 rcvr_mode = 1;
4354 break;
4355 }
4356 case MTTUNEA_PAL_G:{
4357 pict_car = 38900000;
4358 ch_bw = 7000000;
4359 pict2chanb_vsb = -1250000;
4360 pict2snd1 = 5500000;
4361 pict2snd2 = 0;
4362 rcvr_mode = 1;
4363 break;
4364 }
4365 case MTTUNEA_PAL_I:{
4366 pict_car = 38900000;
4367 ch_bw = 8000000;
4368 pict2chanb_vsb = -1250000;
4369 pict2snd1 = 6000000;
4370 pict2snd2 = 0;
4371 rcvr_mode = 1;
4372 break;
4373 }
4374 case MTTUNEA_PAL_L:{
4375 pict_car = 38900000;
4376 ch_bw = 8000000;
4377 pict2chanb_vsb = -1250000;
4378 pict2snd1 = 6500000;
4379 pict2snd2 = 0;
4380 rcvr_mode = 1;
4381 break;
4382 }
4383 case MTTUNEA_PAL_MN:{
4384 pict_car = 38900000;
4385 ch_bw = 6000000;
4386 pict2chanb_vsb = -1250000;
4387 pict2snd1 = 4500000;
4388 pict2snd2 = 0;
4389 rcvr_mode = 1;
4390 break;
4391 }
4392 case MTTUNEA_PAL_DK:{
4393 pict_car = 38900000;
4394 ch_bw = 8000000;
4395 pict2chanb_vsb = -1250000;
4396 pict2snd1 = 6500000;
4397 pict2snd2 = 0;
4398 rcvr_mode = 1;
4399 break;
4400 }
4401 case MTTUNEA_DIGITAL:{
4402 pict_car = 36125000;
4403 ch_bw = 8000000;
4404 pict2chanb_vsb = -(ch_bw / 2);
4405 pict2snd1 = 0;
4406 pict2snd2 = 0;
4407 rcvr_mode = 2;
4408 break;
4409 }
4410 case MTTUNEA_FMRADIO:{
4411 pict_car = 38900000;
4412 ch_bw = 8000000;
4413 pict2chanb_vsb = -(ch_bw / 2);
4414 pict2snd1 = 0;
4415 pict2snd2 = 0;
4416 rcvr_mode = 4;
4417 //f_in -= 2900000;
4418 break;
4419 }
4420 case MTTUNEA_DVBC:{
4421 pict_car = 36125000;
4422 ch_bw = 8000000;
4423 pict2chanb_vsb = -(ch_bw / 2);
4424 pict2snd1 = 0;
4425 pict2snd2 = 0;
4426 rcvr_mode = MT2063_CABLE_QAM;
4427 break;
4428 }
4429 case MTTUNEA_DVBT:{
4430 pict_car = 36125000;
4431 ch_bw = bw_in; //8000000
4432 pict2chanb_vsb = -(ch_bw / 2);
4433 pict2snd1 = 0;
4434 pict2snd2 = 0;
4435 rcvr_mode = MT2063_OFFAIR_COFDM;
4436 break;
4437 }
4438 case MTTUNEA_UNKNOWN:
4439 break;
4440 default:
4441 break;
4442 }
4443
4444 pict2chanb_snd = pict2chanb_vsb - ch_bw;
4445 if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
4446
4447 status |= MT2063_SetParam(h, MT2063_STEPSIZE, 125000);
4448 status |= MT2063_SetParam(h, MT2063_OUTPUT_FREQ, if_mid);
4449 status |= MT2063_SetParam(h, MT2063_OUTPUT_BW, ch_bw);
4450 status |= MT2063_GetParam(h, MT2063_RCVR_MODE, &mode_get);
4451
4452 status |= MT2063_SetParam(h, MT2063_RCVR_MODE, rcvr_mode);
4453 status |= MT2063_Tune(h, (f_in + (pict2chanb_vsb + (ch_bw / 2))));
4454 status |= MT2063_GetParam(h, MT2063_RCVR_MODE, &mode_get);
4455
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004456 return (u32) status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004457}
4458
4459static int mt2063_init(struct dvb_frontend *fe)
4460{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03004461 u32 status = -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004462 struct mt2063_state *state = fe->tuner_priv;
4463
4464 status = MT2063_Open(0xC0, &(state->MT2063_ht), fe);
4465 status |= MT2063_SoftwareShutdown(state->MT2063_ht, 1);
4466 status |= MT2063_ClearPowerMaskBits(state->MT2063_ht, MT2063_ALL_SD);
4467
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03004468 if (0 != status) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004469 printk("%s %d error status = 0x%x!!\n", __func__, __LINE__,
4470 status);
4471 return -1;
4472 }
4473
4474 return 0;
4475}
4476
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004477static int mt2063_get_status(struct dvb_frontend *fe, u32 * status)
4478{
4479 int rc = 0;
4480
4481 //get tuner lock status
4482
4483 return rc;
4484}
4485
4486static int mt2063_get_state(struct dvb_frontend *fe,
4487 enum tuner_param param, struct tuner_state *state)
4488{
4489 struct mt2063_state *mt2063State = fe->tuner_priv;
4490
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004491 switch (param) {
4492 case DVBFE_TUNER_FREQUENCY:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004493 //get frequency
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004494 break;
4495 case DVBFE_TUNER_TUNERSTEP:
4496 break;
4497 case DVBFE_TUNER_IFFREQ:
4498 break;
4499 case DVBFE_TUNER_BANDWIDTH:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004500 //get bandwidth
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004501 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004502 case DVBFE_TUNER_REFCLOCK:
4503 state->refclock =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004504 (u32)
4505 MT2063_GetLocked((void *) (mt2063State->MT2063_ht));
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004506 break;
4507 default:
4508 break;
4509 }
4510
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004511 return (int)state->refclock;
4512}
4513
4514static int mt2063_set_state(struct dvb_frontend *fe,
4515 enum tuner_param param, struct tuner_state *state)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004516{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004517 struct mt2063_state *mt2063State = fe->tuner_priv;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03004518 u32 status = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004519
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004520 switch (param) {
4521 case DVBFE_TUNER_FREQUENCY:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004522 //set frequency
4523
4524 status =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004525 MT_Tune_atv((void *) (mt2063State->MT2063_ht),
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004526 state->frequency, state->bandwidth,
4527 mt2063State->tv_type);
4528
4529 mt2063State->frequency = state->frequency;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004530 break;
4531 case DVBFE_TUNER_TUNERSTEP:
4532 break;
4533 case DVBFE_TUNER_IFFREQ:
4534 break;
4535 case DVBFE_TUNER_BANDWIDTH:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004536 //set bandwidth
4537 mt2063State->bandwidth = state->bandwidth;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004538 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004539 case DVBFE_TUNER_REFCLOCK:
4540
4541 break;
4542 case DVBFE_TUNER_OPEN:
4543 status = MT2063_Open(MT2063_I2C, &(mt2063State->MT2063_ht), fe);
4544 break;
4545 case DVBFE_TUNER_SOFTWARE_SHUTDOWN:
4546 status = MT2063_SoftwareShutdown(mt2063State->MT2063_ht, 1);
4547 break;
4548 case DVBFE_TUNER_CLEAR_POWER_MASKBITS:
4549 status =
4550 MT2063_ClearPowerMaskBits(mt2063State->MT2063_ht,
4551 MT2063_ALL_SD);
4552 break;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004553 default:
4554 break;
4555 }
4556
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004557 return (int)status;
4558}
4559
4560static int mt2063_release(struct dvb_frontend *fe)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004561{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004562 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004563
4564 fe->tuner_priv = NULL;
4565 kfree(state);
4566
4567 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004568}
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004569
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004570static struct dvb_tuner_ops mt2063_ops = {
4571 .info = {
4572 .name = "MT2063 Silicon Tuner",
4573 .frequency_min = 45000000,
4574 .frequency_max = 850000000,
4575 .frequency_step = 0,
4576 },
4577
4578 .init = mt2063_init,
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03004579 .sleep = MT2063_Sleep,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004580 .get_status = mt2063_get_status,
4581 .get_state = mt2063_get_state,
4582 .set_state = mt2063_set_state,
4583 .release = mt2063_release
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004584};
4585
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004586struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
4587 struct mt2063_config *config,
4588 struct i2c_adapter *i2c)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004589{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004590 struct mt2063_state *state = NULL;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004591
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004592 state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004593 if (state == NULL)
4594 goto error;
4595
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004596 state->config = config;
4597 state->i2c = i2c;
4598 state->frontend = fe;
4599 state->reference = config->refclock / 1000; /* kHz */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004600 state->MT2063_init = false;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004601 fe->tuner_priv = state;
4602 fe->ops.tuner_ops = mt2063_ops;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004603
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004604 printk("%s: Attaching MT2063 \n", __func__);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004605 return fe;
4606
4607error:
4608 kfree(state);
4609 return NULL;
4610}
4611
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004612EXPORT_SYMBOL(mt2063_attach);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004613MODULE_PARM_DESC(verbose, "Set Verbosity level");
4614
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004615MODULE_AUTHOR("Henry");
4616MODULE_DESCRIPTION("MT2063 Silicon tuner");
4617MODULE_LICENSE("GPL");