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