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