blob: 63d964ac13b697cf65ef91732636f9e4e7b2a586 [file] [log] [blame]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002#include <linux/init.h>
3#include <linux/kernel.h>
4#include <linux/module.h>
5#include <linux/string.h>
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03006
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03007#include "mt2063.h"
8
9/* Version of this module */
10#define MT2063_VERSION 10018 /* Version 01.18 */
11
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -030012static unsigned int verbose;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -030013module_param(verbose, int, 0644);
14
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -030015
16/*****************/
17/* From drivers/media/common/tuners/mt2063_cfg.h */
18
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -030019static unsigned int mt2063_setTune(struct dvb_frontend *fe, u32 f_in,
20 u32 bw_in,
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -030021 enum MTTune_atv_standard tv_type)
22{
23 //return (int)MT_Tune_atv(h, f_in, bw_in, tv_type);
24
25 struct dvb_frontend_ops *frontend_ops = NULL;
26 struct dvb_tuner_ops *tuner_ops = NULL;
27 struct tuner_state t_state;
28 struct mt2063_state *mt2063State = fe->tuner_priv;
29 int err = 0;
30
31 t_state.frequency = f_in;
32 t_state.bandwidth = bw_in;
33 mt2063State->tv_type = tv_type;
34 if (&fe->ops)
35 frontend_ops = &fe->ops;
36 if (&frontend_ops->tuner_ops)
37 tuner_ops = &frontend_ops->tuner_ops;
38 if (tuner_ops->set_state) {
39 if ((err =
40 tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY,
41 &t_state)) < 0) {
42 printk("%s: Invalid parameter\n", __func__);
43 return err;
44 }
45 }
46
47 return err;
48}
49
50static unsigned int mt2063_lockStatus(struct dvb_frontend *fe)
51{
52 struct dvb_frontend_ops *frontend_ops = &fe->ops;
53 struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
54 struct tuner_state t_state;
55 int err = 0;
56
57 if (&fe->ops)
58 frontend_ops = &fe->ops;
59 if (&frontend_ops->tuner_ops)
60 tuner_ops = &frontend_ops->tuner_ops;
61 if (tuner_ops->get_state) {
62 if ((err =
63 tuner_ops->get_state(fe, DVBFE_TUNER_REFCLOCK,
64 &t_state)) < 0) {
65 printk("%s: Invalid parameter\n", __func__);
66 return err;
67 }
68 }
69 return err;
70}
71
72static unsigned int tuner_MT2063_Open(struct dvb_frontend *fe)
73{
74 struct dvb_frontend_ops *frontend_ops = &fe->ops;
75 struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
76 struct tuner_state t_state;
77 int err = 0;
78
79 if (&fe->ops)
80 frontend_ops = &fe->ops;
81 if (&frontend_ops->tuner_ops)
82 tuner_ops = &frontend_ops->tuner_ops;
83 if (tuner_ops->set_state) {
84 if ((err =
85 tuner_ops->set_state(fe, DVBFE_TUNER_OPEN,
86 &t_state)) < 0) {
87 printk("%s: Invalid parameter\n", __func__);
88 return err;
89 }
90 }
91
92 return err;
93}
94
95static unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe)
96{
97 struct dvb_frontend_ops *frontend_ops = &fe->ops;
98 struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
99 struct tuner_state t_state;
100 int err = 0;
101
102 if (&fe->ops)
103 frontend_ops = &fe->ops;
104 if (&frontend_ops->tuner_ops)
105 tuner_ops = &frontend_ops->tuner_ops;
106 if (tuner_ops->set_state) {
107 if ((err =
108 tuner_ops->set_state(fe, DVBFE_TUNER_SOFTWARE_SHUTDOWN,
109 &t_state)) < 0) {
110 printk("%s: Invalid parameter\n", __func__);
111 return err;
112 }
113 }
114
115 return err;
116}
117
118static unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe)
119{
120 struct dvb_frontend_ops *frontend_ops = &fe->ops;
121 struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
122 struct tuner_state t_state;
123 int err = 0;
124
125 if (&fe->ops)
126 frontend_ops = &fe->ops;
127 if (&frontend_ops->tuner_ops)
128 tuner_ops = &frontend_ops->tuner_ops;
129 if (tuner_ops->set_state) {
130 if ((err =
131 tuner_ops->set_state(fe, DVBFE_TUNER_CLEAR_POWER_MASKBITS,
132 &t_state)) < 0) {
133 printk("%s: Invalid parameter\n", __func__);
134 return err;
135 }
136 }
137
138 return err;
139}
140
141/*****************/
142
143
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300144//i2c operation
145static int mt2063_writeregs(struct mt2063_state *state, u8 reg1,
146 u8 * data, int len)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300147{
148 int ret;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300149 u8 buf[60]; /* = { reg1, data }; */
150
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300151 struct i2c_msg msg = {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300152 .addr = state->config->tuner_address,
153 .flags = 0,
154 .buf = buf,
155 .len = len + 1
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300156 };
157
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300158 msg.buf[0] = reg1;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300159 memcpy(msg.buf + 1, data, len);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300160
161 //printk("mt2063_writeregs state->i2c=%p\n", state->i2c);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300162 ret = i2c_transfer(state->i2c, &msg, 1);
163
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300164 if (ret < 0)
165 printk("mt2063_writeregs error ret=%d\n", ret);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300166
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300167 return ret;
168}
169
170static int mt2063_read_regs(struct mt2063_state *state, u8 reg1, u8 * b, u8 len)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300171{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300172 int ret;
173 u8 b0[] = { reg1 };
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300174 struct i2c_msg msg[] = {
175 {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300176 .addr = state->config->tuner_address,
177 .flags = I2C_M_RD,
178 .buf = b0,
179 .len = 1}, {
180 .addr = state->config->tuner_address,
181 .flags = I2C_M_RD,
182 .buf = b,
183 .len = len}
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300184 };
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300185
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300186 //printk("mt2063_read_regs state->i2c=%p\n", state->i2c);
187 ret = i2c_transfer(state->i2c, msg, 2);
188 if (ret < 0)
189 printk("mt2063_readregs error ret=%d\n", ret);
190
191 return ret;
192}
193
194//context of mt2063_userdef.c <Henry> ======================================
195//#################################################################
196//=================================================================
197/*****************************************************************************
198**
199** Name: MT_WriteSub
200**
201** Description: Write values to device using a two-wire serial bus.
202**
203** Parameters: hUserData - User-specific I/O parameter that was
204** passed to tuner's Open function.
205** addr - device serial bus address (value passed
206** as parameter to MTxxxx_Open)
207** subAddress - serial bus sub-address (Register Address)
208** pData - pointer to the Data to be written to the
209** device
210** cnt - number of bytes/registers to be written
211**
212** Returns: status:
213** MT_OK - No errors
214** MT_COMM_ERR - Serial bus communications error
215** user-defined
216**
217** Notes: This is a callback function that is called from the
218** the tuning algorithm. You MUST provide code for this
219** function to write data using the tuner's 2-wire serial
220** bus.
221**
222** The hUserData parameter is a user-specific argument.
223** If additional arguments are needed for the user's
224** serial bus read/write functions, this argument can be
225** used to supply the necessary information.
226** The hUserData parameter is initialized in the tuner's Open
227** function.
228**
229** Revision History:
230**
231** SCR Date Author Description
232** -------------------------------------------------------------------------
233** N/A 03-25-2004 DAD Original
234**
235*****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300236u32 MT2063_WriteSub(void *hUserData,
237 u32 addr,
238 u8 subAddress, u8 * pData, u32 cnt)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300239{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300240 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300241 struct dvb_frontend *fe = hUserData;
242 struct mt2063_state *state = fe->tuner_priv;
243 /*
244 ** ToDo: Add code here to implement a serial-bus write
245 ** operation to the MTxxxx tuner. If successful,
246 ** return MT_OK.
247 */
248/* return status; */
249
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300250 fe->ops.i2c_gate_ctrl(fe, 1); //I2C bypass drxk3926 close i2c bridge
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300251
252 if (mt2063_writeregs(state, subAddress, pData, cnt) < 0) {
253 status = MT2063_ERROR;
254 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300255 fe->ops.i2c_gate_ctrl(fe, 0); //I2C bypass drxk3926 close i2c bridge
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300256
257 return (status);
258}
259
260/*****************************************************************************
261**
262** Name: MT_ReadSub
263**
264** Description: Read values from device using a two-wire serial bus.
265**
266** Parameters: hUserData - User-specific I/O parameter that was
267** passed to tuner's Open function.
268** addr - device serial bus address (value passed
269** as parameter to MTxxxx_Open)
270** subAddress - serial bus sub-address (Register Address)
271** pData - pointer to the Data to be written to the
272** device
273** cnt - number of bytes/registers to be written
274**
275** Returns: status:
276** MT_OK - No errors
277** MT_COMM_ERR - Serial bus communications error
278** user-defined
279**
280** Notes: This is a callback function that is called from the
281** the tuning algorithm. You MUST provide code for this
282** function to read data using the tuner's 2-wire serial
283** bus.
284**
285** The hUserData parameter is a user-specific argument.
286** If additional arguments are needed for the user's
287** serial bus read/write functions, this argument can be
288** used to supply the necessary information.
289** The hUserData parameter is initialized in the tuner's Open
290** function.
291**
292** Revision History:
293**
294** SCR Date Author Description
295** -------------------------------------------------------------------------
296** N/A 03-25-2004 DAD Original
297**
298*****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300299u32 MT2063_ReadSub(void *hUserData,
300 u32 addr,
301 u8 subAddress, u8 * pData, u32 cnt)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300302{
303 /*
304 ** ToDo: Add code here to implement a serial-bus read
305 ** operation to the MTxxxx tuner. If successful,
306 ** return MT_OK.
307 */
308/* return status; */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300309 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300310 struct dvb_frontend *fe = hUserData;
311 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300312 u32 i = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300313 fe->ops.i2c_gate_ctrl(fe, 1); //I2C bypass drxk3926 close i2c bridge
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300314
315 for (i = 0; i < cnt; i++) {
316 if (mt2063_read_regs(state, subAddress + i, pData + i, 1) < 0) {
317 status = MT2063_ERROR;
318 break;
319 }
320 }
321
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300322 fe->ops.i2c_gate_ctrl(fe, 0); //I2C bypass drxk3926 close i2c bridge
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300323
324 return (status);
325}
326
327/*****************************************************************************
328**
329** Name: MT_Sleep
330**
331** Description: Delay execution for "nMinDelayTime" milliseconds
332**
333** Parameters: hUserData - User-specific I/O parameter that was
334** passed to tuner's Open function.
335** nMinDelayTime - Delay time in milliseconds
336**
337** Returns: None.
338**
339** Notes: This is a callback function that is called from the
340** the tuning algorithm. You MUST provide code that
341** blocks execution for the specified period of time.
342**
343** Revision History:
344**
345** SCR Date Author Description
346** -------------------------------------------------------------------------
347** N/A 03-25-2004 DAD Original
348**
349*****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300350void MT2063_Sleep(void *hUserData, u32 nMinDelayTime)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300351{
352 /*
353 ** ToDo: Add code here to implement a OS blocking
354 ** for a period of "nMinDelayTime" milliseconds.
355 */
356 msleep(nMinDelayTime);
357}
358
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300359/*****************************************************************************
360**
361** Name: MT_TunerGain (MT2060 only)
362**
363** Description: Measure the relative tuner gain using the demodulator
364**
365** Parameters: hUserData - User-specific I/O parameter that was
366** passed to tuner's Open function.
367** pMeas - Tuner gain (1/100 of dB scale).
368** ie. 1234 = 12.34 (dB)
369**
370** Returns: status:
371** MT_OK - No errors
372** user-defined errors could be set
373**
374** Notes: This is a callback function that is called from the
375** the 1st IF location routine. You MUST provide
376** code that measures the relative tuner gain in a dB
377** (not linear) scale. The return value is an integer
378** value scaled to 1/100 of a dB.
379**
380** Revision History:
381**
382** SCR Date Author Description
383** -------------------------------------------------------------------------
384** N/A 06-16-2004 DAD Original
385** N/A 11-30-2004 DAD Renamed from MT_DemodInputPower. This name
386** better describes what this function does.
387**
388*****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300389u32 MT2060_TunerGain(void *hUserData, s32 * pMeas)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300390{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300391 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300392
393 /*
394 ** ToDo: Add code here to return the gain / power level measured
395 ** at the input to the demodulator.
396 */
397
398 return (status);
399}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300400//end of mt2063_userdef.c
401//=================================================================
402//#################################################################
403//=================================================================
404
405//context of mt2063_spuravoid.c <Henry> ======================================
406//#################################################################
407//=================================================================
408
409/*****************************************************************************
410**
411** Name: mt_spuravoid.c
412**
413** Description: Microtune spur avoidance software module.
414** Supports Microtune tuner drivers.
415**
416** CVS ID: $Id: mt_spuravoid.c,v 1.3 2008/06/26 15:39:52 software Exp $
417** CVS Source: $Source: /export/home/cvsroot/software/tuners/MT2063/mt_spuravoid.c,v $
418**
419** Revision History:
420**
421** SCR Date Author Description
422** -------------------------------------------------------------------------
423** 082 03-25-2005 JWS Original multi-tuner support - requires
424** MTxxxx_CNT declarations
425** 096 04-06-2005 DAD Ver 1.11: Fix divide by 0 error if maxH==0.
426** 094 04-06-2005 JWS Ver 1.11 Added uceil and ufloor to get rid
427** of compiler warnings
428** N/A 04-07-2005 DAD Ver 1.13: Merged single- and multi-tuner spur
429** avoidance into a single module.
430** 103 01-31-2005 DAD Ver 1.14: In MT_AddExclZone(), if the range
431** (f_min, f_max) < 0, ignore the entry.
432** 115 03-23-2007 DAD Fix declaration of spur due to truncation
433** errors.
434** 117 03-29-2007 RSK Ver 1.15: Re-wrote to match search order from
435** tuner DLL.
436** 137 06-18-2007 DAD Ver 1.16: Fix possible divide-by-0 error for
437** multi-tuners that have
438** (delta IF1) > (f_out-f_outbw/2).
439** 147 07-27-2007 RSK Ver 1.17: Corrected calculation (-) to (+)
440** Added logic to force f_Center within 1/2 f_Step.
441** 177 S 02-26-2008 RSK Ver 1.18: Corrected calculation using LO1 > MAX/2
442** Type casts added to preserve correct sign.
443** N/A I 06-17-2008 RSK Ver 1.19: Refactoring avoidance of DECT
444** frequencies into MT_ResetExclZones().
445** N/A I 06-20-2008 RSK Ver 1.21: New VERSION number for ver checking.
446**
447*****************************************************************************/
448
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300449/* Version of this module */
450#define MT2063_SPUR_VERSION 10201 /* Version 01.21 */
451
452/* Implement ceiling, floor functions. */
453#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0))
454#define uceil(n, d) ((n)/(d) + ((n)%(d) != 0))
455#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d))
456#define ufloor(n, d) ((n)/(d))
457
458struct MT2063_FIFZone_t {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300459 s32 min_;
460 s32 max_;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300461};
462
463#if MT2063_TUNER_CNT > 1
464static struct MT2063_AvoidSpursData_t *TunerList[MT2063_TUNER_CNT];
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300465static u32 TunerCount = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300466#endif
467
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300468u32 MT2063_RegisterTuner(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300469{
470#if MT2063_TUNER_CNT == 1
471 pAS_Info->nAS_Algorithm = 1;
472 return MT2063_OK;
473#else
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300474 u32 index;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300475
476 pAS_Info->nAS_Algorithm = 2;
477
478 /*
479 ** Check to see if tuner is already registered
480 */
481 for (index = 0; index < TunerCount; index++) {
482 if (TunerList[index] == pAS_Info) {
483 return MT2063_OK; /* Already here - no problem */
484 }
485 }
486
487 /*
488 ** Add tuner to list - if there is room.
489 */
490 if (TunerCount < MT2063_TUNER_CNT) {
491 TunerList[TunerCount] = pAS_Info;
492 TunerCount++;
493 return MT2063_OK;
494 } else
495 return MT2063_TUNER_CNT_ERR;
496#endif
497}
498
499void MT2063_UnRegisterTuner(struct MT2063_AvoidSpursData_t *pAS_Info)
500{
501#if MT2063_TUNER_CNT == 1
502 pAS_Info;
503#else
504
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300505 u32 index;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300506
507 for (index = 0; index < TunerCount; index++) {
508 if (TunerList[index] == pAS_Info) {
509 TunerList[index] = TunerList[--TunerCount];
510 }
511 }
512#endif
513}
514
515/*
516** Reset all exclusion zones.
517** Add zones to protect the PLL FracN regions near zero
518**
519** N/A I 06-17-2008 RSK Ver 1.19: Refactoring avoidance of DECT
520** frequencies into MT_ResetExclZones().
521*/
522void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info)
523{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300524 u32 center;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300525#if MT2063_TUNER_CNT > 1
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300526 u32 index;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300527 struct MT2063_AvoidSpursData_t *adj;
528#endif
529
530 pAS_Info->nZones = 0; /* this clears the used list */
531 pAS_Info->usedZones = NULL; /* reset ptr */
532 pAS_Info->freeZones = NULL; /* reset ptr */
533
534 center =
535 pAS_Info->f_ref *
536 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 +
537 pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in;
538 while (center <
539 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
540 pAS_Info->f_LO1_FracN_Avoid) {
541 /* Exclude LO1 FracN */
542 MT2063_AddExclZone(pAS_Info,
543 center - pAS_Info->f_LO1_FracN_Avoid,
544 center - 1);
545 MT2063_AddExclZone(pAS_Info, center + 1,
546 center + pAS_Info->f_LO1_FracN_Avoid);
547 center += pAS_Info->f_ref;
548 }
549
550 center =
551 pAS_Info->f_ref *
552 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 -
553 pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out;
554 while (center <
555 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
556 pAS_Info->f_LO2_FracN_Avoid) {
557 /* Exclude LO2 FracN */
558 MT2063_AddExclZone(pAS_Info,
559 center - pAS_Info->f_LO2_FracN_Avoid,
560 center - 1);
561 MT2063_AddExclZone(pAS_Info, center + 1,
562 center + pAS_Info->f_LO2_FracN_Avoid);
563 center += pAS_Info->f_ref;
564 }
565
566 if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
567 /* Exclude LO1 values that conflict with DECT channels */
568 MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */
569 MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */
570 MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */
571 MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */
572 MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */
573 }
574
575 if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
576 MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */
577 MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */
578 MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */
579 MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */
580 MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */
581 MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */
582 MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */
583 MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */
584 MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */
585 MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */
586 }
587#if MT2063_TUNER_CNT > 1
588 /*
589 ** Iterate through all adjacent tuners and exclude frequencies related to them
590 */
591 for (index = 0; index < TunerCount; ++index) {
592 adj = TunerList[index];
593 if (pAS_Info == adj) /* skip over our own data, don't process it */
594 continue;
595
596 /*
597 ** Add 1st IF exclusion zone covering adjacent tuner's LO2
598 ** at "adjfLO2 + f_out" +/- m_MinLOSpacing
599 */
600 if (adj->f_LO2 != 0)
601 MT2063_AddExclZone(pAS_Info,
602 (adj->f_LO2 + pAS_Info->f_out) -
603 pAS_Info->f_min_LO_Separation,
604 (adj->f_LO2 + pAS_Info->f_out) +
605 pAS_Info->f_min_LO_Separation);
606
607 /*
608 ** Add 1st IF exclusion zone covering adjacent tuner's LO1
609 ** at "adjfLO1 - f_in" +/- m_MinLOSpacing
610 */
611 if (adj->f_LO1 != 0)
612 MT2063_AddExclZone(pAS_Info,
613 (adj->f_LO1 - pAS_Info->f_in) -
614 pAS_Info->f_min_LO_Separation,
615 (adj->f_LO1 - pAS_Info->f_in) +
616 pAS_Info->f_min_LO_Separation);
617 }
618#endif
619}
620
621static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t
622 *pAS_Info,
623 struct MT2063_ExclZone_t *pPrevNode)
624{
625 struct MT2063_ExclZone_t *pNode;
626 /* Check for a node in the free list */
627 if (pAS_Info->freeZones != NULL) {
628 /* Use one from the free list */
629 pNode = pAS_Info->freeZones;
630 pAS_Info->freeZones = pNode->next_;
631 } else {
632 /* Grab a node from the array */
633 pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones];
634 }
635
636 if (pPrevNode != NULL) {
637 pNode->next_ = pPrevNode->next_;
638 pPrevNode->next_ = pNode;
639 } else { /* insert at the beginning of the list */
640
641 pNode->next_ = pAS_Info->usedZones;
642 pAS_Info->usedZones = pNode;
643 }
644
645 pAS_Info->nZones++;
646 return pNode;
647}
648
649static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t
650 *pAS_Info,
651 struct MT2063_ExclZone_t *pPrevNode,
652 struct MT2063_ExclZone_t
653 *pNodeToRemove)
654{
655 struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_;
656
657 /* Make previous node point to the subsequent node */
658 if (pPrevNode != NULL)
659 pPrevNode->next_ = pNext;
660
661 /* Add pNodeToRemove to the beginning of the freeZones */
662 pNodeToRemove->next_ = pAS_Info->freeZones;
663 pAS_Info->freeZones = pNodeToRemove;
664
665 /* Decrement node count */
666 pAS_Info->nZones--;
667
668 return pNext;
669}
670
671/*****************************************************************************
672**
673** Name: MT_AddExclZone
674**
675** Description: Add (and merge) an exclusion zone into the list.
676** If the range (f_min, f_max) is totally outside the
677** 1st IF BW, ignore the entry.
678** If the range (f_min, f_max) is negative, ignore the entry.
679**
680** Revision History:
681**
682** SCR Date Author Description
683** -------------------------------------------------------------------------
684** 103 01-31-2005 DAD Ver 1.14: In MT_AddExclZone(), if the range
685** (f_min, f_max) < 0, ignore the entry.
686**
687*****************************************************************************/
688void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300689 u32 f_min, u32 f_max)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300690{
691 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
692 struct MT2063_ExclZone_t *pPrev = NULL;
693 struct MT2063_ExclZone_t *pNext = NULL;
694
695 /* Check to see if this overlaps the 1st IF filter */
696 if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2)))
697 && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2)))
698 && (f_min < f_max)) {
699 /*
700 ** 1 2 3 4 5 6
701 **
702 ** New entry: |---| |--| |--| |-| |---| |--|
703 ** or or or or or
704 ** Existing: |--| |--| |--| |---| |-| |--|
705 */
706
707 /* Check for our place in the list */
708 while ((pNode != NULL) && (pNode->max_ < f_min)) {
709 pPrev = pNode;
710 pNode = pNode->next_;
711 }
712
713 if ((pNode != NULL) && (pNode->min_ < f_max)) {
714 /* Combine me with pNode */
715 if (f_min < pNode->min_)
716 pNode->min_ = f_min;
717 if (f_max > pNode->max_)
718 pNode->max_ = f_max;
719 } else {
720 pNode = InsertNode(pAS_Info, pPrev);
721 pNode->min_ = f_min;
722 pNode->max_ = f_max;
723 }
724
725 /* Look for merging possibilities */
726 pNext = pNode->next_;
727 while ((pNext != NULL) && (pNext->min_ < pNode->max_)) {
728 if (pNext->max_ > pNode->max_)
729 pNode->max_ = pNext->max_;
730 pNext = RemoveNode(pAS_Info, pNode, pNext); /* Remove pNext, return ptr to pNext->next */
731 }
732 }
733}
734
735/*****************************************************************************
736**
737** Name: MT_ChooseFirstIF
738**
739** Description: Choose the best available 1st IF
740** If f_Desired is not excluded, choose that first.
741** Otherwise, return the value closest to f_Center that is
742** not excluded
743**
744** Revision History:
745**
746** SCR Date Author Description
747** -------------------------------------------------------------------------
748** 117 03-29-2007 RSK Ver 1.15: Re-wrote to match search order from
749** tuner DLL.
750** 147 07-27-2007 RSK Ver 1.17: Corrected calculation (-) to (+)
751** Added logic to force f_Center within 1/2 f_Step.
752**
753*****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300754u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300755{
756 /*
757 ** Update "f_Desired" to be the nearest "combinational-multiple" of "f_LO1_Step".
758 ** The resulting number, F_LO1 must be a multiple of f_LO1_Step. And F_LO1 is the arithmetic sum
759 ** of f_in + f_Center. Neither f_in, nor f_Center must be a multiple of f_LO1_Step.
760 ** However, the sum must be.
761 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300762 const u32 f_Desired =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300763 pAS_Info->f_LO1_Step *
764 ((pAS_Info->f_if1_Request + pAS_Info->f_in +
765 pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) -
766 pAS_Info->f_in;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300767 const u32 f_Step =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300768 (pAS_Info->f_LO1_Step >
769 pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info->
770 f_LO2_Step;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300771 u32 f_Center;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300772
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300773 s32 i;
774 s32 j = 0;
775 u32 bDesiredExcluded = 0;
776 u32 bZeroExcluded = 0;
777 s32 tmpMin, tmpMax;
778 s32 bestDiff;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300779 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
780 struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES];
781
782 if (pAS_Info->nZones == 0)
783 return f_Desired;
784
785 /* f_Center needs to be an integer multiple of f_Step away from f_Desired */
786 if (pAS_Info->f_if1_Center > f_Desired)
787 f_Center =
788 f_Desired +
789 f_Step *
790 ((pAS_Info->f_if1_Center - f_Desired +
791 f_Step / 2) / f_Step);
792 else
793 f_Center =
794 f_Desired -
795 f_Step *
796 ((f_Desired - pAS_Info->f_if1_Center +
797 f_Step / 2) / f_Step);
798
799 //assert;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300800 //if (!abs((s32) f_Center - (s32) pAS_Info->f_if1_Center) <= (s32) (f_Step/2))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300801 // return 0;
802
803 /* Take MT_ExclZones, center around f_Center and change the resolution to f_Step */
804 while (pNode != NULL) {
805 /* floor function */
806 tmpMin =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300807 floor((s32) (pNode->min_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300808
809 /* ceil function */
810 tmpMax =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300811 ceil((s32) (pNode->max_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300812
813 if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired))
814 bDesiredExcluded = 1;
815
816 if ((tmpMin < 0) && (tmpMax > 0))
817 bZeroExcluded = 1;
818
819 /* See if this zone overlaps the previous */
820 if ((j > 0) && (tmpMin < zones[j - 1].max_))
821 zones[j - 1].max_ = tmpMax;
822 else {
823 /* Add new zone */
824 //assert(j<MT2063_MAX_ZONES);
825 //if (j>=MT2063_MAX_ZONES)
826 //break;
827
828 zones[j].min_ = tmpMin;
829 zones[j].max_ = tmpMax;
830 j++;
831 }
832 pNode = pNode->next_;
833 }
834
835 /*
836 ** If the desired is okay, return with it
837 */
838 if (bDesiredExcluded == 0)
839 return f_Desired;
840
841 /*
842 ** If the desired is excluded and the center is okay, return with it
843 */
844 if (bZeroExcluded == 0)
845 return f_Center;
846
847 /* Find the value closest to 0 (f_Center) */
848 bestDiff = zones[0].min_;
849 for (i = 0; i < j; i++) {
850 if (abs(zones[i].min_) < abs(bestDiff))
851 bestDiff = zones[i].min_;
852 if (abs(zones[i].max_) < abs(bestDiff))
853 bestDiff = zones[i].max_;
854 }
855
856 if (bestDiff < 0)
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300857 return f_Center - ((u32) (-bestDiff) * f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300858
859 return f_Center + (bestDiff * f_Step);
860}
861
862/****************************************************************************
863**
864** Name: gcd
865**
866** Description: Uses Euclid's algorithm
867**
868** Parameters: u, v - unsigned values whose GCD is desired.
869**
870** Global: None
871**
872** Returns: greatest common divisor of u and v, if either value
873** is 0, the other value is returned as the result.
874**
875** Dependencies: None.
876**
877** Revision History:
878**
879** SCR Date Author Description
880** -------------------------------------------------------------------------
881** N/A 06-01-2004 JWS Original
882** N/A 08-03-2004 DAD Changed to Euclid's since it can handle
883** unsigned numbers.
884**
885****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300886static u32 MT2063_gcd(u32 u, u32 v)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300887{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300888 u32 r;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300889
890 while (v != 0) {
891 r = u % v;
892 u = v;
893 v = r;
894 }
895
896 return u;
897}
898
899/****************************************************************************
900**
901** Name: umax
902**
903** Description: Implements a simple maximum function for unsigned numbers.
904** Implemented as a function rather than a macro to avoid
905** multiple evaluation of the calling parameters.
906**
907** Parameters: a, b - Values to be compared
908**
909** Global: None
910**
911** Returns: larger of the input values.
912**
913** Dependencies: None.
914**
915** Revision History:
916**
917** SCR Date Author Description
918** -------------------------------------------------------------------------
919** N/A 06-02-2004 JWS Original
920**
921****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300922static u32 MT2063_umax(u32 a, u32 b)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300923{
924 return (a >= b) ? a : b;
925}
926
927#if MT2063_TUNER_CNT > 1
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300928static s32 RoundAwayFromZero(s32 n, s32 d)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300929{
930 return (n < 0) ? floor(n, d) : ceil(n, d);
931}
932
933/****************************************************************************
934**
935** Name: IsSpurInAdjTunerBand
936**
937** Description: Checks to see if a spur will be present within the IF's
938** bandwidth or near the zero IF.
939** (fIFOut +/- fIFBW/2, -fIFOut +/- fIFBW/2)
940** and
941** (0 +/- fZIFBW/2)
942**
943** ma mb me mf mc md
944** <--+-+-+-----------------+-+-+-----------------+-+-+-->
945** | ^ 0 ^ |
946** ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^
947** a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2
948**
949** Note that some equations are doubled to prevent round-off
950** problems when calculating fIFBW/2
951**
952** The spur frequencies are computed as:
953**
954** fSpur = n * f1 - m * f2 - fOffset
955**
956** Parameters: f1 - The 1st local oscillator (LO) frequency
957** of the tuner whose output we are examining
958** f2 - The 1st local oscillator (LO) frequency
959** of the adjacent tuner
960** fOffset - The 2nd local oscillator of the tuner whose
961** output we are examining
962** fIFOut - Output IF center frequency
963** fIFBW - Output IF Bandwidth
964** nMaxH - max # of LO harmonics to search
965** fp - If spur, positive distance to spur-free band edge (returned)
966** fm - If spur, negative distance to spur-free band edge (returned)
967**
968** Returns: 1 if an LO spur would be present, otherwise 0.
969**
970** Dependencies: None.
971**
972** Revision History:
973**
974** SCR Date Author Description
975** -------------------------------------------------------------------------
976** N/A 01-21-2005 JWS Original, adapted from MT_DoubleConversion.
977** 115 03-23-2007 DAD Fix declaration of spur due to truncation
978** errors.
979** 137 06-18-2007 DAD Ver 1.16: Fix possible divide-by-0 error for
980** multi-tuners that have
981** (delta IF1) > (f_out-f_outbw/2).
982** 177 S 02-26-2008 RSK Ver 1.18: Corrected calculation using LO1 > MAX/2
983** Type casts added to preserve correct sign.
984**
985****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300986static u32 IsSpurInAdjTunerBand(u32 bIsMyOutput,
987 u32 f1,
988 u32 f2,
989 u32 fOffset,
990 u32 fIFOut,
991 u32 fIFBW,
992 u32 fZIFBW,
993 u32 nMaxH, u32 * fp, u32 * fm)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300994{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300995 u32 bSpurFound = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300996
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300997 const u32 fHalf_IFBW = fIFBW / 2;
998 const u32 fHalf_ZIFBW = fZIFBW / 2;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300999
1000 /* Calculate a scale factor for all frequencies, so that our
1001 calculations all stay within 31 bits */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001002 const u32 f_Scale =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001003 ((f1 +
1004 (fOffset + fIFOut +
1005 fHalf_IFBW) / nMaxH) / (MAX_UDATA / 2 / nMaxH)) + 1;
1006
1007 /*
1008 ** After this scaling, _f1, _f2, and _f3 are guaranteed to fit into
1009 ** signed data types (smaller than MAX_UDATA/2)
1010 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001011 const s32 _f1 = (s32) (f1 / f_Scale);
1012 const s32 _f2 = (s32) (f2 / f_Scale);
1013 const s32 _f3 = (s32) (fOffset / f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001014
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001015 const s32 c = (s32) (fIFOut - fHalf_IFBW) / (s32) f_Scale;
1016 const s32 d = (s32) ((fIFOut + fHalf_IFBW) / f_Scale);
1017 const s32 f = (s32) (fHalf_ZIFBW / f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001018
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001019 s32 ma, mb, mc, md, me, mf;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001020
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001021 s32 fp_ = 0;
1022 s32 fm_ = 0;
1023 s32 n;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001024
1025 /*
1026 ** If the other tuner does not have an LO frequency defined,
1027 ** assume that we cannot interfere with it
1028 */
1029 if (f2 == 0)
1030 return 0;
1031
1032 /* Check out all multiples of f1 from -nMaxH to +nMaxH */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001033 for (n = -(s32) nMaxH; n <= (s32) nMaxH; ++n) {
1034 const s32 nf1 = n * _f1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001035 md = (_f3 + d - nf1) / _f2;
1036
1037 /* If # f2 harmonics > nMaxH, then no spurs present */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001038 if (md <= -(s32) nMaxH)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001039 break;
1040
1041 ma = (_f3 - d - nf1) / _f2;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001042 if ((ma == md) || (ma >= (s32) (nMaxH)))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001043 continue;
1044
1045 mc = (_f3 + c - nf1) / _f2;
1046 if (mc != md) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001047 const s32 m = (n < 0) ? md : mc;
1048 const s32 fspur = (nf1 + m * _f2 - _f3);
1049 const s32 den = (bIsMyOutput ? n - 1 : n);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001050 if (den == 0) {
1051 fp_ = (d - fspur) * f_Scale;
1052 fm_ = (fspur - c) * f_Scale;
1053 } else {
1054 fp_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001055 (s32) RoundAwayFromZero((d - fspur) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001056 f_Scale, den);
1057 fm_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001058 (s32) RoundAwayFromZero((fspur - c) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001059 f_Scale, den);
1060 }
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001061 if (((u32) abs(fm_) >= f_Scale)
1062 && ((u32) abs(fp_) >= f_Scale)) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001063 bSpurFound = 1;
1064 break;
1065 }
1066 }
1067
1068 /* Location of Zero-IF-spur to be checked */
1069 mf = (_f3 + f - nf1) / _f2;
1070 me = (_f3 - f - nf1) / _f2;
1071 if (me != mf) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001072 const s32 m = (n < 0) ? mf : me;
1073 const s32 fspur = (nf1 + m * _f2 - _f3);
1074 const s32 den = (bIsMyOutput ? n - 1 : n);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001075 if (den == 0) {
1076 fp_ = (d - fspur) * f_Scale;
1077 fm_ = (fspur - c) * f_Scale;
1078 } else {
1079 fp_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001080 (s32) RoundAwayFromZero((f - fspur) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001081 f_Scale, den);
1082 fm_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001083 (s32) RoundAwayFromZero((fspur + f) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001084 f_Scale, den);
1085 }
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001086 if (((u32) abs(fm_) >= f_Scale)
1087 && ((u32) abs(fp_) >= f_Scale)) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001088 bSpurFound = 1;
1089 break;
1090 }
1091 }
1092
1093 mb = (_f3 - c - nf1) / _f2;
1094 if (ma != mb) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001095 const s32 m = (n < 0) ? mb : ma;
1096 const s32 fspur = (nf1 + m * _f2 - _f3);
1097 const s32 den = (bIsMyOutput ? n - 1 : n);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001098 if (den == 0) {
1099 fp_ = (d - fspur) * f_Scale;
1100 fm_ = (fspur - c) * f_Scale;
1101 } else {
1102 fp_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001103 (s32) RoundAwayFromZero((-c - fspur) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001104 f_Scale, den);
1105 fm_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001106 (s32) RoundAwayFromZero((fspur + d) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001107 f_Scale, den);
1108 }
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001109 if (((u32) abs(fm_) >= f_Scale)
1110 && ((u32) abs(fp_) >= f_Scale)) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001111 bSpurFound = 1;
1112 break;
1113 }
1114 }
1115 }
1116
1117 /*
1118 ** Verify that fm & fp are both positive
1119 ** Add one to ensure next 1st IF choice is not right on the edge
1120 */
1121 if (fp_ < 0) {
1122 *fp = -fm_ + 1;
1123 *fm = -fp_ + 1;
1124 } else if (fp_ > 0) {
1125 *fp = fp_ + 1;
1126 *fm = fm_ + 1;
1127 } else {
1128 *fp = 1;
1129 *fm = abs(fm_) + 1;
1130 }
1131
1132 return bSpurFound;
1133}
1134#endif
1135
1136/****************************************************************************
1137**
1138** Name: IsSpurInBand
1139**
1140** Description: Checks to see if a spur will be present within the IF's
1141** bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW)
1142**
1143** ma mb mc md
1144** <--+-+-+-------------------+-------------------+-+-+-->
1145** | ^ 0 ^ |
1146** ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^
1147** a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2
1148**
1149** Note that some equations are doubled to prevent round-off
1150** problems when calculating fIFBW/2
1151**
1152** Parameters: pAS_Info - Avoid Spurs information block
1153** fm - If spur, amount f_IF1 has to move negative
1154** fp - If spur, amount f_IF1 has to move positive
1155**
1156** Global: None
1157**
1158** Returns: 1 if an LO spur would be present, otherwise 0.
1159**
1160** Dependencies: None.
1161**
1162** Revision History:
1163**
1164** SCR Date Author Description
1165** -------------------------------------------------------------------------
1166** N/A 11-28-2002 DAD Implemented algorithm from applied patent
1167**
1168****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001169static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info,
1170 u32 * fm, u32 * fp)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001171{
1172 /*
1173 ** Calculate LO frequency settings.
1174 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001175 u32 n, n0;
1176 const u32 f_LO1 = pAS_Info->f_LO1;
1177 const u32 f_LO2 = pAS_Info->f_LO2;
1178 const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2;
1179 const u32 c = d - pAS_Info->f_out_bw;
1180 const u32 f = pAS_Info->f_zif_bw / 2;
1181 const u32 f_Scale = (f_LO1 / (MAX_UDATA / 2 / pAS_Info->maxH1)) + 1;
1182 s32 f_nsLO1, f_nsLO2;
1183 s32 f_Spur;
1184 u32 ma, mb, mc, md, me, mf;
1185 u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001186#if MT2063_TUNER_CNT > 1
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001187 u32 index;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001188
1189 struct MT2063_AvoidSpursData_t *adj;
1190#endif
1191 *fm = 0;
1192
1193 /*
1194 ** For each edge (d, c & f), calculate a scale, based on the gcd
1195 ** of f_LO1, f_LO2 and the edge value. Use the larger of this
1196 ** gcd-based scale factor or f_Scale.
1197 */
1198 lo_gcd = MT2063_gcd(f_LO1, f_LO2);
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001199 gd_Scale = MT2063_umax((u32) MT2063_gcd(lo_gcd, d), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001200 hgds = gd_Scale / 2;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001201 gc_Scale = MT2063_umax((u32) MT2063_gcd(lo_gcd, c), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001202 hgcs = gc_Scale / 2;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001203 gf_Scale = MT2063_umax((u32) MT2063_gcd(lo_gcd, f), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001204 hgfs = gf_Scale / 2;
1205
1206 n0 = uceil(f_LO2 - d, f_LO1 - f_LO2);
1207
1208 /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */
1209 for (n = n0; n <= pAS_Info->maxH1; ++n) {
1210 md = (n * ((f_LO1 + hgds) / gd_Scale) -
1211 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
1212
1213 /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */
1214 if (md >= pAS_Info->maxH1)
1215 break;
1216
1217 ma = (n * ((f_LO1 + hgds) / gd_Scale) +
1218 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
1219
1220 /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */
1221 if (md == ma)
1222 continue;
1223
1224 mc = (n * ((f_LO1 + hgcs) / gc_Scale) -
1225 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
1226 if (mc != md) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001227 f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale));
1228 f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale));
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001229 f_Spur =
1230 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
1231 n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale);
1232
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001233 *fp = ((f_Spur - (s32) c) / (mc - n)) + 1;
1234 *fm = (((s32) d - f_Spur) / (mc - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001235 return 1;
1236 }
1237
1238 /* Location of Zero-IF-spur to be checked */
1239 me = (n * ((f_LO1 + hgfs) / gf_Scale) +
1240 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
1241 mf = (n * ((f_LO1 + hgfs) / gf_Scale) -
1242 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
1243 if (me != mf) {
1244 f_nsLO1 = n * (f_LO1 / gf_Scale);
1245 f_nsLO2 = me * (f_LO2 / gf_Scale);
1246 f_Spur =
1247 (gf_Scale * (f_nsLO1 - f_nsLO2)) +
1248 n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale);
1249
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001250 *fp = ((f_Spur + (s32) f) / (me - n)) + 1;
1251 *fm = (((s32) f - f_Spur) / (me - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001252 return 1;
1253 }
1254
1255 mb = (n * ((f_LO1 + hgcs) / gc_Scale) +
1256 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
1257 if (ma != mb) {
1258 f_nsLO1 = n * (f_LO1 / gc_Scale);
1259 f_nsLO2 = ma * (f_LO2 / gc_Scale);
1260 f_Spur =
1261 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
1262 n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale);
1263
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001264 *fp = (((s32) d + f_Spur) / (ma - n)) + 1;
1265 *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001266 return 1;
1267 }
1268 }
1269
1270#if MT2063_TUNER_CNT > 1
1271 /* If no spur found, see if there are more tuners on the same board */
1272 for (index = 0; index < TunerCount; ++index) {
1273 adj = TunerList[index];
1274 if (pAS_Info == adj) /* skip over our own data, don't process it */
1275 continue;
1276
1277 /* Look for LO-related spurs from the adjacent tuner generated into my IF output */
1278 if (IsSpurInAdjTunerBand(1, /* check my IF output */
1279 pAS_Info->f_LO1, /* my fLO1 */
1280 adj->f_LO1, /* the other tuner's fLO1 */
1281 pAS_Info->f_LO2, /* my fLO2 */
1282 pAS_Info->f_out, /* my fOut */
1283 pAS_Info->f_out_bw, /* my output IF bandwidth */
1284 pAS_Info->f_zif_bw, /* my Zero-IF bandwidth */
1285 pAS_Info->maxH2, fp, /* minimum amount to move LO's positive */
1286 fm)) /* miminum amount to move LO's negative */
1287 return 1;
1288 /* Look for LO-related spurs from my tuner generated into the adjacent tuner's IF output */
1289 if (IsSpurInAdjTunerBand(0, /* check his IF output */
1290 pAS_Info->f_LO1, /* my fLO1 */
1291 adj->f_LO1, /* the other tuner's fLO1 */
1292 adj->f_LO2, /* the other tuner's fLO2 */
1293 adj->f_out, /* the other tuner's fOut */
1294 adj->f_out_bw, /* the other tuner's output IF bandwidth */
1295 pAS_Info->f_zif_bw, /* the other tuner's Zero-IF bandwidth */
1296 adj->maxH2, fp, /* minimum amount to move LO's positive */
1297 fm)) /* miminum amount to move LO's negative */
1298 return 1;
1299 }
1300#endif
1301 /* No spurs found */
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001302 return 0;
1303}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001304
1305/*****************************************************************************
1306**
1307** Name: MT_AvoidSpurs
1308**
1309** Description: Main entry point to avoid spurs.
1310** Checks for existing spurs in present LO1, LO2 freqs
1311** and if present, chooses spur-free LO1, LO2 combination
1312** that tunes the same input/output frequencies.
1313**
1314** Revision History:
1315**
1316** SCR Date Author Description
1317** -------------------------------------------------------------------------
1318** 096 04-06-2005 DAD Ver 1.11: Fix divide by 0 error if maxH==0.
1319**
1320*****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001321u32 MT2063_AvoidSpurs(void *h, struct MT2063_AvoidSpursData_t * pAS_Info)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001322{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001323 u32 status = MT2063_OK;
1324 u32 fm, fp; /* restricted range on LO's */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001325 pAS_Info->bSpurAvoided = 0;
1326 pAS_Info->nSpursFound = 0;
1327
1328 if (pAS_Info->maxH1 == 0)
1329 return MT2063_OK;
1330
1331 /*
1332 ** Avoid LO Generated Spurs
1333 **
1334 ** Make sure that have no LO-related spurs within the IF output
1335 ** bandwidth.
1336 **
1337 ** If there is an LO spur in this band, start at the current IF1 frequency
1338 ** and work out until we find a spur-free frequency or run up against the
1339 ** 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they
1340 ** will be unchanged if a spur-free setting is not found.
1341 */
1342 pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
1343 if (pAS_Info->bSpurPresent) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001344 u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */
1345 u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */
1346 u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */
1347 u32 delta_IF1;
1348 u32 new_IF1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001349
1350 /*
1351 ** Spur was found, attempt to find a spur-free 1st IF
1352 */
1353 do {
1354 pAS_Info->nSpursFound++;
1355
1356 /* Raise f_IF1_upper, if needed */
1357 MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp);
1358
1359 /* Choose next IF1 that is closest to f_IF1_CENTER */
1360 new_IF1 = MT2063_ChooseFirstIF(pAS_Info);
1361
1362 if (new_IF1 > zfIF1) {
1363 pAS_Info->f_LO1 += (new_IF1 - zfIF1);
1364 pAS_Info->f_LO2 += (new_IF1 - zfIF1);
1365 } else {
1366 pAS_Info->f_LO1 -= (zfIF1 - new_IF1);
1367 pAS_Info->f_LO2 -= (zfIF1 - new_IF1);
1368 }
1369 zfIF1 = new_IF1;
1370
1371 if (zfIF1 > pAS_Info->f_if1_Center)
1372 delta_IF1 = zfIF1 - pAS_Info->f_if1_Center;
1373 else
1374 delta_IF1 = pAS_Info->f_if1_Center - zfIF1;
1375 }
1376 /*
1377 ** Continue while the new 1st IF is still within the 1st IF bandwidth
1378 ** and there is a spur in the band (again)
1379 */
1380 while ((2 * delta_IF1 + pAS_Info->f_out_bw <=
1381 pAS_Info->f_if1_bw)
1382 && (pAS_Info->bSpurPresent =
1383 IsSpurInBand(pAS_Info, &fm, &fp)));
1384
1385 /*
1386 ** Use the LO-spur free values found. If the search went all the way to
1387 ** the 1st IF band edge and always found spurs, just leave the original
1388 ** choice. It's as "good" as any other.
1389 */
1390 if (pAS_Info->bSpurPresent == 1) {
1391 status |= MT2063_SPUR_PRESENT_ERR;
1392 pAS_Info->f_LO1 = zfLO1;
1393 pAS_Info->f_LO2 = zfLO2;
1394 } else
1395 pAS_Info->bSpurAvoided = 1;
1396 }
1397
1398 status |=
1399 ((pAS_Info->
1400 nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK);
1401
1402 return (status);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001403}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001404
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001405u32 MT2063_AvoidSpursVersion(void)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001406{
1407 return (MT2063_SPUR_VERSION);
1408}
1409
1410//end of mt2063_spuravoid.c
1411//=================================================================
1412//#################################################################
1413//=================================================================
1414
1415/*
1416** The expected version of MT_AvoidSpursData_t
1417** If the version is different, an updated file is needed from Microtune
1418*/
1419/* Expecting version 1.21 of the Spur Avoidance API */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001420
1421typedef enum {
1422 MT2063_SET_ATTEN,
1423 MT2063_INCR_ATTEN,
1424 MT2063_DECR_ATTEN
1425} MT2063_ATTEN_CNTL_MODE;
1426
1427//#define TUNER_MT2063_OPTIMIZATION
1428/*
1429** Constants used by the tuning algorithm
1430*/
1431#define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */
1432#define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */
1433#define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */
1434#define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */
1435#define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */
1436#define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */
1437#define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */
1438#define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */
1439#define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */
1440#define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */
1441#define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */
1442#define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */
1443#define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */
1444#define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */
1445#define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */
1446#define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */
1447#define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */
1448#define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */
1449
1450/*
1451** Define the supported Part/Rev codes for the MT2063
1452*/
1453#define MT2063_B0 (0x9B)
1454#define MT2063_B1 (0x9C)
1455#define MT2063_B2 (0x9D)
1456#define MT2063_B3 (0x9E)
1457
1458/*
1459** The number of Tuner Registers
1460*/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001461static const u32 MT2063_Num_Registers = MT2063_REG_END_REGS;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001462
1463#define USE_GLOBAL_TUNER 0
1464
Mauro Carvalho Chehaba0813ea2011-07-20 21:19:08 -03001465static u32 nMT2063MaxTuners = 1;
1466static struct MT2063_Info_t MT2063_Info[1];
1467static struct MT2063_Info_t *MT2063_Avail[1];
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001468static u32 nMT2063OpenTuners = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001469
1470/*
1471** Constants for setting receiver modes.
1472** (6 modes defined at this time, enumerated by MT2063_RCVR_MODES)
1473** (DNC1GC & DNC2GC are the values, which are used, when the specific
1474** DNC Output is selected, the other is always off)
1475**
1476** If PAL-L or L' is received, set:
1477** MT2063_SetParam(hMT2063,MT2063_TAGC,1);
1478**
1479** --------------+----------------------------------------------
1480** Mode 0 : | MT2063_CABLE_QAM
1481** Mode 1 : | MT2063_CABLE_ANALOG
1482** Mode 2 : | MT2063_OFFAIR_COFDM
1483** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
1484** Mode 4 : | MT2063_OFFAIR_ANALOG
1485** Mode 5 : | MT2063_OFFAIR_8VSB
1486** --------------+----+----+----+----+-----+-----+--------------
1487** Mode | 0 | 1 | 2 | 3 | 4 | 5 |
1488** --------------+----+----+----+----+-----+-----+
1489**
1490**
1491*/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001492static const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 };
1493static const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 };
1494static const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 };
1495static const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 };
1496static const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 };
1497static const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 };
1498static const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 };
1499static const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 };
1500static const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
1501static const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 };
1502static const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 };
1503static const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
1504static const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 };
1505static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 };
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001506
1507/*
1508** Local Function Prototypes - not available for external access.
1509*/
1510
1511/* Forward declaration(s): */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001512static u32 MT2063_CalcLO1Mult(u32 * Div, u32 * FracN, u32 f_LO,
1513 u32 f_LO_Step, u32 f_Ref);
1514static u32 MT2063_CalcLO2Mult(u32 * Div, u32 * FracN, u32 f_LO,
1515 u32 f_LO_Step, u32 f_Ref);
1516static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num,
1517 u32 denom);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001518
1519/******************************************************************************
1520**
1521** Name: MT2063_Open
1522**
1523** Description: Initialize the tuner's register values.
1524**
1525** Parameters: MT2063_Addr - Serial bus address of the tuner.
1526** hMT2063 - Tuner handle passed back.
1527** hUserData - User-defined data, if needed for the
1528** MT_ReadSub() & MT_WriteSub functions.
1529**
1530** Returns: status:
1531** MT_OK - No errors
1532** MT_TUNER_ID_ERR - Tuner Part/Rev code mismatch
1533** MT_TUNER_INIT_ERR - Tuner initialization failed
1534** MT_COMM_ERR - Serial bus communications error
1535** MT_ARG_NULL - Null pointer argument passed
1536** MT_TUNER_CNT_ERR - Too many tuners open
1537**
1538** Dependencies: MT_ReadSub - Read byte(s) of data from the two-wire bus
1539** MT_WriteSub - Write byte(s) of data to the two-wire bus
1540**
1541** Revision History:
1542**
1543** SCR Date Author Description
1544** -------------------------------------------------------------------------
1545** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1546**
1547******************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001548u32 MT2063_Open(u32 MT2063_Addr, void ** hMT2063, void *hUserData)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001549{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001550 u32 status = MT2063_OK; /* Status to be returned. */
1551 s32 i;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001552 struct MT2063_Info_t *pInfo = NULL;
1553 struct dvb_frontend *fe = (struct dvb_frontend *)hUserData;
1554 struct mt2063_state *state = fe->tuner_priv;
1555
1556 /* Check the argument before using */
1557 if (hMT2063 == NULL) {
1558 return MT2063_ARG_NULL;
1559 }
1560
1561 /* Default tuner handle to NULL. If successful, it will be reassigned */
1562
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001563 if (state->MT2063_init == false) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001564 pInfo = kzalloc(sizeof(struct MT2063_Info_t), GFP_KERNEL);
1565 if (pInfo == NULL) {
1566 return MT2063_TUNER_OPEN_ERR;
1567 }
1568 pInfo->handle = NULL;
1569 pInfo->address = MAX_UDATA;
1570 pInfo->rcvr_mode = MT2063_CABLE_QAM;
1571 pInfo->hUserData = NULL;
1572 } else {
1573 pInfo = *hMT2063;
1574 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001575
1576 if (MT2063_NO_ERROR(status)) {
1577 status |= MT2063_RegisterTuner(&pInfo->AS_Data);
1578 }
1579
1580 if (MT2063_NO_ERROR(status)) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001581 pInfo->handle = (void *) pInfo;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001582
1583 pInfo->hUserData = hUserData;
1584 pInfo->address = MT2063_Addr;
1585 pInfo->rcvr_mode = MT2063_CABLE_QAM;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001586 status |= MT2063_ReInit((void *) pInfo);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001587 }
1588
1589 if (MT2063_IS_ERROR(status))
1590 /* MT2063_Close handles the un-registration of the tuner */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001591 MT2063_Close((void *) pInfo);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001592 else {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001593 state->MT2063_init = true;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001594 *hMT2063 = pInfo->handle;
1595
1596 }
1597
1598 return (status);
1599}
1600
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001601static u32 MT2063_IsValidHandle(struct MT2063_Info_t *handle)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001602{
1603 return ((handle != NULL) && (handle->handle == handle)) ? 1 : 0;
1604}
1605
1606/******************************************************************************
1607**
1608** Name: MT2063_Close
1609**
1610** Description: Release the handle to the tuner.
1611**
1612** Parameters: hMT2063 - Handle to the MT2063 tuner
1613**
1614** Returns: status:
1615** MT_OK - No errors
1616** MT_INV_HANDLE - Invalid tuner handle
1617**
1618** Dependencies: mt_errordef.h - definition of error codes
1619**
1620** Revision History:
1621**
1622** SCR Date Author Description
1623** -------------------------------------------------------------------------
1624** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1625**
1626******************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001627u32 MT2063_Close(void *hMT2063)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001628{
1629 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)hMT2063;
1630
1631 if (!MT2063_IsValidHandle(pInfo))
1632 return MT2063_INV_HANDLE;
1633
1634 /* Unregister tuner with SpurAvoidance routines (if needed) */
1635 MT2063_UnRegisterTuner(&pInfo->AS_Data);
1636 /* Now remove the tuner from our own list of tuners */
1637 pInfo->handle = NULL;
1638 pInfo->address = MAX_UDATA;
1639 pInfo->hUserData = NULL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001640 //kfree(pInfo);
1641 //pInfo = NULL;
Mauro Carvalho Chehaba0813ea2011-07-20 21:19:08 -03001642
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001643 return MT2063_OK;
1644}
1645
1646/******************************************************************************
1647**
1648** Name: MT2063_GetGPIO
1649**
1650** Description: Get the current MT2063 GPIO value.
1651**
1652** Parameters: h - Open handle to the tuner (from MT2063_Open).
1653** gpio_id - Selects GPIO0, GPIO1 or GPIO2
1654** attr - Selects input readback, I/O direction or
1655** output value
1656** *value - current setting of GPIO pin
1657**
1658** Usage: status = MT2063_GetGPIO(hMT2063, MT2063_GPIO_OUT, &value);
1659**
1660** Returns: status:
1661** MT_OK - No errors
1662** MT_COMM_ERR - Serial bus communications error
1663** MT_INV_HANDLE - Invalid tuner handle
1664** MT_ARG_NULL - Null pointer argument passed
1665**
1666** Dependencies: MT_ReadSub - Read byte(s) of data from the serial bus
1667**
1668** Revision History:
1669**
1670** SCR Date Author Description
1671** -------------------------------------------------------------------------
1672** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1673**
1674******************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001675u32 MT2063_GetGPIO(void *h, enum MT2063_GPIO_ID gpio_id,
1676 enum MT2063_GPIO_Attr attr, u32 * value)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001677{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001678 u32 status = MT2063_OK; /* Status to be returned */
1679 u8 regno;
1680 s32 shift;
1681 static u8 GPIOreg[3] =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001682 { MT2063_REG_RF_STATUS, MT2063_REG_FIF_OV, MT2063_REG_RF_OV };
1683 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
1684
1685 if (MT2063_IsValidHandle(pInfo) == 0)
1686 return MT2063_INV_HANDLE;
1687
1688 if (value == NULL)
1689 return MT2063_ARG_NULL;
1690
1691 regno = GPIOreg[attr];
1692
1693 /* We'll read the register just in case the write didn't work last time */
1694 status =
1695 MT2063_ReadSub(pInfo->hUserData, pInfo->address, regno,
1696 &pInfo->reg[regno], 1);
1697
1698 shift = (gpio_id - MT2063_GPIO0 + 5);
1699 *value = (pInfo->reg[regno] >> shift) & 1;
1700
1701 return (status);
1702}
1703
1704/****************************************************************************
1705**
1706** Name: MT2063_GetLocked
1707**
1708** Description: Checks to see if LO1 and LO2 are locked.
1709**
1710** Parameters: h - Open handle to the tuner (from MT2063_Open).
1711**
1712** Returns: status:
1713** MT_OK - No errors
1714** MT_UPC_UNLOCK - Upconverter PLL unlocked
1715** MT_DNC_UNLOCK - Downconverter PLL unlocked
1716** MT_COMM_ERR - Serial bus communications error
1717** MT_INV_HANDLE - Invalid tuner handle
1718**
1719** Dependencies: MT_ReadSub - Read byte(s) of data from the serial bus
1720** MT_Sleep - Delay execution for x milliseconds
1721**
1722** Revision History:
1723**
1724** SCR Date Author Description
1725** -------------------------------------------------------------------------
1726** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1727**
1728****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001729u32 MT2063_GetLocked(void *h)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001730{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001731 const u32 nMaxWait = 100; /* wait a maximum of 100 msec */
1732 const u32 nPollRate = 2; /* poll status bits every 2 ms */
1733 const u32 nMaxLoops = nMaxWait / nPollRate;
1734 const u8 LO1LK = 0x80;
1735 u8 LO2LK = 0x08;
1736 u32 status = MT2063_OK; /* Status to be returned */
1737 u32 nDelays = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001738 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
1739
1740 if (MT2063_IsValidHandle(pInfo) == 0)
1741 return MT2063_INV_HANDLE;
1742
1743 /* LO2 Lock bit was in a different place for B0 version */
1744 if (pInfo->tuner_id == MT2063_B0)
1745 LO2LK = 0x40;
1746
1747 do {
1748 status |=
1749 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
1750 MT2063_REG_LO_STATUS,
1751 &pInfo->reg[MT2063_REG_LO_STATUS], 1);
1752
1753 if (MT2063_IS_ERROR(status))
1754 return (status);
1755
1756 if ((pInfo->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) ==
1757 (LO1LK | LO2LK)) {
1758 return (status);
1759 }
1760 MT2063_Sleep(pInfo->hUserData, nPollRate); /* Wait between retries */
1761 }
1762 while (++nDelays < nMaxLoops);
1763
1764 if ((pInfo->reg[MT2063_REG_LO_STATUS] & LO1LK) == 0x00)
1765 status |= MT2063_UPC_UNLOCK;
1766 if ((pInfo->reg[MT2063_REG_LO_STATUS] & LO2LK) == 0x00)
1767 status |= MT2063_DNC_UNLOCK;
1768
1769 return (status);
1770}
1771
1772/****************************************************************************
1773**
1774** Name: MT2063_GetParam
1775**
1776** Description: Gets a tuning algorithm parameter.
1777**
1778** This function provides access to the internals of the
1779** tuning algorithm - mostly for testing purposes.
1780**
1781** Parameters: h - Tuner handle (returned by MT2063_Open)
1782** param - Tuning algorithm parameter
1783** (see enum MT2063_Param)
1784** pValue - ptr to returned value
1785**
1786** param Description
1787** ---------------------- --------------------------------
1788** MT2063_IC_ADDR Serial Bus address of this tuner
1789** MT2063_MAX_OPEN Max # of MT2063's allowed open
1790** MT2063_NUM_OPEN # of MT2063's open
1791** MT2063_SRO_FREQ crystal frequency
1792** MT2063_STEPSIZE minimum tuning step size
1793** MT2063_INPUT_FREQ input center frequency
1794** MT2063_LO1_FREQ LO1 Frequency
1795** MT2063_LO1_STEPSIZE LO1 minimum step size
1796** MT2063_LO1_FRACN_AVOID LO1 FracN keep-out region
1797** MT2063_IF1_ACTUAL Current 1st IF in use
1798** MT2063_IF1_REQUEST Requested 1st IF
1799** MT2063_IF1_CENTER Center of 1st IF SAW filter
1800** MT2063_IF1_BW Bandwidth of 1st IF SAW filter
1801** MT2063_ZIF_BW zero-IF bandwidth
1802** MT2063_LO2_FREQ LO2 Frequency
1803** MT2063_LO2_STEPSIZE LO2 minimum step size
1804** MT2063_LO2_FRACN_AVOID LO2 FracN keep-out region
1805** MT2063_OUTPUT_FREQ output center frequency
1806** MT2063_OUTPUT_BW output bandwidth
1807** MT2063_LO_SEPARATION min inter-tuner LO separation
1808** MT2063_AS_ALG ID of avoid-spurs algorithm in use
1809** MT2063_MAX_HARM1 max # of intra-tuner harmonics
1810** MT2063_MAX_HARM2 max # of inter-tuner harmonics
1811** MT2063_EXCL_ZONES # of 1st IF exclusion zones
1812** MT2063_NUM_SPURS # of spurs found/avoided
1813** MT2063_SPUR_AVOIDED >0 spurs avoided
1814** MT2063_SPUR_PRESENT >0 spurs in output (mathematically)
1815** MT2063_RCVR_MODE Predefined modes.
1816** MT2063_ACLNA LNA attenuator gain code
1817** MT2063_ACRF RF attenuator gain code
1818** MT2063_ACFIF FIF attenuator gain code
1819** MT2063_ACLNA_MAX LNA attenuator limit
1820** MT2063_ACRF_MAX RF attenuator limit
1821** MT2063_ACFIF_MAX FIF attenuator limit
1822** MT2063_PD1 Actual value of PD1
1823** MT2063_PD2 Actual value of PD2
1824** MT2063_DNC_OUTPUT_ENABLE DNC output selection
1825** MT2063_VGAGC VGA gain code
1826** MT2063_VGAOI VGA output current
1827** MT2063_TAGC TAGC setting
1828** MT2063_AMPGC AMP gain code
1829** MT2063_AVOID_DECT Avoid DECT Frequencies
1830** MT2063_CTFILT_SW Cleartune filter selection
1831**
1832** Usage: status |= MT2063_GetParam(hMT2063,
1833** MT2063_IF1_ACTUAL,
1834** &f_IF1_Actual);
1835**
1836** Returns: status:
1837** MT_OK - No errors
1838** MT_INV_HANDLE - Invalid tuner handle
1839** MT_ARG_NULL - Null pointer argument passed
1840** MT_ARG_RANGE - Invalid parameter requested
1841**
1842** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
1843**
1844** See Also: MT2063_SetParam, MT2063_Open
1845**
1846** Revision History:
1847**
1848** SCR Date Author Description
1849** -------------------------------------------------------------------------
1850** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1851** 154 09-13-2007 RSK Ver 1.05: Get/SetParam changes for LOx_FREQ
1852** 10-31-2007 PINZ Ver 1.08: Get/SetParam add VGAGC, VGAOI, AMPGC, TAGC
1853** 173 M 01-23-2008 RSK Ver 1.12: Read LO1C and LO2C registers from HW
1854** in GetParam.
1855** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
1856** Split SetParam up to ACLNA / ACLNA_MAX
1857** removed ACLNA_INRC/DECR (+RF & FIF)
1858** removed GCUAUTO / BYPATNDN/UP
1859** 175 I 16-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
1860** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
1861** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
1862**
1863****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001864u32 MT2063_GetParam(void *h, enum MT2063_Param param, u32 * pValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001865{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001866 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001867 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001868 u32 Div;
1869 u32 Num;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001870
1871 if (pValue == NULL)
1872 status |= MT2063_ARG_NULL;
1873
1874 /* Verify that the handle passed points to a valid tuner */
1875 if (MT2063_IsValidHandle(pInfo) == 0)
1876 status |= MT2063_INV_HANDLE;
1877
1878 if (MT2063_NO_ERROR(status)) {
1879 switch (param) {
1880 /* Serial Bus address of this tuner */
1881 case MT2063_IC_ADDR:
1882 *pValue = pInfo->address;
1883 break;
1884
1885 /* Max # of MT2063's allowed to be open */
1886 case MT2063_MAX_OPEN:
1887 *pValue = nMT2063MaxTuners;
1888 break;
1889
1890 /* # of MT2063's open */
1891 case MT2063_NUM_OPEN:
1892 *pValue = nMT2063OpenTuners;
1893 break;
1894
1895 /* crystal frequency */
1896 case MT2063_SRO_FREQ:
1897 *pValue = pInfo->AS_Data.f_ref;
1898 break;
1899
1900 /* minimum tuning step size */
1901 case MT2063_STEPSIZE:
1902 *pValue = pInfo->AS_Data.f_LO2_Step;
1903 break;
1904
1905 /* input center frequency */
1906 case MT2063_INPUT_FREQ:
1907 *pValue = pInfo->AS_Data.f_in;
1908 break;
1909
1910 /* LO1 Frequency */
1911 case MT2063_LO1_FREQ:
1912 {
1913 /* read the actual tuner register values for LO1C_1 and LO1C_2 */
1914 status |=
1915 MT2063_ReadSub(pInfo->hUserData,
1916 pInfo->address,
1917 MT2063_REG_LO1C_1,
1918 &pInfo->
1919 reg[MT2063_REG_LO1C_1], 2);
1920 Div = pInfo->reg[MT2063_REG_LO1C_1];
1921 Num = pInfo->reg[MT2063_REG_LO1C_2] & 0x3F;
1922 pInfo->AS_Data.f_LO1 =
1923 (pInfo->AS_Data.f_ref * Div) +
1924 MT2063_fLO_FractionalTerm(pInfo->AS_Data.
1925 f_ref, Num, 64);
1926 }
1927 *pValue = pInfo->AS_Data.f_LO1;
1928 break;
1929
1930 /* LO1 minimum step size */
1931 case MT2063_LO1_STEPSIZE:
1932 *pValue = pInfo->AS_Data.f_LO1_Step;
1933 break;
1934
1935 /* LO1 FracN keep-out region */
1936 case MT2063_LO1_FRACN_AVOID_PARAM:
1937 *pValue = pInfo->AS_Data.f_LO1_FracN_Avoid;
1938 break;
1939
1940 /* Current 1st IF in use */
1941 case MT2063_IF1_ACTUAL:
1942 *pValue = pInfo->f_IF1_actual;
1943 break;
1944
1945 /* Requested 1st IF */
1946 case MT2063_IF1_REQUEST:
1947 *pValue = pInfo->AS_Data.f_if1_Request;
1948 break;
1949
1950 /* Center of 1st IF SAW filter */
1951 case MT2063_IF1_CENTER:
1952 *pValue = pInfo->AS_Data.f_if1_Center;
1953 break;
1954
1955 /* Bandwidth of 1st IF SAW filter */
1956 case MT2063_IF1_BW:
1957 *pValue = pInfo->AS_Data.f_if1_bw;
1958 break;
1959
1960 /* zero-IF bandwidth */
1961 case MT2063_ZIF_BW:
1962 *pValue = pInfo->AS_Data.f_zif_bw;
1963 break;
1964
1965 /* LO2 Frequency */
1966 case MT2063_LO2_FREQ:
1967 {
1968 /* Read the actual tuner register values for LO2C_1, LO2C_2 and LO2C_3 */
1969 status |=
1970 MT2063_ReadSub(pInfo->hUserData,
1971 pInfo->address,
1972 MT2063_REG_LO2C_1,
1973 &pInfo->
1974 reg[MT2063_REG_LO2C_1], 3);
1975 Div =
1976 (pInfo->reg[MT2063_REG_LO2C_1] & 0xFE) >> 1;
1977 Num =
1978 ((pInfo->
1979 reg[MT2063_REG_LO2C_1] & 0x01) << 12) |
1980 (pInfo->
1981 reg[MT2063_REG_LO2C_2] << 4) | (pInfo->
1982 reg
1983 [MT2063_REG_LO2C_3]
1984 & 0x00F);
1985 pInfo->AS_Data.f_LO2 =
1986 (pInfo->AS_Data.f_ref * Div) +
1987 MT2063_fLO_FractionalTerm(pInfo->AS_Data.
1988 f_ref, Num, 8191);
1989 }
1990 *pValue = pInfo->AS_Data.f_LO2;
1991 break;
1992
1993 /* LO2 minimum step size */
1994 case MT2063_LO2_STEPSIZE:
1995 *pValue = pInfo->AS_Data.f_LO2_Step;
1996 break;
1997
1998 /* LO2 FracN keep-out region */
1999 case MT2063_LO2_FRACN_AVOID:
2000 *pValue = pInfo->AS_Data.f_LO2_FracN_Avoid;
2001 break;
2002
2003 /* output center frequency */
2004 case MT2063_OUTPUT_FREQ:
2005 *pValue = pInfo->AS_Data.f_out;
2006 break;
2007
2008 /* output bandwidth */
2009 case MT2063_OUTPUT_BW:
2010 *pValue = pInfo->AS_Data.f_out_bw - 750000;
2011 break;
2012
2013 /* min inter-tuner LO separation */
2014 case MT2063_LO_SEPARATION:
2015 *pValue = pInfo->AS_Data.f_min_LO_Separation;
2016 break;
2017
2018 /* ID of avoid-spurs algorithm in use */
2019 case MT2063_AS_ALG:
2020 *pValue = pInfo->AS_Data.nAS_Algorithm;
2021 break;
2022
2023 /* max # of intra-tuner harmonics */
2024 case MT2063_MAX_HARM1:
2025 *pValue = pInfo->AS_Data.maxH1;
2026 break;
2027
2028 /* max # of inter-tuner harmonics */
2029 case MT2063_MAX_HARM2:
2030 *pValue = pInfo->AS_Data.maxH2;
2031 break;
2032
2033 /* # of 1st IF exclusion zones */
2034 case MT2063_EXCL_ZONES:
2035 *pValue = pInfo->AS_Data.nZones;
2036 break;
2037
2038 /* # of spurs found/avoided */
2039 case MT2063_NUM_SPURS:
2040 *pValue = pInfo->AS_Data.nSpursFound;
2041 break;
2042
2043 /* >0 spurs avoided */
2044 case MT2063_SPUR_AVOIDED:
2045 *pValue = pInfo->AS_Data.bSpurAvoided;
2046 break;
2047
2048 /* >0 spurs in output (mathematically) */
2049 case MT2063_SPUR_PRESENT:
2050 *pValue = pInfo->AS_Data.bSpurPresent;
2051 break;
2052
2053 /* Predefined receiver setup combination */
2054 case MT2063_RCVR_MODE:
2055 *pValue = pInfo->rcvr_mode;
2056 break;
2057
2058 case MT2063_PD1:
2059 case MT2063_PD2:
2060 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002061 u8 mask = (param == MT2063_PD1 ? 0x01 : 0x03); /* PD1 vs PD2 */
2062 u8 orig = (pInfo->reg[MT2063_REG_BYP_CTRL]);
2063 u8 reg = (orig & 0xF1) | mask; /* Only set 3 bits (not 5) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002064 int i;
2065
2066 *pValue = 0;
2067
2068 /* Initiate ADC output to reg 0x0A */
2069 if (reg != orig)
2070 status |=
2071 MT2063_WriteSub(pInfo->hUserData,
2072 pInfo->address,
2073 MT2063_REG_BYP_CTRL,
2074 &reg, 1);
2075
2076 if (MT2063_IS_ERROR(status))
2077 return (status);
2078
2079 for (i = 0; i < 8; i++) {
2080 status |=
2081 MT2063_ReadSub(pInfo->hUserData,
2082 pInfo->address,
2083 MT2063_REG_ADC_OUT,
2084 &pInfo->
2085 reg
2086 [MT2063_REG_ADC_OUT],
2087 1);
2088
2089 if (MT2063_NO_ERROR(status))
2090 *pValue +=
2091 pInfo->
2092 reg[MT2063_REG_ADC_OUT];
2093 else {
2094 if (i)
2095 *pValue /= i;
2096 return (status);
2097 }
2098 }
2099 *pValue /= 8; /* divide by number of reads */
2100 *pValue >>= 2; /* only want 6 MSB's out of 8 */
2101
2102 /* Restore value of Register BYP_CTRL */
2103 if (reg != orig)
2104 status |=
2105 MT2063_WriteSub(pInfo->hUserData,
2106 pInfo->address,
2107 MT2063_REG_BYP_CTRL,
2108 &orig, 1);
2109 }
2110 break;
2111
2112 /* Get LNA attenuator code */
2113 case MT2063_ACLNA:
2114 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002115 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002116 status |=
2117 MT2063_GetReg(pInfo, MT2063_REG_XO_STATUS,
2118 &val);
2119 *pValue = val & 0x1f;
2120 }
2121 break;
2122
2123 /* Get RF attenuator code */
2124 case MT2063_ACRF:
2125 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002126 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002127 status |=
2128 MT2063_GetReg(pInfo, MT2063_REG_RF_STATUS,
2129 &val);
2130 *pValue = val & 0x1f;
2131 }
2132 break;
2133
2134 /* Get FIF attenuator code */
2135 case MT2063_ACFIF:
2136 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002137 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002138 status |=
2139 MT2063_GetReg(pInfo, MT2063_REG_FIF_STATUS,
2140 &val);
2141 *pValue = val & 0x1f;
2142 }
2143 break;
2144
2145 /* Get LNA attenuator limit */
2146 case MT2063_ACLNA_MAX:
2147 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002148 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002149 status |=
2150 MT2063_GetReg(pInfo, MT2063_REG_LNA_OV,
2151 &val);
2152 *pValue = val & 0x1f;
2153 }
2154 break;
2155
2156 /* Get RF attenuator limit */
2157 case MT2063_ACRF_MAX:
2158 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002159 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002160 status |=
2161 MT2063_GetReg(pInfo, MT2063_REG_RF_OV,
2162 &val);
2163 *pValue = val & 0x1f;
2164 }
2165 break;
2166
2167 /* Get FIF attenuator limit */
2168 case MT2063_ACFIF_MAX:
2169 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002170 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002171 status |=
2172 MT2063_GetReg(pInfo, MT2063_REG_FIF_OV,
2173 &val);
2174 *pValue = val & 0x1f;
2175 }
2176 break;
2177
2178 /* Get current used DNC output */
2179 case MT2063_DNC_OUTPUT_ENABLE:
2180 {
2181 if ((pInfo->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */
2182 if ((pInfo->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
2183 *pValue =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002184 (u32) MT2063_DNC_NONE;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002185 else
2186 *pValue =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002187 (u32) MT2063_DNC_2;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002188 } else { /* DNC1 is on */
2189
2190 if ((pInfo->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
2191 *pValue =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002192 (u32) MT2063_DNC_1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002193 else
2194 *pValue =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002195 (u32) MT2063_DNC_BOTH;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002196 }
2197 }
2198 break;
2199
2200 /* Get VGA Gain Code */
2201 case MT2063_VGAGC:
2202 *pValue =
2203 ((pInfo->reg[MT2063_REG_VGA_GAIN] & 0x0C) >> 2);
2204 break;
2205
2206 /* Get VGA bias current */
2207 case MT2063_VGAOI:
2208 *pValue = (pInfo->reg[MT2063_REG_RSVD_31] & 0x07);
2209 break;
2210
2211 /* Get TAGC setting */
2212 case MT2063_TAGC:
2213 *pValue = (pInfo->reg[MT2063_REG_RSVD_1E] & 0x03);
2214 break;
2215
2216 /* Get AMP Gain Code */
2217 case MT2063_AMPGC:
2218 *pValue = (pInfo->reg[MT2063_REG_TEMP_SEL] & 0x03);
2219 break;
2220
2221 /* Avoid DECT Frequencies */
2222 case MT2063_AVOID_DECT:
2223 *pValue = pInfo->AS_Data.avoidDECT;
2224 break;
2225
2226 /* Cleartune filter selection: 0 - by IC (default), 1 - by software */
2227 case MT2063_CTFILT_SW:
2228 *pValue = pInfo->ctfilt_sw;
2229 break;
2230
2231 case MT2063_EOP:
2232 default:
2233 status |= MT2063_ARG_RANGE;
2234 }
2235 }
2236 return (status);
2237}
2238
2239/****************************************************************************
2240**
2241** Name: MT2063_GetReg
2242**
2243** Description: Gets an MT2063 register.
2244**
2245** Parameters: h - Tuner handle (returned by MT2063_Open)
2246** reg - MT2063 register/subaddress location
2247** *val - MT2063 register/subaddress value
2248**
2249** Returns: status:
2250** MT_OK - No errors
2251** MT_COMM_ERR - Serial bus communications error
2252** MT_INV_HANDLE - Invalid tuner handle
2253** MT_ARG_NULL - Null pointer argument passed
2254** MT_ARG_RANGE - Argument out of range
2255**
2256** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
2257**
2258** Use this function if you need to read a register from
2259** the MT2063.
2260**
2261** Revision History:
2262**
2263** SCR Date Author Description
2264** -------------------------------------------------------------------------
2265** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2266**
2267****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002268u32 MT2063_GetReg(void *h, u8 reg, u8 * val)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002269{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002270 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002271 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
2272
2273 /* Verify that the handle passed points to a valid tuner */
2274 if (MT2063_IsValidHandle(pInfo) == 0)
2275 status |= MT2063_INV_HANDLE;
2276
2277 if (val == NULL)
2278 status |= MT2063_ARG_NULL;
2279
2280 if (reg >= MT2063_REG_END_REGS)
2281 status |= MT2063_ARG_RANGE;
2282
2283 if (MT2063_NO_ERROR(status)) {
2284 status |=
2285 MT2063_ReadSub(pInfo->hUserData, pInfo->address, reg,
2286 &pInfo->reg[reg], 1);
2287 if (MT2063_NO_ERROR(status))
2288 *val = pInfo->reg[reg];
2289 }
2290
2291 return (status);
2292}
2293
2294/******************************************************************************
2295**
2296** Name: MT2063_GetTemp
2297**
2298** Description: Get the MT2063 Temperature register.
2299**
2300** Parameters: h - Open handle to the tuner (from MT2063_Open).
2301** *value - value read from the register
2302**
2303** Binary
2304** Value Returned Value Approx Temp
2305** ---------------------------------------------
2306** MT2063_T_0C 0000 0C
2307** MT2063_T_10C 0001 10C
2308** MT2063_T_20C 0010 20C
2309** MT2063_T_30C 0011 30C
2310** MT2063_T_40C 0100 40C
2311** MT2063_T_50C 0101 50C
2312** MT2063_T_60C 0110 60C
2313** MT2063_T_70C 0111 70C
2314** MT2063_T_80C 1000 80C
2315** MT2063_T_90C 1001 90C
2316** MT2063_T_100C 1010 100C
2317** MT2063_T_110C 1011 110C
2318** MT2063_T_120C 1100 120C
2319** MT2063_T_130C 1101 130C
2320** MT2063_T_140C 1110 140C
2321** MT2063_T_150C 1111 150C
2322**
2323** Returns: status:
2324** MT_OK - No errors
2325** MT_COMM_ERR - Serial bus communications error
2326** MT_INV_HANDLE - Invalid tuner handle
2327** MT_ARG_NULL - Null pointer argument passed
2328** MT_ARG_RANGE - Argument out of range
2329**
2330** Dependencies: MT_ReadSub - Read byte(s) of data from the two-wire bus
2331** MT_WriteSub - Write byte(s) of data to the two-wire bus
2332**
2333** Revision History:
2334**
2335** SCR Date Author Description
2336** -------------------------------------------------------------------------
2337** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2338**
2339******************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002340u32 MT2063_GetTemp(void *h, enum MT2063_Temperature * value)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002341{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002342 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002343 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
2344
2345 if (MT2063_IsValidHandle(pInfo) == 0)
2346 return MT2063_INV_HANDLE;
2347
2348 if (value == NULL)
2349 return MT2063_ARG_NULL;
2350
2351 if ((MT2063_NO_ERROR(status))
2352 && ((pInfo->reg[MT2063_REG_TEMP_SEL] & 0xE0) != 0x00)) {
2353 pInfo->reg[MT2063_REG_TEMP_SEL] &= (0x1F);
2354 status |= MT2063_WriteSub(pInfo->hUserData,
2355 pInfo->address,
2356 MT2063_REG_TEMP_SEL,
2357 &pInfo->reg[MT2063_REG_TEMP_SEL], 1);
2358 }
2359
2360 if (MT2063_NO_ERROR(status))
2361 status |= MT2063_ReadSub(pInfo->hUserData,
2362 pInfo->address,
2363 MT2063_REG_TEMP_STATUS,
2364 &pInfo->reg[MT2063_REG_TEMP_STATUS],
2365 1);
2366
2367 if (MT2063_NO_ERROR(status))
2368 *value =
2369 (enum MT2063_Temperature)(pInfo->
2370 reg[MT2063_REG_TEMP_STATUS] >> 4);
2371
2372 return (status);
2373}
2374
2375/****************************************************************************
2376**
2377** Name: MT2063_GetUserData
2378**
2379** Description: Gets the user-defined data item.
2380**
2381** Parameters: h - Tuner handle (returned by MT2063_Open)
2382**
2383** Returns: status:
2384** MT_OK - No errors
2385** MT_INV_HANDLE - Invalid tuner handle
2386** MT_ARG_NULL - Null pointer argument passed
2387**
2388** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
2389**
2390** The hUserData parameter is a user-specific argument
2391** that is stored internally with the other tuner-
2392** specific information.
2393**
2394** For example, if additional arguments are needed
2395** for the user to identify the device communicating
2396** with the tuner, this argument can be used to supply
2397** the necessary information.
2398**
2399** The hUserData parameter is initialized in the tuner's
2400** Open function to NULL.
2401**
2402** See Also: MT2063_Open
2403**
2404** Revision History:
2405**
2406** SCR Date Author Description
2407** -------------------------------------------------------------------------
2408** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2409**
2410****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002411u32 MT2063_GetUserData(void *h, void ** hUserData)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002412{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002413 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002414 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
2415
2416 /* Verify that the handle passed points to a valid tuner */
2417 if (MT2063_IsValidHandle(pInfo) == 0)
2418 status = MT2063_INV_HANDLE;
2419
2420 if (hUserData == NULL)
2421 status |= MT2063_ARG_NULL;
2422
2423 if (MT2063_NO_ERROR(status))
2424 *hUserData = pInfo->hUserData;
2425
2426 return (status);
2427}
2428
2429/******************************************************************************
2430**
2431** Name: MT2063_SetReceiverMode
2432**
2433** Description: Set the MT2063 receiver mode
2434**
2435** --------------+----------------------------------------------
2436** Mode 0 : | MT2063_CABLE_QAM
2437** Mode 1 : | MT2063_CABLE_ANALOG
2438** Mode 2 : | MT2063_OFFAIR_COFDM
2439** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
2440** Mode 4 : | MT2063_OFFAIR_ANALOG
2441** Mode 5 : | MT2063_OFFAIR_8VSB
2442** --------------+----+----+----+----+-----+--------------------
2443** (DNC1GC & DNC2GC are the values, which are used, when the specific
2444** DNC Output is selected, the other is always off)
2445**
2446** |<---------- Mode -------------->|
2447** Reg Field | 0 | 1 | 2 | 3 | 4 | 5 |
2448** ------------+-----+-----+-----+-----+-----+-----+
2449** RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF
2450** LNARin | 0 | 0 | 3 | 3 | 3 | 3
2451** FIFFQen | 1 | 1 | 1 | 1 | 1 | 1
2452** FIFFq | 0 | 0 | 0 | 0 | 0 | 0
2453** DNC1gc | 0 | 0 | 0 | 0 | 0 | 0
2454** DNC2gc | 0 | 0 | 0 | 0 | 0 | 0
2455** GCU Auto | 1 | 1 | 1 | 1 | 1 | 1
2456** LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31
2457** LNA Target | 44 | 43 | 43 | 43 | 43 | 43
2458** ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0
2459** RF max Atn | 31 | 31 | 31 | 31 | 31 | 31
2460** PD1 Target | 36 | 36 | 38 | 38 | 36 | 38
2461** ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0
2462** FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5
2463** PD2 Target | 40 | 33 | 42 | 42 | 33 | 42
2464**
2465**
2466** Parameters: pInfo - ptr to MT2063_Info_t structure
2467** Mode - desired reciever mode
2468**
2469** Usage: status = MT2063_SetReceiverMode(hMT2063, Mode);
2470**
2471** Returns: status:
2472** MT_OK - No errors
2473** MT_COMM_ERR - Serial bus communications error
2474**
2475** Dependencies: MT2063_SetReg - Write a byte of data to a HW register.
2476** Assumes that the tuner cache is valid.
2477**
2478** Revision History:
2479**
2480** SCR Date Author Description
2481** -------------------------------------------------------------------------
2482** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2483** N/A 01-10-2007 PINZ Added additional GCU Settings, FIFF Calib will be triggered
2484** 155 10-01-2007 DAD Ver 1.06: Add receiver mode for SECAM positive
2485** modulation
2486** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
2487** N/A 10-22-2007 PINZ Ver 1.07: Changed some Registers at init to have
2488** the same settings as with MT Launcher
2489** N/A 10-30-2007 PINZ Add SetParam VGAGC & VGAOI
2490** Add SetParam DNC_OUTPUT_ENABLE
2491** Removed VGAGC from receiver mode,
2492** default now 1
2493** N/A 10-31-2007 PINZ Ver 1.08: Add SetParam TAGC, removed from rcvr-mode
2494** Add SetParam AMPGC, removed from rcvr-mode
2495** Corrected names of GCU values
2496** reorganized receiver modes, removed,
2497** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
2498** Actualized Receiver-Mode values
2499** N/A 11-12-2007 PINZ Ver 1.09: Actualized Receiver-Mode values
2500** N/A 11-27-2007 PINZ Improved buffered writing
2501** 01-03-2008 PINZ Ver 1.10: Added a trigger of BYPATNUP for
2502** correct wakeup of the LNA after shutdown
2503** Set AFCsd = 1 as default
2504** Changed CAP1sel default
2505** 01-14-2008 PINZ Ver 1.11: Updated gain settings
2506** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
2507** Split SetParam up to ACLNA / ACLNA_MAX
2508** removed ACLNA_INRC/DECR (+RF & FIF)
2509** removed GCUAUTO / BYPATNDN/UP
2510**
2511******************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002512static u32 MT2063_SetReceiverMode(struct MT2063_Info_t *pInfo,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002513 enum MT2063_RCVR_MODES Mode)
2514{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002515 u32 status = MT2063_OK; /* Status to be returned */
2516 u8 val;
2517 u32 longval;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002518
2519 if (Mode >= MT2063_NUM_RCVR_MODES)
2520 status = MT2063_ARG_RANGE;
2521
2522 /* RFAGCen */
2523 if (MT2063_NO_ERROR(status)) {
2524 val =
2525 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002526 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x40) | (RFAGCEN[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002527 ? 0x40 :
2528 0x00);
2529 if (pInfo->reg[MT2063_REG_PD1_TGT] != val) {
2530 status |= MT2063_SetReg(pInfo, MT2063_REG_PD1_TGT, val);
2531 }
2532 }
2533
2534 /* LNARin */
2535 if (MT2063_NO_ERROR(status)) {
2536 status |= MT2063_SetParam(pInfo, MT2063_LNA_RIN, LNARIN[Mode]);
2537 }
2538
2539 /* FIFFQEN and FIFFQ */
2540 if (MT2063_NO_ERROR(status)) {
2541 val =
2542 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002543 reg[MT2063_REG_FIFF_CTRL2] & (u8) ~ 0xF0) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002544 (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
2545 if (pInfo->reg[MT2063_REG_FIFF_CTRL2] != val) {
2546 status |=
2547 MT2063_SetReg(pInfo, MT2063_REG_FIFF_CTRL2, val);
2548 /* trigger FIFF calibration, needed after changing FIFFQ */
2549 val =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002550 (pInfo->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002551 status |=
2552 MT2063_SetReg(pInfo, MT2063_REG_FIFF_CTRL, val);
2553 val =
2554 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002555 reg[MT2063_REG_FIFF_CTRL] & (u8) ~ 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002556 status |=
2557 MT2063_SetReg(pInfo, MT2063_REG_FIFF_CTRL, val);
2558 }
2559 }
2560
2561 /* DNC1GC & DNC2GC */
2562 status |= MT2063_GetParam(pInfo, MT2063_DNC_OUTPUT_ENABLE, &longval);
2563 status |= MT2063_SetParam(pInfo, MT2063_DNC_OUTPUT_ENABLE, longval);
2564
2565 /* acLNAmax */
2566 if (MT2063_NO_ERROR(status)) {
2567 status |=
2568 MT2063_SetParam(pInfo, MT2063_ACLNA_MAX, ACLNAMAX[Mode]);
2569 }
2570
2571 /* LNATGT */
2572 if (MT2063_NO_ERROR(status)) {
2573 status |= MT2063_SetParam(pInfo, MT2063_LNA_TGT, LNATGT[Mode]);
2574 }
2575
2576 /* ACRF */
2577 if (MT2063_NO_ERROR(status)) {
2578 status |=
2579 MT2063_SetParam(pInfo, MT2063_ACRF_MAX, ACRFMAX[Mode]);
2580 }
2581
2582 /* PD1TGT */
2583 if (MT2063_NO_ERROR(status)) {
2584 status |= MT2063_SetParam(pInfo, MT2063_PD1_TGT, PD1TGT[Mode]);
2585 }
2586
2587 /* FIFATN */
2588 if (MT2063_NO_ERROR(status)) {
2589 status |=
2590 MT2063_SetParam(pInfo, MT2063_ACFIF_MAX, ACFIFMAX[Mode]);
2591 }
2592
2593 /* PD2TGT */
2594 if (MT2063_NO_ERROR(status)) {
2595 status |= MT2063_SetParam(pInfo, MT2063_PD2_TGT, PD2TGT[Mode]);
2596 }
2597
2598 /* Ignore ATN Overload */
2599 if (MT2063_NO_ERROR(status)) {
2600 val =
2601 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002602 reg[MT2063_REG_LNA_TGT] & (u8) ~ 0x80) | (RFOVDIS[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002603 ? 0x80 :
2604 0x00);
2605 if (pInfo->reg[MT2063_REG_LNA_TGT] != val) {
2606 status |= MT2063_SetReg(pInfo, MT2063_REG_LNA_TGT, val);
2607 }
2608 }
2609
2610 /* Ignore FIF Overload */
2611 if (MT2063_NO_ERROR(status)) {
2612 val =
2613 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002614 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x80) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002615 (FIFOVDIS[Mode] ? 0x80 : 0x00);
2616 if (pInfo->reg[MT2063_REG_PD1_TGT] != val) {
2617 status |= MT2063_SetReg(pInfo, MT2063_REG_PD1_TGT, val);
2618 }
2619 }
2620
2621 if (MT2063_NO_ERROR(status))
2622 pInfo->rcvr_mode = Mode;
2623
2624 return (status);
2625}
2626
2627/******************************************************************************
2628**
2629** Name: MT2063_ReInit
2630**
2631** Description: Initialize the tuner's register values.
2632**
2633** Parameters: h - Tuner handle (returned by MT2063_Open)
2634**
2635** Returns: status:
2636** MT_OK - No errors
2637** MT_TUNER_ID_ERR - Tuner Part/Rev code mismatch
2638** MT_INV_HANDLE - Invalid tuner handle
2639** MT_COMM_ERR - Serial bus communications error
2640**
2641** Dependencies: MT_ReadSub - Read byte(s) of data from the two-wire bus
2642** MT_WriteSub - Write byte(s) of data to the two-wire bus
2643**
2644** Revision History:
2645**
2646** SCR Date Author Description
2647** -------------------------------------------------------------------------
2648** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2649** 148 09-04-2007 RSK Ver 1.02: Corrected logic of Reg 3B Reference
2650** 153 09-07-2007 RSK Ver 1.03: Lock Time improvements
2651** N/A 10-31-2007 PINZ Ver 1.08: Changed values suitable to rcvr-mode 0
2652** N/A 11-12-2007 PINZ Ver 1.09: Changed values suitable to rcvr-mode 0
2653** N/A 01-03-2007 PINZ Ver 1.10: Added AFCsd = 1 into defaults
2654** N/A 01-04-2007 PINZ Ver 1.10: Changed CAP1sel default
2655** 01-14-2008 PINZ Ver 1.11: Updated gain settings
2656** 03-18-2008 PINZ Ver 1.13: Added Support for B3
2657** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
2658** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
2659**
2660******************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002661u32 MT2063_ReInit(void *h)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002662{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002663 u8 all_resets = 0xF0; /* reset/load bits */
2664 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002665 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002666 u8 *def;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002667
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002668 u8 MT2063B0_defaults[] = { /* Reg, Value */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002669 0x19, 0x05,
2670 0x1B, 0x1D,
2671 0x1C, 0x1F,
2672 0x1D, 0x0F,
2673 0x1E, 0x3F,
2674 0x1F, 0x0F,
2675 0x20, 0x3F,
2676 0x22, 0x21,
2677 0x23, 0x3F,
2678 0x24, 0x20,
2679 0x25, 0x3F,
2680 0x27, 0xEE,
2681 0x2C, 0x27, /* bit at 0x20 is cleared below */
2682 0x30, 0x03,
2683 0x2C, 0x07, /* bit at 0x20 is cleared here */
2684 0x2D, 0x87,
2685 0x2E, 0xAA,
2686 0x28, 0xE1, /* Set the FIFCrst bit here */
2687 0x28, 0xE0, /* Clear the FIFCrst bit here */
2688 0x00
2689 };
2690
2691 /* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002692 u8 MT2063B1_defaults[] = { /* Reg, Value */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002693 0x05, 0xF0,
2694 0x11, 0x10, /* New Enable AFCsd */
2695 0x19, 0x05,
2696 0x1A, 0x6C,
2697 0x1B, 0x24,
2698 0x1C, 0x28,
2699 0x1D, 0x8F,
2700 0x1E, 0x14,
2701 0x1F, 0x8F,
2702 0x20, 0x57,
2703 0x22, 0x21, /* New - ver 1.03 */
2704 0x23, 0x3C, /* New - ver 1.10 */
2705 0x24, 0x20, /* New - ver 1.03 */
2706 0x2C, 0x24, /* bit at 0x20 is cleared below */
2707 0x2D, 0x87, /* FIFFQ=0 */
2708 0x2F, 0xF3,
2709 0x30, 0x0C, /* New - ver 1.11 */
2710 0x31, 0x1B, /* New - ver 1.11 */
2711 0x2C, 0x04, /* bit at 0x20 is cleared here */
2712 0x28, 0xE1, /* Set the FIFCrst bit here */
2713 0x28, 0xE0, /* Clear the FIFCrst bit here */
2714 0x00
2715 };
2716
2717 /* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002718 u8 MT2063B3_defaults[] = { /* Reg, Value */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002719 0x05, 0xF0,
2720 0x19, 0x3D,
2721 0x2C, 0x24, /* bit at 0x20 is cleared below */
2722 0x2C, 0x04, /* bit at 0x20 is cleared here */
2723 0x28, 0xE1, /* Set the FIFCrst bit here */
2724 0x28, 0xE0, /* Clear the FIFCrst bit here */
2725 0x00
2726 };
2727
2728 /* Verify that the handle passed points to a valid tuner */
2729 if (MT2063_IsValidHandle(pInfo) == 0)
2730 status |= MT2063_INV_HANDLE;
2731
2732 /* Read the Part/Rev code from the tuner */
2733 if (MT2063_NO_ERROR(status)) {
2734 status |=
2735 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
2736 MT2063_REG_PART_REV, pInfo->reg, 1);
2737 }
2738
2739 if (MT2063_NO_ERROR(status) /* Check the part/rev code */
2740 &&((pInfo->reg[MT2063_REG_PART_REV] != MT2063_B0) /* MT2063 B0 */
2741 &&(pInfo->reg[MT2063_REG_PART_REV] != MT2063_B1) /* MT2063 B1 */
2742 &&(pInfo->reg[MT2063_REG_PART_REV] != MT2063_B3))) /* MT2063 B3 */
2743 status |= MT2063_TUNER_ID_ERR; /* Wrong tuner Part/Rev code */
2744
2745 /* Read the Part/Rev code (2nd byte) from the tuner */
2746 if (MT2063_NO_ERROR(status))
2747 status |=
2748 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
2749 MT2063_REG_RSVD_3B,
2750 &pInfo->reg[MT2063_REG_RSVD_3B], 1);
2751
2752 if (MT2063_NO_ERROR(status) /* Check the 2nd part/rev code */
2753 &&((pInfo->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) /* b7 != 0 ==> NOT MT2063 */
2754 status |= MT2063_TUNER_ID_ERR; /* Wrong tuner Part/Rev code */
2755
2756 /* Reset the tuner */
2757 if (MT2063_NO_ERROR(status))
2758 status |= MT2063_WriteSub(pInfo->hUserData,
2759 pInfo->address,
2760 MT2063_REG_LO2CQ_3, &all_resets, 1);
2761
2762 /* change all of the default values that vary from the HW reset values */
2763 /* def = (pInfo->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */
2764 switch (pInfo->reg[MT2063_REG_PART_REV]) {
2765 case MT2063_B3:
2766 def = MT2063B3_defaults;
2767 break;
2768
2769 case MT2063_B1:
2770 def = MT2063B1_defaults;
2771 break;
2772
2773 case MT2063_B0:
2774 def = MT2063B0_defaults;
2775 break;
2776
2777 default:
2778 status |= MT2063_TUNER_ID_ERR;
2779 break;
2780 }
2781
2782 while (MT2063_NO_ERROR(status) && *def) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002783 u8 reg = *def++;
2784 u8 val = *def++;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002785 status |=
2786 MT2063_WriteSub(pInfo->hUserData, pInfo->address, reg, &val,
2787 1);
2788 }
2789
2790 /* Wait for FIFF location to complete. */
2791 if (MT2063_NO_ERROR(status)) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002792 u32 FCRUN = 1;
2793 s32 maxReads = 10;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002794 while (MT2063_NO_ERROR(status) && (FCRUN != 0)
2795 && (maxReads-- > 0)) {
2796 MT2063_Sleep(pInfo->hUserData, 2);
2797 status |= MT2063_ReadSub(pInfo->hUserData,
2798 pInfo->address,
2799 MT2063_REG_XO_STATUS,
2800 &pInfo->
2801 reg[MT2063_REG_XO_STATUS], 1);
2802 FCRUN = (pInfo->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6;
2803 }
2804
2805 if (FCRUN != 0)
2806 status |= MT2063_TUNER_INIT_ERR | MT2063_TUNER_TIMEOUT;
2807
2808 if (MT2063_NO_ERROR(status)) /* Re-read FIFFC value */
2809 status |=
2810 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
2811 MT2063_REG_FIFFC,
2812 &pInfo->reg[MT2063_REG_FIFFC], 1);
2813 }
2814
2815 /* Read back all the registers from the tuner */
2816 if (MT2063_NO_ERROR(status))
2817 status |= MT2063_ReadSub(pInfo->hUserData,
2818 pInfo->address,
2819 MT2063_REG_PART_REV,
2820 pInfo->reg, MT2063_REG_END_REGS);
2821
2822 if (MT2063_NO_ERROR(status)) {
2823 /* Initialize the tuner state. */
2824 pInfo->version = MT2063_VERSION;
2825 pInfo->tuner_id = pInfo->reg[MT2063_REG_PART_REV];
2826 pInfo->AS_Data.f_ref = MT2063_REF_FREQ;
2827 pInfo->AS_Data.f_if1_Center =
2828 (pInfo->AS_Data.f_ref / 8) *
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002829 ((u32) pInfo->reg[MT2063_REG_FIFFC] + 640);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002830 pInfo->AS_Data.f_if1_bw = MT2063_IF1_BW;
2831 pInfo->AS_Data.f_out = 43750000UL;
2832 pInfo->AS_Data.f_out_bw = 6750000UL;
2833 pInfo->AS_Data.f_zif_bw = MT2063_ZIF_BW;
2834 pInfo->AS_Data.f_LO1_Step = pInfo->AS_Data.f_ref / 64;
2835 pInfo->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE;
2836 pInfo->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1;
2837 pInfo->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2;
2838 pInfo->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP;
2839 pInfo->AS_Data.f_if1_Request = pInfo->AS_Data.f_if1_Center;
2840 pInfo->AS_Data.f_LO1 = 2181000000UL;
2841 pInfo->AS_Data.f_LO2 = 1486249786UL;
2842 pInfo->f_IF1_actual = pInfo->AS_Data.f_if1_Center;
2843 pInfo->AS_Data.f_in =
2844 pInfo->AS_Data.f_LO1 - pInfo->f_IF1_actual;
2845 pInfo->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID;
2846 pInfo->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID;
2847 pInfo->num_regs = MT2063_REG_END_REGS;
2848 pInfo->AS_Data.avoidDECT = MT2063_AVOID_BOTH;
2849 pInfo->ctfilt_sw = 0;
2850 }
2851
2852 if (MT2063_NO_ERROR(status)) {
2853 pInfo->CTFiltMax[0] = 69230000;
2854 pInfo->CTFiltMax[1] = 105770000;
2855 pInfo->CTFiltMax[2] = 140350000;
2856 pInfo->CTFiltMax[3] = 177110000;
2857 pInfo->CTFiltMax[4] = 212860000;
2858 pInfo->CTFiltMax[5] = 241130000;
2859 pInfo->CTFiltMax[6] = 274370000;
2860 pInfo->CTFiltMax[7] = 309820000;
2861 pInfo->CTFiltMax[8] = 342450000;
2862 pInfo->CTFiltMax[9] = 378870000;
2863 pInfo->CTFiltMax[10] = 416210000;
2864 pInfo->CTFiltMax[11] = 456500000;
2865 pInfo->CTFiltMax[12] = 495790000;
2866 pInfo->CTFiltMax[13] = 534530000;
2867 pInfo->CTFiltMax[14] = 572610000;
2868 pInfo->CTFiltMax[15] = 598970000;
2869 pInfo->CTFiltMax[16] = 635910000;
2870 pInfo->CTFiltMax[17] = 672130000;
2871 pInfo->CTFiltMax[18] = 714840000;
2872 pInfo->CTFiltMax[19] = 739660000;
2873 pInfo->CTFiltMax[20] = 770410000;
2874 pInfo->CTFiltMax[21] = 814660000;
2875 pInfo->CTFiltMax[22] = 846950000;
2876 pInfo->CTFiltMax[23] = 867820000;
2877 pInfo->CTFiltMax[24] = 915980000;
2878 pInfo->CTFiltMax[25] = 947450000;
2879 pInfo->CTFiltMax[26] = 983110000;
2880 pInfo->CTFiltMax[27] = 1021630000;
2881 pInfo->CTFiltMax[28] = 1061870000;
2882 pInfo->CTFiltMax[29] = 1098330000;
2883 pInfo->CTFiltMax[30] = 1138990000;
2884 }
2885
2886 /*
2887 ** Fetch the FCU osc value and use it and the fRef value to
2888 ** scale all of the Band Max values
2889 */
2890 if (MT2063_NO_ERROR(status)) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002891 u32 fcu_osc;
2892 u32 i;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002893
2894 pInfo->reg[MT2063_REG_CTUNE_CTRL] = 0x0A;
2895 status |=
2896 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
2897 MT2063_REG_CTUNE_CTRL,
2898 &pInfo->reg[MT2063_REG_CTUNE_CTRL], 1);
2899 /* Read the ClearTune filter calibration value */
2900 status |=
2901 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
2902 MT2063_REG_FIFFC,
2903 &pInfo->reg[MT2063_REG_FIFFC], 1);
2904 fcu_osc = pInfo->reg[MT2063_REG_FIFFC];
2905
2906 pInfo->reg[MT2063_REG_CTUNE_CTRL] = 0x00;
2907 status |=
2908 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
2909 MT2063_REG_CTUNE_CTRL,
2910 &pInfo->reg[MT2063_REG_CTUNE_CTRL], 1);
2911
2912 /* Adjust each of the values in the ClearTune filter cross-over table */
2913 for (i = 0; i < 31; i++) {
2914 pInfo->CTFiltMax[i] =
2915 (pInfo->CTFiltMax[i] / 768) * (fcu_osc + 640);
2916 }
2917 }
2918
2919 return (status);
2920}
2921
2922/******************************************************************************
2923**
2924** Name: MT2063_SetGPIO
2925**
2926** Description: Modify the MT2063 GPIO value.
2927**
2928** Parameters: h - Open handle to the tuner (from MT2063_Open).
2929** gpio_id - Selects GPIO0, GPIO1 or GPIO2
2930** attr - Selects input readback, I/O direction or
2931** output value
2932** value - value to set GPIO pin 15, 14 or 19
2933**
2934** Usage: status = MT2063_SetGPIO(hMT2063, MT2063_GPIO1, MT2063_GPIO_OUT, 1);
2935**
2936** Returns: status:
2937** MT_OK - No errors
2938** MT_COMM_ERR - Serial bus communications error
2939** MT_INV_HANDLE - Invalid tuner handle
2940**
2941** Dependencies: MT_WriteSub - Write byte(s) of data to the two-wire-bus
2942**
2943** Revision History:
2944**
2945** SCR Date Author Description
2946** -------------------------------------------------------------------------
2947** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2948**
2949******************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002950u32 MT2063_SetGPIO(void *h, enum MT2063_GPIO_ID gpio_id,
2951 enum MT2063_GPIO_Attr attr, u32 value)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002952{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002953 u32 status = MT2063_OK; /* Status to be returned */
2954 u8 regno;
2955 s32 shift;
2956 static u8 GPIOreg[3] = { 0x15, 0x19, 0x18 };
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002957 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
2958
2959 if (MT2063_IsValidHandle(pInfo) == 0)
2960 return MT2063_INV_HANDLE;
2961
2962 regno = GPIOreg[attr];
2963
2964 shift = (gpio_id - MT2063_GPIO0 + 5);
2965
2966 if (value & 0x01)
2967 pInfo->reg[regno] |= (0x01 << shift);
2968 else
2969 pInfo->reg[regno] &= ~(0x01 << shift);
2970 status =
2971 MT2063_WriteSub(pInfo->hUserData, pInfo->address, regno,
2972 &pInfo->reg[regno], 1);
2973
2974 return (status);
2975}
2976
2977/****************************************************************************
2978**
2979** Name: MT2063_SetParam
2980**
2981** Description: Sets a tuning algorithm parameter.
2982**
2983** This function provides access to the internals of the
2984** tuning algorithm. You can override many of the tuning
2985** algorithm defaults using this function.
2986**
2987** Parameters: h - Tuner handle (returned by MT2063_Open)
2988** param - Tuning algorithm parameter
2989** (see enum MT2063_Param)
2990** nValue - value to be set
2991**
2992** param Description
2993** ---------------------- --------------------------------
2994** MT2063_SRO_FREQ crystal frequency
2995** MT2063_STEPSIZE minimum tuning step size
2996** MT2063_LO1_FREQ LO1 frequency
2997** MT2063_LO1_STEPSIZE LO1 minimum step size
2998** MT2063_LO1_FRACN_AVOID LO1 FracN keep-out region
2999** MT2063_IF1_REQUEST Requested 1st IF
3000** MT2063_ZIF_BW zero-IF bandwidth
3001** MT2063_LO2_FREQ LO2 frequency
3002** MT2063_LO2_STEPSIZE LO2 minimum step size
3003** MT2063_LO2_FRACN_AVOID LO2 FracN keep-out region
3004** MT2063_OUTPUT_FREQ output center frequency
3005** MT2063_OUTPUT_BW output bandwidth
3006** MT2063_LO_SEPARATION min inter-tuner LO separation
3007** MT2063_MAX_HARM1 max # of intra-tuner harmonics
3008** MT2063_MAX_HARM2 max # of inter-tuner harmonics
3009** MT2063_RCVR_MODE Predefined modes
3010** MT2063_LNA_RIN Set LNA Rin (*)
3011** MT2063_LNA_TGT Set target power level at LNA (*)
3012** MT2063_PD1_TGT Set target power level at PD1 (*)
3013** MT2063_PD2_TGT Set target power level at PD2 (*)
3014** MT2063_ACLNA_MAX LNA attenuator limit (*)
3015** MT2063_ACRF_MAX RF attenuator limit (*)
3016** MT2063_ACFIF_MAX FIF attenuator limit (*)
3017** MT2063_DNC_OUTPUT_ENABLE DNC output selection
3018** MT2063_VGAGC VGA gain code
3019** MT2063_VGAOI VGA output current
3020** MT2063_TAGC TAGC setting
3021** MT2063_AMPGC AMP gain code
3022** MT2063_AVOID_DECT Avoid DECT Frequencies
3023** MT2063_CTFILT_SW Cleartune filter selection
3024**
3025** (*) This parameter is set by MT2063_RCVR_MODE, do not call
3026** additionally.
3027**
3028** Usage: status |= MT2063_SetParam(hMT2063,
3029** MT2063_STEPSIZE,
3030** 50000);
3031**
3032** Returns: status:
3033** MT_OK - No errors
3034** MT_INV_HANDLE - Invalid tuner handle
3035** MT_ARG_NULL - Null pointer argument passed
3036** MT_ARG_RANGE - Invalid parameter requested
3037** or set value out of range
3038** or non-writable parameter
3039**
3040** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3041**
3042** See Also: MT2063_GetParam, MT2063_Open
3043**
3044** Revision History:
3045**
3046** SCR Date Author Description
3047** -------------------------------------------------------------------------
3048** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3049** 154 09-13-2007 RSK Ver 1.05: Get/SetParam changes for LOx_FREQ
3050** 10-31-2007 PINZ Ver 1.08: Get/SetParam add VGAGC, VGAOI, AMPGC, TAGC
3051** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
3052** Split SetParam up to ACLNA / ACLNA_MAX
3053** removed ACLNA_INRC/DECR (+RF & FIF)
3054** removed GCUAUTO / BYPATNDN/UP
3055** 175 I 06-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
3056** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
3057** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
3058**
3059****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003060u32 MT2063_SetParam(void *h, enum MT2063_Param param, u32 nValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003061{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003062 u32 status = MT2063_OK; /* Status to be returned */
3063 u8 val = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003064 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
3065
3066 /* Verify that the handle passed points to a valid tuner */
3067 if (MT2063_IsValidHandle(pInfo) == 0)
3068 status |= MT2063_INV_HANDLE;
3069
3070 if (MT2063_NO_ERROR(status)) {
3071 switch (param) {
3072 /* crystal frequency */
3073 case MT2063_SRO_FREQ:
3074 pInfo->AS_Data.f_ref = nValue;
3075 pInfo->AS_Data.f_LO1_FracN_Avoid = 0;
3076 pInfo->AS_Data.f_LO2_FracN_Avoid = nValue / 80 - 1;
3077 pInfo->AS_Data.f_LO1_Step = nValue / 64;
3078 pInfo->AS_Data.f_if1_Center =
3079 (pInfo->AS_Data.f_ref / 8) *
3080 (pInfo->reg[MT2063_REG_FIFFC] + 640);
3081 break;
3082
3083 /* minimum tuning step size */
3084 case MT2063_STEPSIZE:
3085 pInfo->AS_Data.f_LO2_Step = nValue;
3086 break;
3087
3088 /* LO1 frequency */
3089 case MT2063_LO1_FREQ:
3090 {
3091 /* Note: LO1 and LO2 are BOTH written at toggle of LDLOos */
3092 /* Capture the Divider and Numerator portions of other LO */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003093 u8 tempLO2CQ[3];
3094 u8 tempLO2C[3];
3095 u8 tmpOneShot;
3096 u32 Div, FracN;
3097 u8 restore = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003098
3099 /* Buffer the queue for restoration later and get actual LO2 values. */
3100 status |=
3101 MT2063_ReadSub(pInfo->hUserData,
3102 pInfo->address,
3103 MT2063_REG_LO2CQ_1,
3104 &(tempLO2CQ[0]), 3);
3105 status |=
3106 MT2063_ReadSub(pInfo->hUserData,
3107 pInfo->address,
3108 MT2063_REG_LO2C_1,
3109 &(tempLO2C[0]), 3);
3110
3111 /* clear the one-shot bits */
3112 tempLO2CQ[2] = tempLO2CQ[2] & 0x0F;
3113 tempLO2C[2] = tempLO2C[2] & 0x0F;
3114
3115 /* only write the queue values if they are different from the actual. */
3116 if ((tempLO2CQ[0] != tempLO2C[0]) ||
3117 (tempLO2CQ[1] != tempLO2C[1]) ||
3118 (tempLO2CQ[2] != tempLO2C[2])) {
3119 /* put actual LO2 value into queue (with 0 in one-shot bits) */
3120 status |=
3121 MT2063_WriteSub(pInfo->hUserData,
3122 pInfo->address,
3123 MT2063_REG_LO2CQ_1,
3124 &(tempLO2C[0]), 3);
3125
3126 if (status == MT2063_OK) {
3127 /* cache the bytes just written. */
3128 pInfo->reg[MT2063_REG_LO2CQ_1] =
3129 tempLO2C[0];
3130 pInfo->reg[MT2063_REG_LO2CQ_2] =
3131 tempLO2C[1];
3132 pInfo->reg[MT2063_REG_LO2CQ_3] =
3133 tempLO2C[2];
3134 }
3135 restore = 1;
3136 }
3137
3138 /* Calculate the Divider and Numberator components of LO1 */
3139 status =
3140 MT2063_CalcLO1Mult(&Div, &FracN, nValue,
3141 pInfo->AS_Data.f_ref /
3142 64,
3143 pInfo->AS_Data.f_ref);
3144 pInfo->reg[MT2063_REG_LO1CQ_1] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003145 (u8) (Div & 0x00FF);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003146 pInfo->reg[MT2063_REG_LO1CQ_2] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003147 (u8) (FracN);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003148 status |=
3149 MT2063_WriteSub(pInfo->hUserData,
3150 pInfo->address,
3151 MT2063_REG_LO1CQ_1,
3152 &pInfo->
3153 reg[MT2063_REG_LO1CQ_1], 2);
3154
3155 /* set the one-shot bit to load the pair of LO values */
3156 tmpOneShot = tempLO2CQ[2] | 0xE0;
3157 status |=
3158 MT2063_WriteSub(pInfo->hUserData,
3159 pInfo->address,
3160 MT2063_REG_LO2CQ_3,
3161 &tmpOneShot, 1);
3162
3163 /* only restore the queue values if they were different from the actual. */
3164 if (restore) {
3165 /* put actual LO2 value into queue (0 in one-shot bits) */
3166 status |=
3167 MT2063_WriteSub(pInfo->hUserData,
3168 pInfo->address,
3169 MT2063_REG_LO2CQ_1,
3170 &(tempLO2CQ[0]), 3);
3171
3172 /* cache the bytes just written. */
3173 pInfo->reg[MT2063_REG_LO2CQ_1] =
3174 tempLO2CQ[0];
3175 pInfo->reg[MT2063_REG_LO2CQ_2] =
3176 tempLO2CQ[1];
3177 pInfo->reg[MT2063_REG_LO2CQ_3] =
3178 tempLO2CQ[2];
3179 }
3180
3181 MT2063_GetParam(pInfo->hUserData,
3182 MT2063_LO1_FREQ,
3183 &pInfo->AS_Data.f_LO1);
3184 }
3185 break;
3186
3187 /* LO1 minimum step size */
3188 case MT2063_LO1_STEPSIZE:
3189 pInfo->AS_Data.f_LO1_Step = nValue;
3190 break;
3191
3192 /* LO1 FracN keep-out region */
3193 case MT2063_LO1_FRACN_AVOID_PARAM:
3194 pInfo->AS_Data.f_LO1_FracN_Avoid = nValue;
3195 break;
3196
3197 /* Requested 1st IF */
3198 case MT2063_IF1_REQUEST:
3199 pInfo->AS_Data.f_if1_Request = nValue;
3200 break;
3201
3202 /* zero-IF bandwidth */
3203 case MT2063_ZIF_BW:
3204 pInfo->AS_Data.f_zif_bw = nValue;
3205 break;
3206
3207 /* LO2 frequency */
3208 case MT2063_LO2_FREQ:
3209 {
3210 /* Note: LO1 and LO2 are BOTH written at toggle of LDLOos */
3211 /* Capture the Divider and Numerator portions of other LO */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003212 u8 tempLO1CQ[2];
3213 u8 tempLO1C[2];
3214 u32 Div2;
3215 u32 FracN2;
3216 u8 tmpOneShot;
3217 u8 restore = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003218
3219 /* Buffer the queue for restoration later and get actual LO2 values. */
3220 status |=
3221 MT2063_ReadSub(pInfo->hUserData,
3222 pInfo->address,
3223 MT2063_REG_LO1CQ_1,
3224 &(tempLO1CQ[0]), 2);
3225 status |=
3226 MT2063_ReadSub(pInfo->hUserData,
3227 pInfo->address,
3228 MT2063_REG_LO1C_1,
3229 &(tempLO1C[0]), 2);
3230
3231 /* only write the queue values if they are different from the actual. */
3232 if ((tempLO1CQ[0] != tempLO1C[0])
3233 || (tempLO1CQ[1] != tempLO1C[1])) {
3234 /* put actual LO1 value into queue */
3235 status |=
3236 MT2063_WriteSub(pInfo->hUserData,
3237 pInfo->address,
3238 MT2063_REG_LO1CQ_1,
3239 &(tempLO1C[0]), 2);
3240
3241 /* cache the bytes just written. */
3242 pInfo->reg[MT2063_REG_LO1CQ_1] =
3243 tempLO1C[0];
3244 pInfo->reg[MT2063_REG_LO1CQ_2] =
3245 tempLO1C[1];
3246 restore = 1;
3247 }
3248
3249 /* Calculate the Divider and Numberator components of LO2 */
3250 status =
3251 MT2063_CalcLO2Mult(&Div2, &FracN2, nValue,
3252 pInfo->AS_Data.f_ref /
3253 8191,
3254 pInfo->AS_Data.f_ref);
3255 pInfo->reg[MT2063_REG_LO2CQ_1] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003256 (u8) ((Div2 << 1) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003257 ((FracN2 >> 12) & 0x01)) & 0xFF;
3258 pInfo->reg[MT2063_REG_LO2CQ_2] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003259 (u8) ((FracN2 >> 4) & 0xFF);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003260 pInfo->reg[MT2063_REG_LO2CQ_3] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003261 (u8) ((FracN2 & 0x0F));
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003262 status |=
3263 MT2063_WriteSub(pInfo->hUserData,
3264 pInfo->address,
3265 MT2063_REG_LO1CQ_1,
3266 &pInfo->
3267 reg[MT2063_REG_LO1CQ_1], 3);
3268
3269 /* set the one-shot bit to load the LO values */
3270 tmpOneShot =
3271 pInfo->reg[MT2063_REG_LO2CQ_3] | 0xE0;
3272 status |=
3273 MT2063_WriteSub(pInfo->hUserData,
3274 pInfo->address,
3275 MT2063_REG_LO2CQ_3,
3276 &tmpOneShot, 1);
3277
3278 /* only restore LO1 queue value if they were different from the actual. */
3279 if (restore) {
3280 /* put previous LO1 queue value back into queue */
3281 status |=
3282 MT2063_WriteSub(pInfo->hUserData,
3283 pInfo->address,
3284 MT2063_REG_LO1CQ_1,
3285 &(tempLO1CQ[0]), 2);
3286
3287 /* cache the bytes just written. */
3288 pInfo->reg[MT2063_REG_LO1CQ_1] =
3289 tempLO1CQ[0];
3290 pInfo->reg[MT2063_REG_LO1CQ_2] =
3291 tempLO1CQ[1];
3292 }
3293
3294 MT2063_GetParam(pInfo->hUserData,
3295 MT2063_LO2_FREQ,
3296 &pInfo->AS_Data.f_LO2);
3297 }
3298 break;
3299
3300 /* LO2 minimum step size */
3301 case MT2063_LO2_STEPSIZE:
3302 pInfo->AS_Data.f_LO2_Step = nValue;
3303 break;
3304
3305 /* LO2 FracN keep-out region */
3306 case MT2063_LO2_FRACN_AVOID:
3307 pInfo->AS_Data.f_LO2_FracN_Avoid = nValue;
3308 break;
3309
3310 /* output center frequency */
3311 case MT2063_OUTPUT_FREQ:
3312 pInfo->AS_Data.f_out = nValue;
3313 break;
3314
3315 /* output bandwidth */
3316 case MT2063_OUTPUT_BW:
3317 pInfo->AS_Data.f_out_bw = nValue + 750000;
3318 break;
3319
3320 /* min inter-tuner LO separation */
3321 case MT2063_LO_SEPARATION:
3322 pInfo->AS_Data.f_min_LO_Separation = nValue;
3323 break;
3324
3325 /* max # of intra-tuner harmonics */
3326 case MT2063_MAX_HARM1:
3327 pInfo->AS_Data.maxH1 = nValue;
3328 break;
3329
3330 /* max # of inter-tuner harmonics */
3331 case MT2063_MAX_HARM2:
3332 pInfo->AS_Data.maxH2 = nValue;
3333 break;
3334
3335 case MT2063_RCVR_MODE:
3336 status |=
3337 MT2063_SetReceiverMode(pInfo,
3338 (enum MT2063_RCVR_MODES)
3339 nValue);
3340 break;
3341
3342 /* Set LNA Rin -- nValue is desired value */
3343 case MT2063_LNA_RIN:
3344 val =
3345 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003346 reg[MT2063_REG_CTRL_2C] & (u8) ~ 0x03) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003347 (nValue & 0x03);
3348 if (pInfo->reg[MT2063_REG_CTRL_2C] != val) {
3349 status |=
3350 MT2063_SetReg(pInfo, MT2063_REG_CTRL_2C,
3351 val);
3352 }
3353 break;
3354
3355 /* Set target power level at LNA -- nValue is desired value */
3356 case MT2063_LNA_TGT:
3357 val =
3358 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003359 reg[MT2063_REG_LNA_TGT] & (u8) ~ 0x3F) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003360 (nValue & 0x3F);
3361 if (pInfo->reg[MT2063_REG_LNA_TGT] != val) {
3362 status |=
3363 MT2063_SetReg(pInfo, MT2063_REG_LNA_TGT,
3364 val);
3365 }
3366 break;
3367
3368 /* Set target power level at PD1 -- nValue is desired value */
3369 case MT2063_PD1_TGT:
3370 val =
3371 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003372 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x3F) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003373 (nValue & 0x3F);
3374 if (pInfo->reg[MT2063_REG_PD1_TGT] != val) {
3375 status |=
3376 MT2063_SetReg(pInfo, MT2063_REG_PD1_TGT,
3377 val);
3378 }
3379 break;
3380
3381 /* Set target power level at PD2 -- nValue is desired value */
3382 case MT2063_PD2_TGT:
3383 val =
3384 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003385 reg[MT2063_REG_PD2_TGT] & (u8) ~ 0x3F) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003386 (nValue & 0x3F);
3387 if (pInfo->reg[MT2063_REG_PD2_TGT] != val) {
3388 status |=
3389 MT2063_SetReg(pInfo, MT2063_REG_PD2_TGT,
3390 val);
3391 }
3392 break;
3393
3394 /* Set LNA atten limit -- nValue is desired value */
3395 case MT2063_ACLNA_MAX:
3396 val =
3397 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003398 reg[MT2063_REG_LNA_OV] & (u8) ~ 0x1F) | (nValue
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003399 &
3400 0x1F);
3401 if (pInfo->reg[MT2063_REG_LNA_OV] != val) {
3402 status |=
3403 MT2063_SetReg(pInfo, MT2063_REG_LNA_OV,
3404 val);
3405 }
3406 break;
3407
3408 /* Set RF atten limit -- nValue is desired value */
3409 case MT2063_ACRF_MAX:
3410 val =
3411 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003412 reg[MT2063_REG_RF_OV] & (u8) ~ 0x1F) | (nValue
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003413 &
3414 0x1F);
3415 if (pInfo->reg[MT2063_REG_RF_OV] != val) {
3416 status |=
3417 MT2063_SetReg(pInfo, MT2063_REG_RF_OV, val);
3418 }
3419 break;
3420
3421 /* Set FIF atten limit -- nValue is desired value, max. 5 if no B3 */
3422 case MT2063_ACFIF_MAX:
3423 if (pInfo->reg[MT2063_REG_PART_REV] != MT2063_B3
3424 && nValue > 5)
3425 nValue = 5;
3426 val =
3427 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003428 reg[MT2063_REG_FIF_OV] & (u8) ~ 0x1F) | (nValue
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003429 &
3430 0x1F);
3431 if (pInfo->reg[MT2063_REG_FIF_OV] != val) {
3432 status |=
3433 MT2063_SetReg(pInfo, MT2063_REG_FIF_OV,
3434 val);
3435 }
3436 break;
3437
3438 case MT2063_DNC_OUTPUT_ENABLE:
3439 /* selects, which DNC output is used */
3440 switch ((enum MT2063_DNC_Output_Enable)nValue) {
3441 case MT2063_DNC_NONE:
3442 {
3443 val = (pInfo->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
3444 if (pInfo->reg[MT2063_REG_DNC_GAIN] !=
3445 val)
3446 status |=
3447 MT2063_SetReg(h,
3448 MT2063_REG_DNC_GAIN,
3449 val);
3450
3451 val = (pInfo->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
3452 if (pInfo->reg[MT2063_REG_VGA_GAIN] !=
3453 val)
3454 status |=
3455 MT2063_SetReg(h,
3456 MT2063_REG_VGA_GAIN,
3457 val);
3458
3459 val = (pInfo->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
3460 if (pInfo->reg[MT2063_REG_RSVD_20] !=
3461 val)
3462 status |=
3463 MT2063_SetReg(h,
3464 MT2063_REG_RSVD_20,
3465 val);
3466
3467 break;
3468 }
3469 case MT2063_DNC_1:
3470 {
3471 val = (pInfo->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[pInfo->rcvr_mode] & 0x03); /* Set DNC1GC=x */
3472 if (pInfo->reg[MT2063_REG_DNC_GAIN] !=
3473 val)
3474 status |=
3475 MT2063_SetReg(h,
3476 MT2063_REG_DNC_GAIN,
3477 val);
3478
3479 val = (pInfo->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
3480 if (pInfo->reg[MT2063_REG_VGA_GAIN] !=
3481 val)
3482 status |=
3483 MT2063_SetReg(h,
3484 MT2063_REG_VGA_GAIN,
3485 val);
3486
3487 val = (pInfo->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
3488 if (pInfo->reg[MT2063_REG_RSVD_20] !=
3489 val)
3490 status |=
3491 MT2063_SetReg(h,
3492 MT2063_REG_RSVD_20,
3493 val);
3494
3495 break;
3496 }
3497 case MT2063_DNC_2:
3498 {
3499 val = (pInfo->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
3500 if (pInfo->reg[MT2063_REG_DNC_GAIN] !=
3501 val)
3502 status |=
3503 MT2063_SetReg(h,
3504 MT2063_REG_DNC_GAIN,
3505 val);
3506
3507 val = (pInfo->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[pInfo->rcvr_mode] & 0x03); /* Set DNC2GC=x */
3508 if (pInfo->reg[MT2063_REG_VGA_GAIN] !=
3509 val)
3510 status |=
3511 MT2063_SetReg(h,
3512 MT2063_REG_VGA_GAIN,
3513 val);
3514
3515 val = (pInfo->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
3516 if (pInfo->reg[MT2063_REG_RSVD_20] !=
3517 val)
3518 status |=
3519 MT2063_SetReg(h,
3520 MT2063_REG_RSVD_20,
3521 val);
3522
3523 break;
3524 }
3525 case MT2063_DNC_BOTH:
3526 {
3527 val = (pInfo->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[pInfo->rcvr_mode] & 0x03); /* Set DNC1GC=x */
3528 if (pInfo->reg[MT2063_REG_DNC_GAIN] !=
3529 val)
3530 status |=
3531 MT2063_SetReg(h,
3532 MT2063_REG_DNC_GAIN,
3533 val);
3534
3535 val = (pInfo->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[pInfo->rcvr_mode] & 0x03); /* Set DNC2GC=x */
3536 if (pInfo->reg[MT2063_REG_VGA_GAIN] !=
3537 val)
3538 status |=
3539 MT2063_SetReg(h,
3540 MT2063_REG_VGA_GAIN,
3541 val);
3542
3543 val = (pInfo->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
3544 if (pInfo->reg[MT2063_REG_RSVD_20] !=
3545 val)
3546 status |=
3547 MT2063_SetReg(h,
3548 MT2063_REG_RSVD_20,
3549 val);
3550
3551 break;
3552 }
3553 default:
3554 break;
3555 }
3556 break;
3557
3558 case MT2063_VGAGC:
3559 /* Set VGA gain code */
3560 val =
3561 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003562 reg[MT2063_REG_VGA_GAIN] & (u8) ~ 0x0C) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003563 ((nValue & 0x03) << 2);
3564 if (pInfo->reg[MT2063_REG_VGA_GAIN] != val) {
3565 status |=
3566 MT2063_SetReg(pInfo, MT2063_REG_VGA_GAIN,
3567 val);
3568 }
3569 break;
3570
3571 case MT2063_VGAOI:
3572 /* Set VGA bias current */
3573 val =
3574 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003575 reg[MT2063_REG_RSVD_31] & (u8) ~ 0x07) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003576 (nValue & 0x07);
3577 if (pInfo->reg[MT2063_REG_RSVD_31] != val) {
3578 status |=
3579 MT2063_SetReg(pInfo, MT2063_REG_RSVD_31,
3580 val);
3581 }
3582 break;
3583
3584 case MT2063_TAGC:
3585 /* Set TAGC */
3586 val =
3587 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003588 reg[MT2063_REG_RSVD_1E] & (u8) ~ 0x03) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003589 (nValue & 0x03);
3590 if (pInfo->reg[MT2063_REG_RSVD_1E] != val) {
3591 status |=
3592 MT2063_SetReg(pInfo, MT2063_REG_RSVD_1E,
3593 val);
3594 }
3595 break;
3596
3597 case MT2063_AMPGC:
3598 /* Set Amp gain code */
3599 val =
3600 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003601 reg[MT2063_REG_TEMP_SEL] & (u8) ~ 0x03) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003602 (nValue & 0x03);
3603 if (pInfo->reg[MT2063_REG_TEMP_SEL] != val) {
3604 status |=
3605 MT2063_SetReg(pInfo, MT2063_REG_TEMP_SEL,
3606 val);
3607 }
3608 break;
3609
3610 /* Avoid DECT Frequencies */
3611 case MT2063_AVOID_DECT:
3612 {
3613 enum MT2063_DECT_Avoid_Type newAvoidSetting =
3614 (enum MT2063_DECT_Avoid_Type)nValue;
3615 if ((newAvoidSetting >=
3616 MT2063_NO_DECT_AVOIDANCE)
3617 && (newAvoidSetting <= MT2063_AVOID_BOTH)) {
3618 pInfo->AS_Data.avoidDECT =
3619 newAvoidSetting;
3620 }
3621 }
3622 break;
3623
3624 /* Cleartune filter selection: 0 - by IC (default), 1 - by software */
3625 case MT2063_CTFILT_SW:
3626 pInfo->ctfilt_sw = (nValue & 0x01);
3627 break;
3628
3629 /* These parameters are read-only */
3630 case MT2063_IC_ADDR:
3631 case MT2063_MAX_OPEN:
3632 case MT2063_NUM_OPEN:
3633 case MT2063_INPUT_FREQ:
3634 case MT2063_IF1_ACTUAL:
3635 case MT2063_IF1_CENTER:
3636 case MT2063_IF1_BW:
3637 case MT2063_AS_ALG:
3638 case MT2063_EXCL_ZONES:
3639 case MT2063_SPUR_AVOIDED:
3640 case MT2063_NUM_SPURS:
3641 case MT2063_SPUR_PRESENT:
3642 case MT2063_ACLNA:
3643 case MT2063_ACRF:
3644 case MT2063_ACFIF:
3645 case MT2063_EOP:
3646 default:
3647 status |= MT2063_ARG_RANGE;
3648 }
3649 }
3650 return (status);
3651}
3652
3653/****************************************************************************
3654**
3655** Name: MT2063_SetPowerMaskBits
3656**
3657** Description: Sets the power-down mask bits for various sections of
3658** the MT2063
3659**
3660** Parameters: h - Tuner handle (returned by MT2063_Open)
3661** Bits - Mask bits to be set.
3662**
3663** See definition of MT2063_Mask_Bits type for description
3664** of each of the power bits.
3665**
3666** Returns: status:
3667** MT_OK - No errors
3668** MT_INV_HANDLE - Invalid tuner handle
3669** MT_COMM_ERR - Serial bus communications error
3670**
3671** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3672**
3673** Revision History:
3674**
3675** SCR Date Author Description
3676** -------------------------------------------------------------------------
3677** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3678**
3679****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003680u32 MT2063_SetPowerMaskBits(void *h, enum MT2063_Mask_Bits Bits)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003681{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003682 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003683 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
3684
3685 /* Verify that the handle passed points to a valid tuner */
3686 if (MT2063_IsValidHandle(pInfo) == 0)
3687 status = MT2063_INV_HANDLE;
3688 else {
3689 Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */
3690 if ((Bits & 0xFF00) != 0) {
3691 pInfo->reg[MT2063_REG_PWR_2] |=
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003692 (u8) ((Bits & 0xFF00) >> 8);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003693 status |=
3694 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3695 MT2063_REG_PWR_2,
3696 &pInfo->reg[MT2063_REG_PWR_2], 1);
3697 }
3698 if ((Bits & 0xFF) != 0) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003699 pInfo->reg[MT2063_REG_PWR_1] |= ((u8) Bits & 0xFF);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003700 status |=
3701 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3702 MT2063_REG_PWR_1,
3703 &pInfo->reg[MT2063_REG_PWR_1], 1);
3704 }
3705 }
3706
3707 return (status);
3708}
3709
3710/****************************************************************************
3711**
3712** Name: MT2063_ClearPowerMaskBits
3713**
3714** Description: Clears the power-down mask bits for various sections of
3715** the MT2063
3716**
3717** Parameters: h - Tuner handle (returned by MT2063_Open)
3718** Bits - Mask bits to be cleared.
3719**
3720** See definition of MT2063_Mask_Bits type for description
3721** of each of the power bits.
3722**
3723** Returns: status:
3724** MT_OK - No errors
3725** MT_INV_HANDLE - Invalid tuner handle
3726** MT_COMM_ERR - Serial bus communications error
3727**
3728** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3729**
3730** Revision History:
3731**
3732** SCR Date Author Description
3733** -------------------------------------------------------------------------
3734** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3735**
3736****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003737u32 MT2063_ClearPowerMaskBits(void *h, enum MT2063_Mask_Bits Bits)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003738{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003739 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003740 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
3741
3742 /* Verify that the handle passed points to a valid tuner */
3743 if (MT2063_IsValidHandle(pInfo) == 0)
3744 status = MT2063_INV_HANDLE;
3745 else {
3746 Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */
3747 if ((Bits & 0xFF00) != 0) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003748 pInfo->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003749 status |=
3750 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3751 MT2063_REG_PWR_2,
3752 &pInfo->reg[MT2063_REG_PWR_2], 1);
3753 }
3754 if ((Bits & 0xFF) != 0) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003755 pInfo->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003756 status |=
3757 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3758 MT2063_REG_PWR_1,
3759 &pInfo->reg[MT2063_REG_PWR_1], 1);
3760 }
3761 }
3762
3763 return (status);
3764}
3765
3766/****************************************************************************
3767**
3768** Name: MT2063_GetPowerMaskBits
3769**
3770** Description: Returns a mask of the enabled power shutdown bits
3771**
3772** Parameters: h - Tuner handle (returned by MT2063_Open)
3773** Bits - Mask bits to currently set.
3774**
3775** See definition of MT2063_Mask_Bits type for description
3776** of each of the power bits.
3777**
3778** Returns: status:
3779** MT_OK - No errors
3780** MT_INV_HANDLE - Invalid tuner handle
3781** MT_ARG_NULL - Output argument is NULL
3782** MT_COMM_ERR - Serial bus communications error
3783**
3784** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3785**
3786** Revision History:
3787**
3788** SCR Date Author Description
3789** -------------------------------------------------------------------------
3790** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3791**
3792****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003793u32 MT2063_GetPowerMaskBits(void *h, enum MT2063_Mask_Bits * Bits)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003794{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003795 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003796 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
3797
3798 /* Verify that the handle passed points to a valid tuner */
3799 if (MT2063_IsValidHandle(pInfo) == 0)
3800 status = MT2063_INV_HANDLE;
3801 else {
3802 if (Bits == NULL)
3803 status |= MT2063_ARG_NULL;
3804
3805 if (MT2063_NO_ERROR(status))
3806 status |=
3807 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
3808 MT2063_REG_PWR_1,
3809 &pInfo->reg[MT2063_REG_PWR_1], 2);
3810
3811 if (MT2063_NO_ERROR(status)) {
3812 *Bits =
3813 (enum
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003814 MT2063_Mask_Bits)(((s32) pInfo->
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003815 reg[MT2063_REG_PWR_2] << 8) +
3816 pInfo->reg[MT2063_REG_PWR_1]);
3817 *Bits = (enum MT2063_Mask_Bits)(*Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */
3818 }
3819 }
3820
3821 return (status);
3822}
3823
3824/****************************************************************************
3825**
3826** Name: MT2063_EnableExternalShutdown
3827**
3828** Description: Enables or disables the operation of the external
3829** shutdown pin
3830**
3831** Parameters: h - Tuner handle (returned by MT2063_Open)
3832** Enabled - 0 = disable the pin, otherwise enable it
3833**
3834** Returns: status:
3835** MT_OK - No errors
3836** MT_INV_HANDLE - Invalid tuner handle
3837** MT_COMM_ERR - Serial bus communications error
3838**
3839** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3840**
3841** Revision History:
3842**
3843** SCR Date Author Description
3844** -------------------------------------------------------------------------
3845** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3846**
3847****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003848u32 MT2063_EnableExternalShutdown(void *h, u8 Enabled)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003849{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003850 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003851 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
3852
3853 /* Verify that the handle passed points to a valid tuner */
3854 if (MT2063_IsValidHandle(pInfo) == 0)
3855 status = MT2063_INV_HANDLE;
3856 else {
3857 if (Enabled == 0)
3858 pInfo->reg[MT2063_REG_PWR_1] &= ~0x08; /* Turn off the bit */
3859 else
3860 pInfo->reg[MT2063_REG_PWR_1] |= 0x08; /* Turn the bit on */
3861
3862 status |=
3863 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3864 MT2063_REG_PWR_1,
3865 &pInfo->reg[MT2063_REG_PWR_1], 1);
3866 }
3867
3868 return (status);
3869}
3870
3871/****************************************************************************
3872**
3873** Name: MT2063_SoftwareShutdown
3874**
3875** Description: Enables or disables software shutdown function. When
3876** Shutdown==1, any section whose power mask is set will be
3877** shutdown.
3878**
3879** Parameters: h - Tuner handle (returned by MT2063_Open)
3880** Shutdown - 1 = shutdown the masked sections, otherwise
3881** power all sections on
3882**
3883** Returns: status:
3884** MT_OK - No errors
3885** MT_INV_HANDLE - Invalid tuner handle
3886** MT_COMM_ERR - Serial bus communications error
3887**
3888** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3889**
3890** Revision History:
3891**
3892** SCR Date Author Description
3893** -------------------------------------------------------------------------
3894** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3895** 01-03-2008 PINZ Ver 1.xx: Added a trigger of BYPATNUP for
3896** correct wakeup of the LNA
3897**
3898****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003899u32 MT2063_SoftwareShutdown(void *h, u8 Shutdown)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003900{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003901 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003902 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
3903
3904 /* Verify that the handle passed points to a valid tuner */
3905 if (MT2063_IsValidHandle(pInfo) == 0) {
3906 status = MT2063_INV_HANDLE;
3907 } else {
3908 if (Shutdown == 1)
3909 pInfo->reg[MT2063_REG_PWR_1] |= 0x04; /* Turn the bit on */
3910 else
3911 pInfo->reg[MT2063_REG_PWR_1] &= ~0x04; /* Turn off the bit */
3912
3913 status |=
3914 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3915 MT2063_REG_PWR_1,
3916 &pInfo->reg[MT2063_REG_PWR_1], 1);
3917
3918 if (Shutdown != 1) {
3919 pInfo->reg[MT2063_REG_BYP_CTRL] =
3920 (pInfo->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40;
3921 status |=
3922 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3923 MT2063_REG_BYP_CTRL,
3924 &pInfo->reg[MT2063_REG_BYP_CTRL],
3925 1);
3926 pInfo->reg[MT2063_REG_BYP_CTRL] =
3927 (pInfo->reg[MT2063_REG_BYP_CTRL] & 0x9F);
3928 status |=
3929 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3930 MT2063_REG_BYP_CTRL,
3931 &pInfo->reg[MT2063_REG_BYP_CTRL],
3932 1);
3933 }
3934 }
3935
3936 return (status);
3937}
3938
3939/****************************************************************************
3940**
3941** Name: MT2063_SetExtSRO
3942**
3943** Description: Sets the external SRO driver.
3944**
3945** Parameters: h - Tuner handle (returned by MT2063_Open)
3946** Ext_SRO_Setting - external SRO drive setting
3947**
3948** (default) MT2063_EXT_SRO_OFF - ext driver off
3949** MT2063_EXT_SRO_BY_1 - ext driver = SRO frequency
3950** MT2063_EXT_SRO_BY_2 - ext driver = SRO/2 frequency
3951** MT2063_EXT_SRO_BY_4 - ext driver = SRO/4 frequency
3952**
3953** Returns: status:
3954** MT_OK - No errors
3955** MT_COMM_ERR - Serial bus communications error
3956** MT_INV_HANDLE - Invalid tuner handle
3957**
3958** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3959**
3960** The Ext_SRO_Setting settings default to OFF
3961** Use this function if you need to override the default
3962**
3963** Revision History:
3964**
3965** SCR Date Author Description
3966** -------------------------------------------------------------------------
3967** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3968** 189 S 05-13-2008 RSK Ver 1.16: Correct location for ExtSRO control.
3969**
3970****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003971u32 MT2063_SetExtSRO(void *h, enum MT2063_Ext_SRO Ext_SRO_Setting)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003972{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003973 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003974 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
3975
3976 /* Verify that the handle passed points to a valid tuner */
3977 if (MT2063_IsValidHandle(pInfo) == 0)
3978 status = MT2063_INV_HANDLE;
3979 else {
3980 pInfo->reg[MT2063_REG_CTRL_2C] =
3981 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003982 reg[MT2063_REG_CTRL_2C] & 0x3F) | ((u8) Ext_SRO_Setting
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003983 << 6);
3984 status =
3985 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3986 MT2063_REG_CTRL_2C,
3987 &pInfo->reg[MT2063_REG_CTRL_2C], 1);
3988 }
3989
3990 return (status);
3991}
3992
3993/****************************************************************************
3994**
3995** Name: MT2063_SetReg
3996**
3997** Description: Sets an MT2063 register.
3998**
3999** Parameters: h - Tuner handle (returned by MT2063_Open)
4000** reg - MT2063 register/subaddress location
4001** val - MT2063 register/subaddress value
4002**
4003** Returns: status:
4004** MT_OK - No errors
4005** MT_COMM_ERR - Serial bus communications error
4006** MT_INV_HANDLE - Invalid tuner handle
4007** MT_ARG_RANGE - Argument out of range
4008**
4009** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
4010**
4011** Use this function if you need to override a default
4012** register value
4013**
4014** Revision History:
4015**
4016** SCR Date Author Description
4017** -------------------------------------------------------------------------
4018** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
4019**
4020****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004021u32 MT2063_SetReg(void *h, u8 reg, u8 val)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004022{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004023 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004024 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
4025
4026 /* Verify that the handle passed points to a valid tuner */
4027 if (MT2063_IsValidHandle(pInfo) == 0)
4028 status |= MT2063_INV_HANDLE;
4029
4030 if (reg >= MT2063_REG_END_REGS)
4031 status |= MT2063_ARG_RANGE;
4032
4033 if (MT2063_NO_ERROR(status)) {
4034 status |=
4035 MT2063_WriteSub(pInfo->hUserData, pInfo->address, reg, &val,
4036 1);
4037 if (MT2063_NO_ERROR(status))
4038 pInfo->reg[reg] = val;
4039 }
4040
4041 return (status);
4042}
4043
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004044static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004045{
4046 return f_ref * (f_LO / f_ref)
4047 + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step);
4048}
4049
4050/****************************************************************************
4051**
4052** Name: fLO_FractionalTerm
4053**
4054** Description: Calculates the portion contributed by FracN / denom.
4055**
4056** This function preserves maximum precision without
4057** risk of overflow. It accurately calculates
4058** f_ref * num / denom to within 1 HZ with fixed math.
4059**
4060** Parameters: num - Fractional portion of the multiplier
4061** denom - denominator portion of the ratio
4062** This routine successfully handles denom values
4063** up to and including 2^18.
4064** f_Ref - SRO frequency. This calculation handles
4065** f_ref as two separate 14-bit fields.
4066** Therefore, a maximum value of 2^28-1
4067** may safely be used for f_ref. This is
4068** the genesis of the magic number "14" and the
4069** magic mask value of 0x03FFF.
4070**
4071** Returns: f_ref * num / denom
4072**
4073** Revision History:
4074**
4075** SCR Date Author Description
4076** -------------------------------------------------------------------------
4077** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
4078**
4079****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004080static u32 MT2063_fLO_FractionalTerm(u32 f_ref,
4081 u32 num, u32 denom)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004082{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004083 u32 t1 = (f_ref >> 14) * num;
4084 u32 term1 = t1 / denom;
4085 u32 loss = t1 % denom;
4086 u32 term2 =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004087 (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom;
4088 return ((term1 << 14) + term2);
4089}
4090
4091/****************************************************************************
4092**
4093** Name: CalcLO1Mult
4094**
4095** Description: Calculates Integer divider value and the numerator
4096** value for a FracN PLL.
4097**
4098** This function assumes that the f_LO and f_Ref are
4099** evenly divisible by f_LO_Step.
4100**
4101** Parameters: Div - OUTPUT: Whole number portion of the multiplier
4102** FracN - OUTPUT: Fractional portion of the multiplier
4103** f_LO - desired LO frequency.
4104** f_LO_Step - Minimum step size for the LO (in Hz).
4105** f_Ref - SRO frequency.
4106** f_Avoid - Range of PLL frequencies to avoid near
4107** integer multiples of f_Ref (in Hz).
4108**
4109** Returns: Recalculated LO frequency.
4110**
4111** Revision History:
4112**
4113** SCR Date Author Description
4114** -------------------------------------------------------------------------
4115** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
4116**
4117****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004118static u32 MT2063_CalcLO1Mult(u32 * Div,
4119 u32 * FracN,
4120 u32 f_LO,
4121 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004122{
4123 /* Calculate the whole number portion of the divider */
4124 *Div = f_LO / f_Ref;
4125
4126 /* Calculate the numerator value (round to nearest f_LO_Step) */
4127 *FracN =
4128 (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
4129 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
4130
4131 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64);
4132}
4133
4134/****************************************************************************
4135**
4136** Name: CalcLO2Mult
4137**
4138** Description: Calculates Integer divider value and the numerator
4139** value for a FracN PLL.
4140**
4141** This function assumes that the f_LO and f_Ref are
4142** evenly divisible by f_LO_Step.
4143**
4144** Parameters: Div - OUTPUT: Whole number portion of the multiplier
4145** FracN - OUTPUT: Fractional portion of the multiplier
4146** f_LO - desired LO frequency.
4147** f_LO_Step - Minimum step size for the LO (in Hz).
4148** f_Ref - SRO frequency.
4149** f_Avoid - Range of PLL frequencies to avoid near
4150** integer multiples of f_Ref (in Hz).
4151**
4152** Returns: Recalculated LO frequency.
4153**
4154** Revision History:
4155**
4156** SCR Date Author Description
4157** -------------------------------------------------------------------------
4158** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
4159**
4160****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004161static u32 MT2063_CalcLO2Mult(u32 * Div,
4162 u32 * FracN,
4163 u32 f_LO,
4164 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004165{
4166 /* Calculate the whole number portion of the divider */
4167 *Div = f_LO / f_Ref;
4168
4169 /* Calculate the numerator value (round to nearest f_LO_Step) */
4170 *FracN =
4171 (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
4172 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
4173
4174 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN,
4175 8191);
4176}
4177
4178/****************************************************************************
4179**
4180** Name: FindClearTuneFilter
4181**
4182** Description: Calculate the corrrect ClearTune filter to be used for
4183** a given input frequency.
4184**
4185** Parameters: pInfo - ptr to tuner data structure
4186** f_in - RF input center frequency (in Hz).
4187**
4188** Returns: ClearTune filter number (0-31)
4189**
4190** Dependencies: MUST CALL MT2064_Open BEFORE FindClearTuneFilter!
4191**
4192** Revision History:
4193**
4194** SCR Date Author Description
4195** -------------------------------------------------------------------------
4196** 04-10-2008 PINZ Ver 1.14: Use software-controlled ClearTune
4197** cross-over frequency values.
4198**
4199****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004200static u32 FindClearTuneFilter(struct MT2063_Info_t *pInfo, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004201{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004202 u32 RFBand;
4203 u32 idx; /* index loop */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004204
4205 /*
4206 ** Find RF Band setting
4207 */
4208 RFBand = 31; /* def when f_in > all */
4209 for (idx = 0; idx < 31; ++idx) {
4210 if (pInfo->CTFiltMax[idx] >= f_in) {
4211 RFBand = idx;
4212 break;
4213 }
4214 }
4215 return (RFBand);
4216}
4217
4218/****************************************************************************
4219**
4220** Name: MT2063_Tune
4221**
4222** Description: Change the tuner's tuned frequency to RFin.
4223**
4224** Parameters: h - Open handle to the tuner (from MT2063_Open).
4225** f_in - RF input center frequency (in Hz).
4226**
4227** Returns: status:
4228** MT_OK - No errors
4229** MT_INV_HANDLE - Invalid tuner handle
4230** MT_UPC_UNLOCK - Upconverter PLL unlocked
4231** MT_DNC_UNLOCK - Downconverter PLL unlocked
4232** MT_COMM_ERR - Serial bus communications error
4233** MT_SPUR_CNT_MASK - Count of avoided LO spurs
4234** MT_SPUR_PRESENT - LO spur possible in output
4235** MT_FIN_RANGE - Input freq out of range
4236** MT_FOUT_RANGE - Output freq out of range
4237** MT_UPC_RANGE - Upconverter freq out of range
4238** MT_DNC_RANGE - Downconverter freq out of range
4239**
4240** Dependencies: MUST CALL MT2063_Open BEFORE MT2063_Tune!
4241**
4242** MT_ReadSub - Read data from the two-wire serial bus
4243** MT_WriteSub - Write data to the two-wire serial bus
4244** MT_Sleep - Delay execution for x milliseconds
4245** MT2063_GetLocked - Checks to see if LO1 and LO2 are locked
4246**
4247** Revision History:
4248**
4249** SCR Date Author Description
4250** -------------------------------------------------------------------------
4251** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
4252** 04-10-2008 PINZ Ver 1.05: Use software-controlled ClearTune
4253** cross-over frequency values.
4254** 175 I 16-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
4255** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
4256** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
4257**
4258****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004259u32 MT2063_Tune(void *h, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004260{ /* RF input center frequency */
4261 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
4262
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004263 u32 status = MT2063_OK; /* status of operation */
4264 u32 LO1; /* 1st LO register value */
4265 u32 Num1; /* Numerator for LO1 reg. value */
4266 u32 f_IF1; /* 1st IF requested */
4267 u32 LO2; /* 2nd LO register value */
4268 u32 Num2; /* Numerator for LO2 reg. value */
4269 u32 ofLO1, ofLO2; /* last time's LO frequencies */
4270 u32 ofin, ofout; /* last time's I/O frequencies */
4271 u8 fiffc = 0x80; /* FIFF center freq from tuner */
4272 u32 fiffof; /* Offset from FIFF center freq */
4273 const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */
4274 u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */
4275 u8 val;
4276 u32 RFBand;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004277
4278 /* Verify that the handle passed points to a valid tuner */
4279 if (MT2063_IsValidHandle(pInfo) == 0)
4280 return MT2063_INV_HANDLE;
4281
4282 /* Check the input and output frequency ranges */
4283 if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ))
4284 status |= MT2063_FIN_RANGE;
4285
4286 if ((pInfo->AS_Data.f_out < MT2063_MIN_FOUT_FREQ)
4287 || (pInfo->AS_Data.f_out > MT2063_MAX_FOUT_FREQ))
4288 status |= MT2063_FOUT_RANGE;
4289
4290 /*
4291 ** Save original LO1 and LO2 register values
4292 */
4293 ofLO1 = pInfo->AS_Data.f_LO1;
4294 ofLO2 = pInfo->AS_Data.f_LO2;
4295 ofin = pInfo->AS_Data.f_in;
4296 ofout = pInfo->AS_Data.f_out;
4297
4298 /*
4299 ** Find and set RF Band setting
4300 */
4301 if (pInfo->ctfilt_sw == 1) {
4302 val = (pInfo->reg[MT2063_REG_CTUNE_CTRL] | 0x08);
4303 if (pInfo->reg[MT2063_REG_CTUNE_CTRL] != val) {
4304 status |=
4305 MT2063_SetReg(pInfo, MT2063_REG_CTUNE_CTRL, val);
4306 }
4307 val = pInfo->reg[MT2063_REG_CTUNE_OV];
4308 RFBand = FindClearTuneFilter(pInfo, f_in);
4309 pInfo->reg[MT2063_REG_CTUNE_OV] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004310 (u8) ((pInfo->reg[MT2063_REG_CTUNE_OV] & ~0x1F)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004311 | RFBand);
4312 if (pInfo->reg[MT2063_REG_CTUNE_OV] != val) {
4313 status |=
4314 MT2063_SetReg(pInfo, MT2063_REG_CTUNE_OV, val);
4315 }
4316 }
4317
4318 /*
4319 ** Read the FIFF Center Frequency from the tuner
4320 */
4321 if (MT2063_NO_ERROR(status)) {
4322 status |=
4323 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
4324 MT2063_REG_FIFFC,
4325 &pInfo->reg[MT2063_REG_FIFFC], 1);
4326 fiffc = pInfo->reg[MT2063_REG_FIFFC];
4327 }
4328 /*
4329 ** Assign in the requested values
4330 */
4331 pInfo->AS_Data.f_in = f_in;
4332 /* Request a 1st IF such that LO1 is on a step size */
4333 pInfo->AS_Data.f_if1_Request =
4334 MT2063_Round_fLO(pInfo->AS_Data.f_if1_Request + f_in,
4335 pInfo->AS_Data.f_LO1_Step,
4336 pInfo->AS_Data.f_ref) - f_in;
4337
4338 /*
4339 ** Calculate frequency settings. f_IF1_FREQ + f_in is the
4340 ** desired LO1 frequency
4341 */
4342 MT2063_ResetExclZones(&pInfo->AS_Data);
4343
4344 f_IF1 = MT2063_ChooseFirstIF(&pInfo->AS_Data);
4345
4346 pInfo->AS_Data.f_LO1 =
4347 MT2063_Round_fLO(f_IF1 + f_in, pInfo->AS_Data.f_LO1_Step,
4348 pInfo->AS_Data.f_ref);
4349
4350 pInfo->AS_Data.f_LO2 =
4351 MT2063_Round_fLO(pInfo->AS_Data.f_LO1 - pInfo->AS_Data.f_out - f_in,
4352 pInfo->AS_Data.f_LO2_Step, pInfo->AS_Data.f_ref);
4353
4354 /*
4355 ** Check for any LO spurs in the output bandwidth and adjust
4356 ** the LO settings to avoid them if needed
4357 */
4358 status |= MT2063_AvoidSpurs(h, &pInfo->AS_Data);
4359 /*
4360 ** MT_AvoidSpurs spurs may have changed the LO1 & LO2 values.
4361 ** Recalculate the LO frequencies and the values to be placed
4362 ** in the tuning registers.
4363 */
4364 pInfo->AS_Data.f_LO1 =
4365 MT2063_CalcLO1Mult(&LO1, &Num1, pInfo->AS_Data.f_LO1,
4366 pInfo->AS_Data.f_LO1_Step, pInfo->AS_Data.f_ref);
4367 pInfo->AS_Data.f_LO2 =
4368 MT2063_Round_fLO(pInfo->AS_Data.f_LO1 - pInfo->AS_Data.f_out - f_in,
4369 pInfo->AS_Data.f_LO2_Step, pInfo->AS_Data.f_ref);
4370 pInfo->AS_Data.f_LO2 =
4371 MT2063_CalcLO2Mult(&LO2, &Num2, pInfo->AS_Data.f_LO2,
4372 pInfo->AS_Data.f_LO2_Step, pInfo->AS_Data.f_ref);
4373
4374 /*
4375 ** Check the upconverter and downconverter frequency ranges
4376 */
4377 if ((pInfo->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ)
4378 || (pInfo->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ))
4379 status |= MT2063_UPC_RANGE;
4380 if ((pInfo->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ)
4381 || (pInfo->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ))
4382 status |= MT2063_DNC_RANGE;
4383 /* LO2 Lock bit was in a different place for B0 version */
4384 if (pInfo->tuner_id == MT2063_B0)
4385 LO2LK = 0x40;
4386
4387 /*
4388 ** If we have the same LO frequencies and we're already locked,
4389 ** then skip re-programming the LO registers.
4390 */
4391 if ((ofLO1 != pInfo->AS_Data.f_LO1)
4392 || (ofLO2 != pInfo->AS_Data.f_LO2)
4393 || ((pInfo->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) !=
4394 (LO1LK | LO2LK))) {
4395 /*
4396 ** Calculate the FIFFOF register value
4397 **
4398 ** IF1_Actual
4399 ** FIFFOF = ------------ - 8 * FIFFC - 4992
4400 ** f_ref/64
4401 */
4402 fiffof =
4403 (pInfo->AS_Data.f_LO1 -
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004404 f_in) / (pInfo->AS_Data.f_ref / 64) - 8 * (u32) fiffc -
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004405 4992;
4406 if (fiffof > 0xFF)
4407 fiffof = 0xFF;
4408
4409 /*
4410 ** Place all of the calculated values into the local tuner
4411 ** register fields.
4412 */
4413 if (MT2063_NO_ERROR(status)) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004414 pInfo->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */
4415 pInfo->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */
4416 pInfo->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004417 |(Num2 >> 12)); /* NUM2q (hi) */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004418 pInfo->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */
4419 pInfo->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004420
4421 /*
4422 ** Now write out the computed register values
4423 ** IMPORTANT: There is a required order for writing
4424 ** (0x05 must follow all the others).
4425 */
4426 status |= MT2063_WriteSub(pInfo->hUserData, pInfo->address, MT2063_REG_LO1CQ_1, &pInfo->reg[MT2063_REG_LO1CQ_1], 5); /* 0x01 - 0x05 */
4427 if (pInfo->tuner_id == MT2063_B0) {
4428 /* Re-write the one-shot bits to trigger the tune operation */
4429 status |= MT2063_WriteSub(pInfo->hUserData, pInfo->address, MT2063_REG_LO2CQ_3, &pInfo->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */
4430 }
4431 /* Write out the FIFF offset only if it's changing */
4432 if (pInfo->reg[MT2063_REG_FIFF_OFFSET] !=
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004433 (u8) fiffof) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004434 pInfo->reg[MT2063_REG_FIFF_OFFSET] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004435 (u8) fiffof;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004436 status |=
4437 MT2063_WriteSub(pInfo->hUserData,
4438 pInfo->address,
4439 MT2063_REG_FIFF_OFFSET,
4440 &pInfo->
4441 reg[MT2063_REG_FIFF_OFFSET],
4442 1);
4443 }
4444 }
4445
4446 /*
4447 ** Check for LO's locking
4448 */
4449
4450 if (MT2063_NO_ERROR(status)) {
4451 status |= MT2063_GetLocked(h);
4452 }
4453 /*
4454 ** If we locked OK, assign calculated data to MT2063_Info_t structure
4455 */
4456 if (MT2063_NO_ERROR(status)) {
4457 pInfo->f_IF1_actual = pInfo->AS_Data.f_LO1 - f_in;
4458 }
4459 }
4460
4461 return (status);
4462}
4463
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004464u32 MT_Tune_atv(void *h, u32 f_in, u32 bw_in,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004465 enum MTTune_atv_standard tv_type)
4466{
4467
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004468 u32 status = MT2063_OK;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004469 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
4470 struct dvb_frontend *fe = (struct dvb_frontend *)pInfo->hUserData;
4471 struct mt2063_state *state = fe->tuner_priv;
4472
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004473 s32 pict_car = 0;
4474 s32 pict2chanb_vsb = 0;
4475 s32 pict2chanb_snd = 0;
4476 s32 pict2snd1 = 0;
4477 s32 pict2snd2 = 0;
4478 s32 ch_bw = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004479
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004480 s32 if_mid = 0;
4481 s32 rcvr_mode = 0;
4482 u32 mode_get = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004483
4484 switch (tv_type) {
4485 case MTTUNEA_PAL_B:{
4486 pict_car = 38900000;
4487 ch_bw = 8000000;
4488 pict2chanb_vsb = -1250000;
4489 pict2snd1 = 5500000;
4490 pict2snd2 = 5742000;
4491 rcvr_mode = 1;
4492 break;
4493 }
4494 case MTTUNEA_PAL_G:{
4495 pict_car = 38900000;
4496 ch_bw = 7000000;
4497 pict2chanb_vsb = -1250000;
4498 pict2snd1 = 5500000;
4499 pict2snd2 = 0;
4500 rcvr_mode = 1;
4501 break;
4502 }
4503 case MTTUNEA_PAL_I:{
4504 pict_car = 38900000;
4505 ch_bw = 8000000;
4506 pict2chanb_vsb = -1250000;
4507 pict2snd1 = 6000000;
4508 pict2snd2 = 0;
4509 rcvr_mode = 1;
4510 break;
4511 }
4512 case MTTUNEA_PAL_L:{
4513 pict_car = 38900000;
4514 ch_bw = 8000000;
4515 pict2chanb_vsb = -1250000;
4516 pict2snd1 = 6500000;
4517 pict2snd2 = 0;
4518 rcvr_mode = 1;
4519 break;
4520 }
4521 case MTTUNEA_PAL_MN:{
4522 pict_car = 38900000;
4523 ch_bw = 6000000;
4524 pict2chanb_vsb = -1250000;
4525 pict2snd1 = 4500000;
4526 pict2snd2 = 0;
4527 rcvr_mode = 1;
4528 break;
4529 }
4530 case MTTUNEA_PAL_DK:{
4531 pict_car = 38900000;
4532 ch_bw = 8000000;
4533 pict2chanb_vsb = -1250000;
4534 pict2snd1 = 6500000;
4535 pict2snd2 = 0;
4536 rcvr_mode = 1;
4537 break;
4538 }
4539 case MTTUNEA_DIGITAL:{
4540 pict_car = 36125000;
4541 ch_bw = 8000000;
4542 pict2chanb_vsb = -(ch_bw / 2);
4543 pict2snd1 = 0;
4544 pict2snd2 = 0;
4545 rcvr_mode = 2;
4546 break;
4547 }
4548 case MTTUNEA_FMRADIO:{
4549 pict_car = 38900000;
4550 ch_bw = 8000000;
4551 pict2chanb_vsb = -(ch_bw / 2);
4552 pict2snd1 = 0;
4553 pict2snd2 = 0;
4554 rcvr_mode = 4;
4555 //f_in -= 2900000;
4556 break;
4557 }
4558 case MTTUNEA_DVBC:{
4559 pict_car = 36125000;
4560 ch_bw = 8000000;
4561 pict2chanb_vsb = -(ch_bw / 2);
4562 pict2snd1 = 0;
4563 pict2snd2 = 0;
4564 rcvr_mode = MT2063_CABLE_QAM;
4565 break;
4566 }
4567 case MTTUNEA_DVBT:{
4568 pict_car = 36125000;
4569 ch_bw = bw_in; //8000000
4570 pict2chanb_vsb = -(ch_bw / 2);
4571 pict2snd1 = 0;
4572 pict2snd2 = 0;
4573 rcvr_mode = MT2063_OFFAIR_COFDM;
4574 break;
4575 }
4576 case MTTUNEA_UNKNOWN:
4577 break;
4578 default:
4579 break;
4580 }
4581
4582 pict2chanb_snd = pict2chanb_vsb - ch_bw;
4583 if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
4584
4585 status |= MT2063_SetParam(h, MT2063_STEPSIZE, 125000);
4586 status |= MT2063_SetParam(h, MT2063_OUTPUT_FREQ, if_mid);
4587 status |= MT2063_SetParam(h, MT2063_OUTPUT_BW, ch_bw);
4588 status |= MT2063_GetParam(h, MT2063_RCVR_MODE, &mode_get);
4589
4590 status |= MT2063_SetParam(h, MT2063_RCVR_MODE, rcvr_mode);
4591 status |= MT2063_Tune(h, (f_in + (pict2chanb_vsb + (ch_bw / 2))));
4592 status |= MT2063_GetParam(h, MT2063_RCVR_MODE, &mode_get);
4593
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004594 return (u32) status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004595}
4596
4597static int mt2063_init(struct dvb_frontend *fe)
4598{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004599 u32 status = MT2063_ERROR;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004600 struct mt2063_state *state = fe->tuner_priv;
4601
4602 status = MT2063_Open(0xC0, &(state->MT2063_ht), fe);
4603 status |= MT2063_SoftwareShutdown(state->MT2063_ht, 1);
4604 status |= MT2063_ClearPowerMaskBits(state->MT2063_ht, MT2063_ALL_SD);
4605
4606 if (MT2063_OK != status) {
4607 printk("%s %d error status = 0x%x!!\n", __func__, __LINE__,
4608 status);
4609 return -1;
4610 }
4611
4612 return 0;
4613}
4614
4615static int mt2063_sleep(struct dvb_frontend *fe)
4616{
4617 /* TODO: power down */
4618 return 0;
4619}
4620
4621static int mt2063_get_status(struct dvb_frontend *fe, u32 * status)
4622{
4623 int rc = 0;
4624
4625 //get tuner lock status
4626
4627 return rc;
4628}
4629
4630static int mt2063_get_state(struct dvb_frontend *fe,
4631 enum tuner_param param, struct tuner_state *state)
4632{
4633 struct mt2063_state *mt2063State = fe->tuner_priv;
4634
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004635 switch (param) {
4636 case DVBFE_TUNER_FREQUENCY:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004637 //get frequency
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004638 break;
4639 case DVBFE_TUNER_TUNERSTEP:
4640 break;
4641 case DVBFE_TUNER_IFFREQ:
4642 break;
4643 case DVBFE_TUNER_BANDWIDTH:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004644 //get bandwidth
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004645 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004646 case DVBFE_TUNER_REFCLOCK:
4647 state->refclock =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004648 (u32)
4649 MT2063_GetLocked((void *) (mt2063State->MT2063_ht));
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004650 break;
4651 default:
4652 break;
4653 }
4654
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004655 return (int)state->refclock;
4656}
4657
4658static int mt2063_set_state(struct dvb_frontend *fe,
4659 enum tuner_param param, struct tuner_state *state)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004660{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004661 struct mt2063_state *mt2063State = fe->tuner_priv;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004662 u32 status = MT2063_OK;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004663
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004664 switch (param) {
4665 case DVBFE_TUNER_FREQUENCY:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004666 //set frequency
4667
4668 status =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004669 MT_Tune_atv((void *) (mt2063State->MT2063_ht),
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004670 state->frequency, state->bandwidth,
4671 mt2063State->tv_type);
4672
4673 mt2063State->frequency = state->frequency;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004674 break;
4675 case DVBFE_TUNER_TUNERSTEP:
4676 break;
4677 case DVBFE_TUNER_IFFREQ:
4678 break;
4679 case DVBFE_TUNER_BANDWIDTH:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004680 //set bandwidth
4681 mt2063State->bandwidth = state->bandwidth;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004682 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004683 case DVBFE_TUNER_REFCLOCK:
4684
4685 break;
4686 case DVBFE_TUNER_OPEN:
4687 status = MT2063_Open(MT2063_I2C, &(mt2063State->MT2063_ht), fe);
4688 break;
4689 case DVBFE_TUNER_SOFTWARE_SHUTDOWN:
4690 status = MT2063_SoftwareShutdown(mt2063State->MT2063_ht, 1);
4691 break;
4692 case DVBFE_TUNER_CLEAR_POWER_MASKBITS:
4693 status =
4694 MT2063_ClearPowerMaskBits(mt2063State->MT2063_ht,
4695 MT2063_ALL_SD);
4696 break;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004697 default:
4698 break;
4699 }
4700
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004701 return (int)status;
4702}
4703
4704static int mt2063_release(struct dvb_frontend *fe)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004705{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004706 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004707
4708 fe->tuner_priv = NULL;
4709 kfree(state);
4710
4711 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004712}
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004713
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004714static struct dvb_tuner_ops mt2063_ops = {
4715 .info = {
4716 .name = "MT2063 Silicon Tuner",
4717 .frequency_min = 45000000,
4718 .frequency_max = 850000000,
4719 .frequency_step = 0,
4720 },
4721
4722 .init = mt2063_init,
4723 .sleep = mt2063_sleep,
4724 .get_status = mt2063_get_status,
4725 .get_state = mt2063_get_state,
4726 .set_state = mt2063_set_state,
4727 .release = mt2063_release
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004728};
4729
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004730struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
4731 struct mt2063_config *config,
4732 struct i2c_adapter *i2c)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004733{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004734 struct mt2063_state *state = NULL;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004735
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004736 state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004737 if (state == NULL)
4738 goto error;
4739
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004740 state->config = config;
4741 state->i2c = i2c;
4742 state->frontend = fe;
4743 state->reference = config->refclock / 1000; /* kHz */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004744 state->MT2063_init = false;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004745 fe->tuner_priv = state;
4746 fe->ops.tuner_ops = mt2063_ops;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004747
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004748 printk("%s: Attaching MT2063 \n", __func__);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004749 return fe;
4750
4751error:
4752 kfree(state);
4753 return NULL;
4754}
4755
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004756EXPORT_SYMBOL(mt2063_attach);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004757MODULE_PARM_DESC(verbose, "Set Verbosity level");
4758
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004759MODULE_AUTHOR("Henry");
4760MODULE_DESCRIPTION("MT2063 Silicon tuner");
4761MODULE_LICENSE("GPL");