blob: 43e543e1efe2f2d7906a009f7376e037b0f7264b [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 Chehabf8676952011-07-20 22:00:30 -030029unsigned int mt2063_setTune(struct dvb_frontend *fe, u32 f_in,
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -030030 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
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -030060unsigned int mt2063_lockStatus(struct dvb_frontend *fe)
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -030061{
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
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -030082unsigned int tuner_MT2063_Open(struct dvb_frontend *fe)
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -030083{
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
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300105unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe)
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300106{
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
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300128unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe)
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300129{
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 Chehabf8676952011-07-20 22:00:30 -0300360static int MT2063_Sleep(struct dvb_frontend *fe)
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 */
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300366 msleep(10);
367
368 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300369}
370
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300371//end of mt2063_userdef.c
372//=================================================================
373//#################################################################
374//=================================================================
375
376//context of mt2063_spuravoid.c <Henry> ======================================
377//#################################################################
378//=================================================================
379
380/*****************************************************************************
381**
382** Name: mt_spuravoid.c
383**
384** Description: Microtune spur avoidance software module.
385** Supports Microtune tuner drivers.
386**
387** CVS ID: $Id: mt_spuravoid.c,v 1.3 2008/06/26 15:39:52 software Exp $
388** CVS Source: $Source: /export/home/cvsroot/software/tuners/MT2063/mt_spuravoid.c,v $
389**
390** Revision History:
391**
392** SCR Date Author Description
393** -------------------------------------------------------------------------
394** 082 03-25-2005 JWS Original multi-tuner support - requires
395** MTxxxx_CNT declarations
396** 096 04-06-2005 DAD Ver 1.11: Fix divide by 0 error if maxH==0.
397** 094 04-06-2005 JWS Ver 1.11 Added uceil and ufloor to get rid
398** of compiler warnings
399** N/A 04-07-2005 DAD Ver 1.13: Merged single- and multi-tuner spur
400** avoidance into a single module.
401** 103 01-31-2005 DAD Ver 1.14: In MT_AddExclZone(), if the range
402** (f_min, f_max) < 0, ignore the entry.
403** 115 03-23-2007 DAD Fix declaration of spur due to truncation
404** errors.
405** 117 03-29-2007 RSK Ver 1.15: Re-wrote to match search order from
406** tuner DLL.
407** 137 06-18-2007 DAD Ver 1.16: Fix possible divide-by-0 error for
408** multi-tuners that have
409** (delta IF1) > (f_out-f_outbw/2).
410** 147 07-27-2007 RSK Ver 1.17: Corrected calculation (-) to (+)
411** Added logic to force f_Center within 1/2 f_Step.
412** 177 S 02-26-2008 RSK Ver 1.18: Corrected calculation using LO1 > MAX/2
413** Type casts added to preserve correct sign.
414** N/A I 06-17-2008 RSK Ver 1.19: Refactoring avoidance of DECT
415** frequencies into MT_ResetExclZones().
416** N/A I 06-20-2008 RSK Ver 1.21: New VERSION number for ver checking.
417**
418*****************************************************************************/
419
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300420/* Version of this module */
421#define MT2063_SPUR_VERSION 10201 /* Version 01.21 */
422
423/* Implement ceiling, floor functions. */
424#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0))
425#define uceil(n, d) ((n)/(d) + ((n)%(d) != 0))
426#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d))
427#define ufloor(n, d) ((n)/(d))
428
429struct MT2063_FIFZone_t {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300430 s32 min_;
431 s32 max_;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300432};
433
434#if MT2063_TUNER_CNT > 1
435static struct MT2063_AvoidSpursData_t *TunerList[MT2063_TUNER_CNT];
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300436static u32 TunerCount = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300437#endif
438
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300439static u32 MT2063_RegisterTuner(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300440{
441#if MT2063_TUNER_CNT == 1
442 pAS_Info->nAS_Algorithm = 1;
443 return MT2063_OK;
444#else
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300445 u32 index;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300446
447 pAS_Info->nAS_Algorithm = 2;
448
449 /*
450 ** Check to see if tuner is already registered
451 */
452 for (index = 0; index < TunerCount; index++) {
453 if (TunerList[index] == pAS_Info) {
454 return MT2063_OK; /* Already here - no problem */
455 }
456 }
457
458 /*
459 ** Add tuner to list - if there is room.
460 */
461 if (TunerCount < MT2063_TUNER_CNT) {
462 TunerList[TunerCount] = pAS_Info;
463 TunerCount++;
464 return MT2063_OK;
465 } else
466 return MT2063_TUNER_CNT_ERR;
467#endif
468}
469
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300470static void MT2063_UnRegisterTuner(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300471{
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300472#if MT2063_TUNER_CNT > 1
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300473 u32 index;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300474
475 for (index = 0; index < TunerCount; index++) {
476 if (TunerList[index] == pAS_Info) {
477 TunerList[index] = TunerList[--TunerCount];
478 }
479 }
480#endif
481}
482
483/*
484** Reset all exclusion zones.
485** Add zones to protect the PLL FracN regions near zero
486**
487** N/A I 06-17-2008 RSK Ver 1.19: Refactoring avoidance of DECT
488** frequencies into MT_ResetExclZones().
489*/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300490static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300491{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300492 u32 center;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300493#if MT2063_TUNER_CNT > 1
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300494 u32 index;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300495 struct MT2063_AvoidSpursData_t *adj;
496#endif
497
498 pAS_Info->nZones = 0; /* this clears the used list */
499 pAS_Info->usedZones = NULL; /* reset ptr */
500 pAS_Info->freeZones = NULL; /* reset ptr */
501
502 center =
503 pAS_Info->f_ref *
504 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 +
505 pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in;
506 while (center <
507 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
508 pAS_Info->f_LO1_FracN_Avoid) {
509 /* Exclude LO1 FracN */
510 MT2063_AddExclZone(pAS_Info,
511 center - pAS_Info->f_LO1_FracN_Avoid,
512 center - 1);
513 MT2063_AddExclZone(pAS_Info, center + 1,
514 center + pAS_Info->f_LO1_FracN_Avoid);
515 center += pAS_Info->f_ref;
516 }
517
518 center =
519 pAS_Info->f_ref *
520 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 -
521 pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out;
522 while (center <
523 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
524 pAS_Info->f_LO2_FracN_Avoid) {
525 /* Exclude LO2 FracN */
526 MT2063_AddExclZone(pAS_Info,
527 center - pAS_Info->f_LO2_FracN_Avoid,
528 center - 1);
529 MT2063_AddExclZone(pAS_Info, center + 1,
530 center + pAS_Info->f_LO2_FracN_Avoid);
531 center += pAS_Info->f_ref;
532 }
533
534 if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
535 /* Exclude LO1 values that conflict with DECT channels */
536 MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */
537 MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */
538 MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */
539 MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */
540 MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */
541 }
542
543 if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
544 MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */
545 MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */
546 MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */
547 MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */
548 MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */
549 MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */
550 MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */
551 MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */
552 MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */
553 MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */
554 }
555#if MT2063_TUNER_CNT > 1
556 /*
557 ** Iterate through all adjacent tuners and exclude frequencies related to them
558 */
559 for (index = 0; index < TunerCount; ++index) {
560 adj = TunerList[index];
561 if (pAS_Info == adj) /* skip over our own data, don't process it */
562 continue;
563
564 /*
565 ** Add 1st IF exclusion zone covering adjacent tuner's LO2
566 ** at "adjfLO2 + f_out" +/- m_MinLOSpacing
567 */
568 if (adj->f_LO2 != 0)
569 MT2063_AddExclZone(pAS_Info,
570 (adj->f_LO2 + pAS_Info->f_out) -
571 pAS_Info->f_min_LO_Separation,
572 (adj->f_LO2 + pAS_Info->f_out) +
573 pAS_Info->f_min_LO_Separation);
574
575 /*
576 ** Add 1st IF exclusion zone covering adjacent tuner's LO1
577 ** at "adjfLO1 - f_in" +/- m_MinLOSpacing
578 */
579 if (adj->f_LO1 != 0)
580 MT2063_AddExclZone(pAS_Info,
581 (adj->f_LO1 - pAS_Info->f_in) -
582 pAS_Info->f_min_LO_Separation,
583 (adj->f_LO1 - pAS_Info->f_in) +
584 pAS_Info->f_min_LO_Separation);
585 }
586#endif
587}
588
589static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t
590 *pAS_Info,
591 struct MT2063_ExclZone_t *pPrevNode)
592{
593 struct MT2063_ExclZone_t *pNode;
594 /* Check for a node in the free list */
595 if (pAS_Info->freeZones != NULL) {
596 /* Use one from the free list */
597 pNode = pAS_Info->freeZones;
598 pAS_Info->freeZones = pNode->next_;
599 } else {
600 /* Grab a node from the array */
601 pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones];
602 }
603
604 if (pPrevNode != NULL) {
605 pNode->next_ = pPrevNode->next_;
606 pPrevNode->next_ = pNode;
607 } else { /* insert at the beginning of the list */
608
609 pNode->next_ = pAS_Info->usedZones;
610 pAS_Info->usedZones = pNode;
611 }
612
613 pAS_Info->nZones++;
614 return pNode;
615}
616
617static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t
618 *pAS_Info,
619 struct MT2063_ExclZone_t *pPrevNode,
620 struct MT2063_ExclZone_t
621 *pNodeToRemove)
622{
623 struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_;
624
625 /* Make previous node point to the subsequent node */
626 if (pPrevNode != NULL)
627 pPrevNode->next_ = pNext;
628
629 /* Add pNodeToRemove to the beginning of the freeZones */
630 pNodeToRemove->next_ = pAS_Info->freeZones;
631 pAS_Info->freeZones = pNodeToRemove;
632
633 /* Decrement node count */
634 pAS_Info->nZones--;
635
636 return pNext;
637}
638
639/*****************************************************************************
640**
641** Name: MT_AddExclZone
642**
643** Description: Add (and merge) an exclusion zone into the list.
644** If the range (f_min, f_max) is totally outside the
645** 1st IF BW, ignore the entry.
646** If the range (f_min, f_max) is negative, ignore the entry.
647**
648** Revision History:
649**
650** SCR Date Author Description
651** -------------------------------------------------------------------------
652** 103 01-31-2005 DAD Ver 1.14: In MT_AddExclZone(), if the range
653** (f_min, f_max) < 0, ignore the entry.
654**
655*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300656static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300657 u32 f_min, u32 f_max)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300658{
659 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
660 struct MT2063_ExclZone_t *pPrev = NULL;
661 struct MT2063_ExclZone_t *pNext = NULL;
662
663 /* Check to see if this overlaps the 1st IF filter */
664 if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2)))
665 && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2)))
666 && (f_min < f_max)) {
667 /*
668 ** 1 2 3 4 5 6
669 **
670 ** New entry: |---| |--| |--| |-| |---| |--|
671 ** or or or or or
672 ** Existing: |--| |--| |--| |---| |-| |--|
673 */
674
675 /* Check for our place in the list */
676 while ((pNode != NULL) && (pNode->max_ < f_min)) {
677 pPrev = pNode;
678 pNode = pNode->next_;
679 }
680
681 if ((pNode != NULL) && (pNode->min_ < f_max)) {
682 /* Combine me with pNode */
683 if (f_min < pNode->min_)
684 pNode->min_ = f_min;
685 if (f_max > pNode->max_)
686 pNode->max_ = f_max;
687 } else {
688 pNode = InsertNode(pAS_Info, pPrev);
689 pNode->min_ = f_min;
690 pNode->max_ = f_max;
691 }
692
693 /* Look for merging possibilities */
694 pNext = pNode->next_;
695 while ((pNext != NULL) && (pNext->min_ < pNode->max_)) {
696 if (pNext->max_ > pNode->max_)
697 pNode->max_ = pNext->max_;
698 pNext = RemoveNode(pAS_Info, pNode, pNext); /* Remove pNext, return ptr to pNext->next */
699 }
700 }
701}
702
703/*****************************************************************************
704**
705** Name: MT_ChooseFirstIF
706**
707** Description: Choose the best available 1st IF
708** If f_Desired is not excluded, choose that first.
709** Otherwise, return the value closest to f_Center that is
710** not excluded
711**
712** Revision History:
713**
714** SCR Date Author Description
715** -------------------------------------------------------------------------
716** 117 03-29-2007 RSK Ver 1.15: Re-wrote to match search order from
717** tuner DLL.
718** 147 07-27-2007 RSK Ver 1.17: Corrected calculation (-) to (+)
719** Added logic to force f_Center within 1/2 f_Step.
720**
721*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300722static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300723{
724 /*
725 ** Update "f_Desired" to be the nearest "combinational-multiple" of "f_LO1_Step".
726 ** The resulting number, F_LO1 must be a multiple of f_LO1_Step. And F_LO1 is the arithmetic sum
727 ** of f_in + f_Center. Neither f_in, nor f_Center must be a multiple of f_LO1_Step.
728 ** However, the sum must be.
729 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300730 const u32 f_Desired =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300731 pAS_Info->f_LO1_Step *
732 ((pAS_Info->f_if1_Request + pAS_Info->f_in +
733 pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) -
734 pAS_Info->f_in;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300735 const u32 f_Step =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300736 (pAS_Info->f_LO1_Step >
737 pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info->
738 f_LO2_Step;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300739 u32 f_Center;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300740
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300741 s32 i;
742 s32 j = 0;
743 u32 bDesiredExcluded = 0;
744 u32 bZeroExcluded = 0;
745 s32 tmpMin, tmpMax;
746 s32 bestDiff;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300747 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
748 struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES];
749
750 if (pAS_Info->nZones == 0)
751 return f_Desired;
752
753 /* f_Center needs to be an integer multiple of f_Step away from f_Desired */
754 if (pAS_Info->f_if1_Center > f_Desired)
755 f_Center =
756 f_Desired +
757 f_Step *
758 ((pAS_Info->f_if1_Center - f_Desired +
759 f_Step / 2) / f_Step);
760 else
761 f_Center =
762 f_Desired -
763 f_Step *
764 ((f_Desired - pAS_Info->f_if1_Center +
765 f_Step / 2) / f_Step);
766
767 //assert;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300768 //if (!abs((s32) f_Center - (s32) pAS_Info->f_if1_Center) <= (s32) (f_Step/2))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300769 // return 0;
770
771 /* Take MT_ExclZones, center around f_Center and change the resolution to f_Step */
772 while (pNode != NULL) {
773 /* floor function */
774 tmpMin =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300775 floor((s32) (pNode->min_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300776
777 /* ceil function */
778 tmpMax =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300779 ceil((s32) (pNode->max_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300780
781 if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired))
782 bDesiredExcluded = 1;
783
784 if ((tmpMin < 0) && (tmpMax > 0))
785 bZeroExcluded = 1;
786
787 /* See if this zone overlaps the previous */
788 if ((j > 0) && (tmpMin < zones[j - 1].max_))
789 zones[j - 1].max_ = tmpMax;
790 else {
791 /* Add new zone */
792 //assert(j<MT2063_MAX_ZONES);
793 //if (j>=MT2063_MAX_ZONES)
794 //break;
795
796 zones[j].min_ = tmpMin;
797 zones[j].max_ = tmpMax;
798 j++;
799 }
800 pNode = pNode->next_;
801 }
802
803 /*
804 ** If the desired is okay, return with it
805 */
806 if (bDesiredExcluded == 0)
807 return f_Desired;
808
809 /*
810 ** If the desired is excluded and the center is okay, return with it
811 */
812 if (bZeroExcluded == 0)
813 return f_Center;
814
815 /* Find the value closest to 0 (f_Center) */
816 bestDiff = zones[0].min_;
817 for (i = 0; i < j; i++) {
818 if (abs(zones[i].min_) < abs(bestDiff))
819 bestDiff = zones[i].min_;
820 if (abs(zones[i].max_) < abs(bestDiff))
821 bestDiff = zones[i].max_;
822 }
823
824 if (bestDiff < 0)
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300825 return f_Center - ((u32) (-bestDiff) * f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300826
827 return f_Center + (bestDiff * f_Step);
828}
829
830/****************************************************************************
831**
832** Name: gcd
833**
834** Description: Uses Euclid's algorithm
835**
836** Parameters: u, v - unsigned values whose GCD is desired.
837**
838** Global: None
839**
840** Returns: greatest common divisor of u and v, if either value
841** is 0, the other value is returned as the result.
842**
843** Dependencies: None.
844**
845** Revision History:
846**
847** SCR Date Author Description
848** -------------------------------------------------------------------------
849** N/A 06-01-2004 JWS Original
850** N/A 08-03-2004 DAD Changed to Euclid's since it can handle
851** unsigned numbers.
852**
853****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300854static u32 MT2063_gcd(u32 u, u32 v)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300855{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300856 u32 r;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300857
858 while (v != 0) {
859 r = u % v;
860 u = v;
861 v = r;
862 }
863
864 return u;
865}
866
867/****************************************************************************
868**
869** Name: umax
870**
871** Description: Implements a simple maximum function for unsigned numbers.
872** Implemented as a function rather than a macro to avoid
873** multiple evaluation of the calling parameters.
874**
875** Parameters: a, b - Values to be compared
876**
877** Global: None
878**
879** Returns: larger of the input values.
880**
881** Dependencies: None.
882**
883** Revision History:
884**
885** SCR Date Author Description
886** -------------------------------------------------------------------------
887** N/A 06-02-2004 JWS Original
888**
889****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300890static u32 MT2063_umax(u32 a, u32 b)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300891{
892 return (a >= b) ? a : b;
893}
894
895#if MT2063_TUNER_CNT > 1
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300896static s32 RoundAwayFromZero(s32 n, s32 d)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300897{
898 return (n < 0) ? floor(n, d) : ceil(n, d);
899}
900
901/****************************************************************************
902**
903** Name: IsSpurInAdjTunerBand
904**
905** Description: Checks to see if a spur will be present within the IF's
906** bandwidth or near the zero IF.
907** (fIFOut +/- fIFBW/2, -fIFOut +/- fIFBW/2)
908** and
909** (0 +/- fZIFBW/2)
910**
911** ma mb me mf mc md
912** <--+-+-+-----------------+-+-+-----------------+-+-+-->
913** | ^ 0 ^ |
914** ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^
915** a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2
916**
917** Note that some equations are doubled to prevent round-off
918** problems when calculating fIFBW/2
919**
920** The spur frequencies are computed as:
921**
922** fSpur = n * f1 - m * f2 - fOffset
923**
924** Parameters: f1 - The 1st local oscillator (LO) frequency
925** of the tuner whose output we are examining
926** f2 - The 1st local oscillator (LO) frequency
927** of the adjacent tuner
928** fOffset - The 2nd local oscillator of the tuner whose
929** output we are examining
930** fIFOut - Output IF center frequency
931** fIFBW - Output IF Bandwidth
932** nMaxH - max # of LO harmonics to search
933** fp - If spur, positive distance to spur-free band edge (returned)
934** fm - If spur, negative distance to spur-free band edge (returned)
935**
936** Returns: 1 if an LO spur would be present, otherwise 0.
937**
938** Dependencies: None.
939**
940** Revision History:
941**
942** SCR Date Author Description
943** -------------------------------------------------------------------------
944** N/A 01-21-2005 JWS Original, adapted from MT_DoubleConversion.
945** 115 03-23-2007 DAD Fix declaration of spur due to truncation
946** errors.
947** 137 06-18-2007 DAD Ver 1.16: Fix possible divide-by-0 error for
948** multi-tuners that have
949** (delta IF1) > (f_out-f_outbw/2).
950** 177 S 02-26-2008 RSK Ver 1.18: Corrected calculation using LO1 > MAX/2
951** Type casts added to preserve correct sign.
952**
953****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300954static u32 IsSpurInAdjTunerBand(u32 bIsMyOutput,
955 u32 f1,
956 u32 f2,
957 u32 fOffset,
958 u32 fIFOut,
959 u32 fIFBW,
960 u32 fZIFBW,
961 u32 nMaxH, u32 * fp, u32 * fm)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300962{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300963 u32 bSpurFound = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300964
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300965 const u32 fHalf_IFBW = fIFBW / 2;
966 const u32 fHalf_ZIFBW = fZIFBW / 2;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300967
968 /* Calculate a scale factor for all frequencies, so that our
969 calculations all stay within 31 bits */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300970 const u32 f_Scale =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300971 ((f1 +
972 (fOffset + fIFOut +
973 fHalf_IFBW) / nMaxH) / (MAX_UDATA / 2 / nMaxH)) + 1;
974
975 /*
976 ** After this scaling, _f1, _f2, and _f3 are guaranteed to fit into
977 ** signed data types (smaller than MAX_UDATA/2)
978 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300979 const s32 _f1 = (s32) (f1 / f_Scale);
980 const s32 _f2 = (s32) (f2 / f_Scale);
981 const s32 _f3 = (s32) (fOffset / f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300982
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300983 const s32 c = (s32) (fIFOut - fHalf_IFBW) / (s32) f_Scale;
984 const s32 d = (s32) ((fIFOut + fHalf_IFBW) / f_Scale);
985 const s32 f = (s32) (fHalf_ZIFBW / f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300986
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300987 s32 ma, mb, mc, md, me, mf;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300988
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300989 s32 fp_ = 0;
990 s32 fm_ = 0;
991 s32 n;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300992
993 /*
994 ** If the other tuner does not have an LO frequency defined,
995 ** assume that we cannot interfere with it
996 */
997 if (f2 == 0)
998 return 0;
999
1000 /* Check out all multiples of f1 from -nMaxH to +nMaxH */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001001 for (n = -(s32) nMaxH; n <= (s32) nMaxH; ++n) {
1002 const s32 nf1 = n * _f1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001003 md = (_f3 + d - nf1) / _f2;
1004
1005 /* If # f2 harmonics > nMaxH, then no spurs present */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001006 if (md <= -(s32) nMaxH)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001007 break;
1008
1009 ma = (_f3 - d - nf1) / _f2;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001010 if ((ma == md) || (ma >= (s32) (nMaxH)))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001011 continue;
1012
1013 mc = (_f3 + c - nf1) / _f2;
1014 if (mc != md) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001015 const s32 m = (n < 0) ? md : mc;
1016 const s32 fspur = (nf1 + m * _f2 - _f3);
1017 const s32 den = (bIsMyOutput ? n - 1 : n);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001018 if (den == 0) {
1019 fp_ = (d - fspur) * f_Scale;
1020 fm_ = (fspur - c) * f_Scale;
1021 } else {
1022 fp_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001023 (s32) RoundAwayFromZero((d - fspur) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001024 f_Scale, den);
1025 fm_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001026 (s32) RoundAwayFromZero((fspur - c) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001027 f_Scale, den);
1028 }
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001029 if (((u32) abs(fm_) >= f_Scale)
1030 && ((u32) abs(fp_) >= f_Scale)) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001031 bSpurFound = 1;
1032 break;
1033 }
1034 }
1035
1036 /* Location of Zero-IF-spur to be checked */
1037 mf = (_f3 + f - nf1) / _f2;
1038 me = (_f3 - f - nf1) / _f2;
1039 if (me != mf) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001040 const s32 m = (n < 0) ? mf : me;
1041 const s32 fspur = (nf1 + m * _f2 - _f3);
1042 const s32 den = (bIsMyOutput ? n - 1 : n);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001043 if (den == 0) {
1044 fp_ = (d - fspur) * f_Scale;
1045 fm_ = (fspur - c) * f_Scale;
1046 } else {
1047 fp_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001048 (s32) RoundAwayFromZero((f - fspur) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001049 f_Scale, den);
1050 fm_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001051 (s32) RoundAwayFromZero((fspur + f) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001052 f_Scale, den);
1053 }
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001054 if (((u32) abs(fm_) >= f_Scale)
1055 && ((u32) abs(fp_) >= f_Scale)) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001056 bSpurFound = 1;
1057 break;
1058 }
1059 }
1060
1061 mb = (_f3 - c - nf1) / _f2;
1062 if (ma != mb) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001063 const s32 m = (n < 0) ? mb : ma;
1064 const s32 fspur = (nf1 + m * _f2 - _f3);
1065 const s32 den = (bIsMyOutput ? n - 1 : n);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001066 if (den == 0) {
1067 fp_ = (d - fspur) * f_Scale;
1068 fm_ = (fspur - c) * f_Scale;
1069 } else {
1070 fp_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001071 (s32) RoundAwayFromZero((-c - fspur) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001072 f_Scale, den);
1073 fm_ =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001074 (s32) RoundAwayFromZero((fspur + d) *
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001075 f_Scale, den);
1076 }
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001077 if (((u32) abs(fm_) >= f_Scale)
1078 && ((u32) abs(fp_) >= f_Scale)) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001079 bSpurFound = 1;
1080 break;
1081 }
1082 }
1083 }
1084
1085 /*
1086 ** Verify that fm & fp are both positive
1087 ** Add one to ensure next 1st IF choice is not right on the edge
1088 */
1089 if (fp_ < 0) {
1090 *fp = -fm_ + 1;
1091 *fm = -fp_ + 1;
1092 } else if (fp_ > 0) {
1093 *fp = fp_ + 1;
1094 *fm = fm_ + 1;
1095 } else {
1096 *fp = 1;
1097 *fm = abs(fm_) + 1;
1098 }
1099
1100 return bSpurFound;
1101}
1102#endif
1103
1104/****************************************************************************
1105**
1106** Name: IsSpurInBand
1107**
1108** Description: Checks to see if a spur will be present within the IF's
1109** bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW)
1110**
1111** ma mb mc md
1112** <--+-+-+-------------------+-------------------+-+-+-->
1113** | ^ 0 ^ |
1114** ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^
1115** a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2
1116**
1117** Note that some equations are doubled to prevent round-off
1118** problems when calculating fIFBW/2
1119**
1120** Parameters: pAS_Info - Avoid Spurs information block
1121** fm - If spur, amount f_IF1 has to move negative
1122** fp - If spur, amount f_IF1 has to move positive
1123**
1124** Global: None
1125**
1126** Returns: 1 if an LO spur would be present, otherwise 0.
1127**
1128** Dependencies: None.
1129**
1130** Revision History:
1131**
1132** SCR Date Author Description
1133** -------------------------------------------------------------------------
1134** N/A 11-28-2002 DAD Implemented algorithm from applied patent
1135**
1136****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001137static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info,
1138 u32 * fm, u32 * fp)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001139{
1140 /*
1141 ** Calculate LO frequency settings.
1142 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001143 u32 n, n0;
1144 const u32 f_LO1 = pAS_Info->f_LO1;
1145 const u32 f_LO2 = pAS_Info->f_LO2;
1146 const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2;
1147 const u32 c = d - pAS_Info->f_out_bw;
1148 const u32 f = pAS_Info->f_zif_bw / 2;
1149 const u32 f_Scale = (f_LO1 / (MAX_UDATA / 2 / pAS_Info->maxH1)) + 1;
1150 s32 f_nsLO1, f_nsLO2;
1151 s32 f_Spur;
1152 u32 ma, mb, mc, md, me, mf;
1153 u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001154#if MT2063_TUNER_CNT > 1
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001155 u32 index;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001156
1157 struct MT2063_AvoidSpursData_t *adj;
1158#endif
1159 *fm = 0;
1160
1161 /*
1162 ** For each edge (d, c & f), calculate a scale, based on the gcd
1163 ** of f_LO1, f_LO2 and the edge value. Use the larger of this
1164 ** gcd-based scale factor or f_Scale.
1165 */
1166 lo_gcd = MT2063_gcd(f_LO1, f_LO2);
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001167 gd_Scale = MT2063_umax((u32) MT2063_gcd(lo_gcd, d), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001168 hgds = gd_Scale / 2;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001169 gc_Scale = MT2063_umax((u32) MT2063_gcd(lo_gcd, c), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001170 hgcs = gc_Scale / 2;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001171 gf_Scale = MT2063_umax((u32) MT2063_gcd(lo_gcd, f), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001172 hgfs = gf_Scale / 2;
1173
1174 n0 = uceil(f_LO2 - d, f_LO1 - f_LO2);
1175
1176 /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */
1177 for (n = n0; n <= pAS_Info->maxH1; ++n) {
1178 md = (n * ((f_LO1 + hgds) / gd_Scale) -
1179 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
1180
1181 /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */
1182 if (md >= pAS_Info->maxH1)
1183 break;
1184
1185 ma = (n * ((f_LO1 + hgds) / gd_Scale) +
1186 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
1187
1188 /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */
1189 if (md == ma)
1190 continue;
1191
1192 mc = (n * ((f_LO1 + hgcs) / gc_Scale) -
1193 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
1194 if (mc != md) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001195 f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale));
1196 f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale));
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001197 f_Spur =
1198 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
1199 n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale);
1200
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001201 *fp = ((f_Spur - (s32) c) / (mc - n)) + 1;
1202 *fm = (((s32) d - f_Spur) / (mc - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001203 return 1;
1204 }
1205
1206 /* Location of Zero-IF-spur to be checked */
1207 me = (n * ((f_LO1 + hgfs) / gf_Scale) +
1208 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
1209 mf = (n * ((f_LO1 + hgfs) / gf_Scale) -
1210 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
1211 if (me != mf) {
1212 f_nsLO1 = n * (f_LO1 / gf_Scale);
1213 f_nsLO2 = me * (f_LO2 / gf_Scale);
1214 f_Spur =
1215 (gf_Scale * (f_nsLO1 - f_nsLO2)) +
1216 n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale);
1217
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001218 *fp = ((f_Spur + (s32) f) / (me - n)) + 1;
1219 *fm = (((s32) f - f_Spur) / (me - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001220 return 1;
1221 }
1222
1223 mb = (n * ((f_LO1 + hgcs) / gc_Scale) +
1224 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
1225 if (ma != mb) {
1226 f_nsLO1 = n * (f_LO1 / gc_Scale);
1227 f_nsLO2 = ma * (f_LO2 / gc_Scale);
1228 f_Spur =
1229 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
1230 n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale);
1231
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001232 *fp = (((s32) d + f_Spur) / (ma - n)) + 1;
1233 *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001234 return 1;
1235 }
1236 }
1237
1238#if MT2063_TUNER_CNT > 1
1239 /* If no spur found, see if there are more tuners on the same board */
1240 for (index = 0; index < TunerCount; ++index) {
1241 adj = TunerList[index];
1242 if (pAS_Info == adj) /* skip over our own data, don't process it */
1243 continue;
1244
1245 /* Look for LO-related spurs from the adjacent tuner generated into my IF output */
1246 if (IsSpurInAdjTunerBand(1, /* check my IF output */
1247 pAS_Info->f_LO1, /* my fLO1 */
1248 adj->f_LO1, /* the other tuner's fLO1 */
1249 pAS_Info->f_LO2, /* my fLO2 */
1250 pAS_Info->f_out, /* my fOut */
1251 pAS_Info->f_out_bw, /* my output IF bandwidth */
1252 pAS_Info->f_zif_bw, /* my Zero-IF bandwidth */
1253 pAS_Info->maxH2, fp, /* minimum amount to move LO's positive */
1254 fm)) /* miminum amount to move LO's negative */
1255 return 1;
1256 /* Look for LO-related spurs from my tuner generated into the adjacent tuner's IF output */
1257 if (IsSpurInAdjTunerBand(0, /* check his IF output */
1258 pAS_Info->f_LO1, /* my fLO1 */
1259 adj->f_LO1, /* the other tuner's fLO1 */
1260 adj->f_LO2, /* the other tuner's fLO2 */
1261 adj->f_out, /* the other tuner's fOut */
1262 adj->f_out_bw, /* the other tuner's output IF bandwidth */
1263 pAS_Info->f_zif_bw, /* the other tuner's Zero-IF bandwidth */
1264 adj->maxH2, fp, /* minimum amount to move LO's positive */
1265 fm)) /* miminum amount to move LO's negative */
1266 return 1;
1267 }
1268#endif
1269 /* No spurs found */
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001270 return 0;
1271}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001272
1273/*****************************************************************************
1274**
1275** Name: MT_AvoidSpurs
1276**
1277** Description: Main entry point to avoid spurs.
1278** Checks for existing spurs in present LO1, LO2 freqs
1279** and if present, chooses spur-free LO1, LO2 combination
1280** that tunes the same input/output frequencies.
1281**
1282** Revision History:
1283**
1284** SCR Date Author Description
1285** -------------------------------------------------------------------------
1286** 096 04-06-2005 DAD Ver 1.11: Fix divide by 0 error if maxH==0.
1287**
1288*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001289static u32 MT2063_AvoidSpurs(void *h, struct MT2063_AvoidSpursData_t * pAS_Info)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001290{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001291 u32 status = MT2063_OK;
1292 u32 fm, fp; /* restricted range on LO's */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001293 pAS_Info->bSpurAvoided = 0;
1294 pAS_Info->nSpursFound = 0;
1295
1296 if (pAS_Info->maxH1 == 0)
1297 return MT2063_OK;
1298
1299 /*
1300 ** Avoid LO Generated Spurs
1301 **
1302 ** Make sure that have no LO-related spurs within the IF output
1303 ** bandwidth.
1304 **
1305 ** If there is an LO spur in this band, start at the current IF1 frequency
1306 ** and work out until we find a spur-free frequency or run up against the
1307 ** 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they
1308 ** will be unchanged if a spur-free setting is not found.
1309 */
1310 pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
1311 if (pAS_Info->bSpurPresent) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001312 u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */
1313 u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */
1314 u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */
1315 u32 delta_IF1;
1316 u32 new_IF1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001317
1318 /*
1319 ** Spur was found, attempt to find a spur-free 1st IF
1320 */
1321 do {
1322 pAS_Info->nSpursFound++;
1323
1324 /* Raise f_IF1_upper, if needed */
1325 MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp);
1326
1327 /* Choose next IF1 that is closest to f_IF1_CENTER */
1328 new_IF1 = MT2063_ChooseFirstIF(pAS_Info);
1329
1330 if (new_IF1 > zfIF1) {
1331 pAS_Info->f_LO1 += (new_IF1 - zfIF1);
1332 pAS_Info->f_LO2 += (new_IF1 - zfIF1);
1333 } else {
1334 pAS_Info->f_LO1 -= (zfIF1 - new_IF1);
1335 pAS_Info->f_LO2 -= (zfIF1 - new_IF1);
1336 }
1337 zfIF1 = new_IF1;
1338
1339 if (zfIF1 > pAS_Info->f_if1_Center)
1340 delta_IF1 = zfIF1 - pAS_Info->f_if1_Center;
1341 else
1342 delta_IF1 = pAS_Info->f_if1_Center - zfIF1;
1343 }
1344 /*
1345 ** Continue while the new 1st IF is still within the 1st IF bandwidth
1346 ** and there is a spur in the band (again)
1347 */
1348 while ((2 * delta_IF1 + pAS_Info->f_out_bw <=
1349 pAS_Info->f_if1_bw)
1350 && (pAS_Info->bSpurPresent =
1351 IsSpurInBand(pAS_Info, &fm, &fp)));
1352
1353 /*
1354 ** Use the LO-spur free values found. If the search went all the way to
1355 ** the 1st IF band edge and always found spurs, just leave the original
1356 ** choice. It's as "good" as any other.
1357 */
1358 if (pAS_Info->bSpurPresent == 1) {
1359 status |= MT2063_SPUR_PRESENT_ERR;
1360 pAS_Info->f_LO1 = zfLO1;
1361 pAS_Info->f_LO2 = zfLO2;
1362 } else
1363 pAS_Info->bSpurAvoided = 1;
1364 }
1365
1366 status |=
1367 ((pAS_Info->
1368 nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK);
1369
1370 return (status);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001371}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001372
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001373//end of mt2063_spuravoid.c
1374//=================================================================
1375//#################################################################
1376//=================================================================
1377
1378/*
1379** The expected version of MT_AvoidSpursData_t
1380** If the version is different, an updated file is needed from Microtune
1381*/
1382/* Expecting version 1.21 of the Spur Avoidance API */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001383
1384typedef enum {
1385 MT2063_SET_ATTEN,
1386 MT2063_INCR_ATTEN,
1387 MT2063_DECR_ATTEN
1388} MT2063_ATTEN_CNTL_MODE;
1389
1390//#define TUNER_MT2063_OPTIMIZATION
1391/*
1392** Constants used by the tuning algorithm
1393*/
1394#define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */
1395#define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */
1396#define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */
1397#define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */
1398#define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */
1399#define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */
1400#define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */
1401#define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */
1402#define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */
1403#define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */
1404#define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */
1405#define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */
1406#define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */
1407#define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */
1408#define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */
1409#define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */
1410#define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */
1411#define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */
1412
1413/*
1414** Define the supported Part/Rev codes for the MT2063
1415*/
1416#define MT2063_B0 (0x9B)
1417#define MT2063_B1 (0x9C)
1418#define MT2063_B2 (0x9D)
1419#define MT2063_B3 (0x9E)
1420
1421/*
1422** The number of Tuner Registers
1423*/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001424static const u32 MT2063_Num_Registers = MT2063_REG_END_REGS;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001425
1426#define USE_GLOBAL_TUNER 0
1427
Mauro Carvalho Chehaba0813ea2011-07-20 21:19:08 -03001428static u32 nMT2063MaxTuners = 1;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001429static u32 nMT2063OpenTuners = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001430
1431/*
1432** Constants for setting receiver modes.
1433** (6 modes defined at this time, enumerated by MT2063_RCVR_MODES)
1434** (DNC1GC & DNC2GC are the values, which are used, when the specific
1435** DNC Output is selected, the other is always off)
1436**
1437** If PAL-L or L' is received, set:
1438** MT2063_SetParam(hMT2063,MT2063_TAGC,1);
1439**
1440** --------------+----------------------------------------------
1441** Mode 0 : | MT2063_CABLE_QAM
1442** Mode 1 : | MT2063_CABLE_ANALOG
1443** Mode 2 : | MT2063_OFFAIR_COFDM
1444** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
1445** Mode 4 : | MT2063_OFFAIR_ANALOG
1446** Mode 5 : | MT2063_OFFAIR_8VSB
1447** --------------+----+----+----+----+-----+-----+--------------
1448** Mode | 0 | 1 | 2 | 3 | 4 | 5 |
1449** --------------+----+----+----+----+-----+-----+
1450**
1451**
1452*/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001453static const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 };
1454static const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 };
1455static const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 };
1456static const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 };
1457static const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 };
1458static const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 };
1459static const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 };
1460static const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 };
1461static const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
1462static const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 };
1463static const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 };
1464static const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
1465static const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 };
1466static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 };
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001467
1468/*
1469** Local Function Prototypes - not available for external access.
1470*/
1471
1472/* Forward declaration(s): */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001473static u32 MT2063_CalcLO1Mult(u32 * Div, u32 * FracN, u32 f_LO,
1474 u32 f_LO_Step, u32 f_Ref);
1475static u32 MT2063_CalcLO2Mult(u32 * Div, u32 * FracN, u32 f_LO,
1476 u32 f_LO_Step, u32 f_Ref);
1477static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num,
1478 u32 denom);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001479
1480/******************************************************************************
1481**
1482** Name: MT2063_Open
1483**
1484** Description: Initialize the tuner's register values.
1485**
1486** Parameters: MT2063_Addr - Serial bus address of the tuner.
1487** hMT2063 - Tuner handle passed back.
1488** hUserData - User-defined data, if needed for the
1489** MT_ReadSub() & MT_WriteSub functions.
1490**
1491** Returns: status:
1492** MT_OK - No errors
1493** MT_TUNER_ID_ERR - Tuner Part/Rev code mismatch
1494** MT_TUNER_INIT_ERR - Tuner initialization failed
1495** MT_COMM_ERR - Serial bus communications error
1496** MT_ARG_NULL - Null pointer argument passed
1497** MT_TUNER_CNT_ERR - Too many tuners open
1498**
1499** Dependencies: MT_ReadSub - Read byte(s) of data from the two-wire bus
1500** MT_WriteSub - Write byte(s) of data to the two-wire bus
1501**
1502** Revision History:
1503**
1504** SCR Date Author Description
1505** -------------------------------------------------------------------------
1506** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1507**
1508******************************************************************************/
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -03001509static u32 MT2063_Open(u32 MT2063_Addr, struct MT2063_Info_t **hMT2063, void *hUserData)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001510{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001511 u32 status = MT2063_OK; /* Status to be returned. */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001512 struct MT2063_Info_t *pInfo = NULL;
1513 struct dvb_frontend *fe = (struct dvb_frontend *)hUserData;
1514 struct mt2063_state *state = fe->tuner_priv;
1515
1516 /* Check the argument before using */
1517 if (hMT2063 == NULL) {
1518 return MT2063_ARG_NULL;
1519 }
1520
1521 /* Default tuner handle to NULL. If successful, it will be reassigned */
1522
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001523 if (state->MT2063_init == false) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001524 pInfo = kzalloc(sizeof(struct MT2063_Info_t), GFP_KERNEL);
1525 if (pInfo == NULL) {
1526 return MT2063_TUNER_OPEN_ERR;
1527 }
1528 pInfo->handle = NULL;
1529 pInfo->address = MAX_UDATA;
1530 pInfo->rcvr_mode = MT2063_CABLE_QAM;
1531 pInfo->hUserData = NULL;
1532 } else {
1533 pInfo = *hMT2063;
1534 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001535
1536 if (MT2063_NO_ERROR(status)) {
1537 status |= MT2063_RegisterTuner(&pInfo->AS_Data);
1538 }
1539
1540 if (MT2063_NO_ERROR(status)) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001541 pInfo->handle = (void *) pInfo;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001542
1543 pInfo->hUserData = hUserData;
1544 pInfo->address = MT2063_Addr;
1545 pInfo->rcvr_mode = MT2063_CABLE_QAM;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001546 status |= MT2063_ReInit((void *) pInfo);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001547 }
1548
1549 if (MT2063_IS_ERROR(status))
1550 /* MT2063_Close handles the un-registration of the tuner */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001551 MT2063_Close((void *) pInfo);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001552 else {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001553 state->MT2063_init = true;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001554 *hMT2063 = pInfo->handle;
1555
1556 }
1557
1558 return (status);
1559}
1560
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001561static u32 MT2063_IsValidHandle(struct MT2063_Info_t *handle)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001562{
1563 return ((handle != NULL) && (handle->handle == handle)) ? 1 : 0;
1564}
1565
1566/******************************************************************************
1567**
1568** Name: MT2063_Close
1569**
1570** Description: Release the handle to the tuner.
1571**
1572** Parameters: hMT2063 - Handle to the MT2063 tuner
1573**
1574** Returns: status:
1575** MT_OK - No errors
1576** MT_INV_HANDLE - Invalid tuner handle
1577**
1578** Dependencies: mt_errordef.h - definition of error codes
1579**
1580** Revision History:
1581**
1582** SCR Date Author Description
1583** -------------------------------------------------------------------------
1584** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1585**
1586******************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001587static u32 MT2063_Close(void *hMT2063)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001588{
1589 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)hMT2063;
1590
1591 if (!MT2063_IsValidHandle(pInfo))
1592 return MT2063_INV_HANDLE;
1593
1594 /* Unregister tuner with SpurAvoidance routines (if needed) */
1595 MT2063_UnRegisterTuner(&pInfo->AS_Data);
1596 /* Now remove the tuner from our own list of tuners */
1597 pInfo->handle = NULL;
1598 pInfo->address = MAX_UDATA;
1599 pInfo->hUserData = NULL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001600 //kfree(pInfo);
1601 //pInfo = NULL;
Mauro Carvalho Chehaba0813ea2011-07-20 21:19:08 -03001602
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001603 return MT2063_OK;
1604}
1605
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001606/****************************************************************************
1607**
1608** Name: MT2063_GetLocked
1609**
1610** Description: Checks to see if LO1 and LO2 are locked.
1611**
1612** Parameters: h - Open handle to the tuner (from MT2063_Open).
1613**
1614** Returns: status:
1615** MT_OK - No errors
1616** MT_UPC_UNLOCK - Upconverter PLL unlocked
1617** MT_DNC_UNLOCK - Downconverter PLL unlocked
1618** MT_COMM_ERR - Serial bus communications error
1619** MT_INV_HANDLE - Invalid tuner handle
1620**
1621** Dependencies: MT_ReadSub - Read byte(s) of data from the serial bus
1622** MT_Sleep - Delay execution for x milliseconds
1623**
1624** Revision History:
1625**
1626** SCR Date Author Description
1627** -------------------------------------------------------------------------
1628** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1629**
1630****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001631static u32 MT2063_GetLocked(void *h)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001632{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001633 const u32 nMaxWait = 100; /* wait a maximum of 100 msec */
1634 const u32 nPollRate = 2; /* poll status bits every 2 ms */
1635 const u32 nMaxLoops = nMaxWait / nPollRate;
1636 const u8 LO1LK = 0x80;
1637 u8 LO2LK = 0x08;
1638 u32 status = MT2063_OK; /* Status to be returned */
1639 u32 nDelays = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001640 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
1641
1642 if (MT2063_IsValidHandle(pInfo) == 0)
1643 return MT2063_INV_HANDLE;
1644
1645 /* LO2 Lock bit was in a different place for B0 version */
1646 if (pInfo->tuner_id == MT2063_B0)
1647 LO2LK = 0x40;
1648
1649 do {
1650 status |=
1651 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
1652 MT2063_REG_LO_STATUS,
1653 &pInfo->reg[MT2063_REG_LO_STATUS], 1);
1654
1655 if (MT2063_IS_ERROR(status))
1656 return (status);
1657
1658 if ((pInfo->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) ==
1659 (LO1LK | LO2LK)) {
1660 return (status);
1661 }
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001662 msleep(nPollRate); /* Wait between retries */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001663 }
1664 while (++nDelays < nMaxLoops);
1665
1666 if ((pInfo->reg[MT2063_REG_LO_STATUS] & LO1LK) == 0x00)
1667 status |= MT2063_UPC_UNLOCK;
1668 if ((pInfo->reg[MT2063_REG_LO_STATUS] & LO2LK) == 0x00)
1669 status |= MT2063_DNC_UNLOCK;
1670
1671 return (status);
1672}
1673
1674/****************************************************************************
1675**
1676** Name: MT2063_GetParam
1677**
1678** Description: Gets a tuning algorithm parameter.
1679**
1680** This function provides access to the internals of the
1681** tuning algorithm - mostly for testing purposes.
1682**
1683** Parameters: h - Tuner handle (returned by MT2063_Open)
1684** param - Tuning algorithm parameter
1685** (see enum MT2063_Param)
1686** pValue - ptr to returned value
1687**
1688** param Description
1689** ---------------------- --------------------------------
1690** MT2063_IC_ADDR Serial Bus address of this tuner
1691** MT2063_MAX_OPEN Max # of MT2063's allowed open
1692** MT2063_NUM_OPEN # of MT2063's open
1693** MT2063_SRO_FREQ crystal frequency
1694** MT2063_STEPSIZE minimum tuning step size
1695** MT2063_INPUT_FREQ input center frequency
1696** MT2063_LO1_FREQ LO1 Frequency
1697** MT2063_LO1_STEPSIZE LO1 minimum step size
1698** MT2063_LO1_FRACN_AVOID LO1 FracN keep-out region
1699** MT2063_IF1_ACTUAL Current 1st IF in use
1700** MT2063_IF1_REQUEST Requested 1st IF
1701** MT2063_IF1_CENTER Center of 1st IF SAW filter
1702** MT2063_IF1_BW Bandwidth of 1st IF SAW filter
1703** MT2063_ZIF_BW zero-IF bandwidth
1704** MT2063_LO2_FREQ LO2 Frequency
1705** MT2063_LO2_STEPSIZE LO2 minimum step size
1706** MT2063_LO2_FRACN_AVOID LO2 FracN keep-out region
1707** MT2063_OUTPUT_FREQ output center frequency
1708** MT2063_OUTPUT_BW output bandwidth
1709** MT2063_LO_SEPARATION min inter-tuner LO separation
1710** MT2063_AS_ALG ID of avoid-spurs algorithm in use
1711** MT2063_MAX_HARM1 max # of intra-tuner harmonics
1712** MT2063_MAX_HARM2 max # of inter-tuner harmonics
1713** MT2063_EXCL_ZONES # of 1st IF exclusion zones
1714** MT2063_NUM_SPURS # of spurs found/avoided
1715** MT2063_SPUR_AVOIDED >0 spurs avoided
1716** MT2063_SPUR_PRESENT >0 spurs in output (mathematically)
1717** MT2063_RCVR_MODE Predefined modes.
1718** MT2063_ACLNA LNA attenuator gain code
1719** MT2063_ACRF RF attenuator gain code
1720** MT2063_ACFIF FIF attenuator gain code
1721** MT2063_ACLNA_MAX LNA attenuator limit
1722** MT2063_ACRF_MAX RF attenuator limit
1723** MT2063_ACFIF_MAX FIF attenuator limit
1724** MT2063_PD1 Actual value of PD1
1725** MT2063_PD2 Actual value of PD2
1726** MT2063_DNC_OUTPUT_ENABLE DNC output selection
1727** MT2063_VGAGC VGA gain code
1728** MT2063_VGAOI VGA output current
1729** MT2063_TAGC TAGC setting
1730** MT2063_AMPGC AMP gain code
1731** MT2063_AVOID_DECT Avoid DECT Frequencies
1732** MT2063_CTFILT_SW Cleartune filter selection
1733**
1734** Usage: status |= MT2063_GetParam(hMT2063,
1735** MT2063_IF1_ACTUAL,
1736** &f_IF1_Actual);
1737**
1738** Returns: status:
1739** MT_OK - No errors
1740** MT_INV_HANDLE - Invalid tuner handle
1741** MT_ARG_NULL - Null pointer argument passed
1742** MT_ARG_RANGE - Invalid parameter requested
1743**
1744** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
1745**
1746** See Also: MT2063_SetParam, MT2063_Open
1747**
1748** Revision History:
1749**
1750** SCR Date Author Description
1751** -------------------------------------------------------------------------
1752** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1753** 154 09-13-2007 RSK Ver 1.05: Get/SetParam changes for LOx_FREQ
1754** 10-31-2007 PINZ Ver 1.08: Get/SetParam add VGAGC, VGAOI, AMPGC, TAGC
1755** 173 M 01-23-2008 RSK Ver 1.12: Read LO1C and LO2C registers from HW
1756** in GetParam.
1757** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
1758** Split SetParam up to ACLNA / ACLNA_MAX
1759** removed ACLNA_INRC/DECR (+RF & FIF)
1760** removed GCUAUTO / BYPATNDN/UP
1761** 175 I 16-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
1762** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
1763** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
1764**
1765****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001766static u32 MT2063_GetParam(void *h, enum MT2063_Param param, u32 * pValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001767{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001768 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001769 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001770 u32 Div;
1771 u32 Num;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001772
1773 if (pValue == NULL)
1774 status |= MT2063_ARG_NULL;
1775
1776 /* Verify that the handle passed points to a valid tuner */
1777 if (MT2063_IsValidHandle(pInfo) == 0)
1778 status |= MT2063_INV_HANDLE;
1779
1780 if (MT2063_NO_ERROR(status)) {
1781 switch (param) {
1782 /* Serial Bus address of this tuner */
1783 case MT2063_IC_ADDR:
1784 *pValue = pInfo->address;
1785 break;
1786
1787 /* Max # of MT2063's allowed to be open */
1788 case MT2063_MAX_OPEN:
1789 *pValue = nMT2063MaxTuners;
1790 break;
1791
1792 /* # of MT2063's open */
1793 case MT2063_NUM_OPEN:
1794 *pValue = nMT2063OpenTuners;
1795 break;
1796
1797 /* crystal frequency */
1798 case MT2063_SRO_FREQ:
1799 *pValue = pInfo->AS_Data.f_ref;
1800 break;
1801
1802 /* minimum tuning step size */
1803 case MT2063_STEPSIZE:
1804 *pValue = pInfo->AS_Data.f_LO2_Step;
1805 break;
1806
1807 /* input center frequency */
1808 case MT2063_INPUT_FREQ:
1809 *pValue = pInfo->AS_Data.f_in;
1810 break;
1811
1812 /* LO1 Frequency */
1813 case MT2063_LO1_FREQ:
1814 {
1815 /* read the actual tuner register values for LO1C_1 and LO1C_2 */
1816 status |=
1817 MT2063_ReadSub(pInfo->hUserData,
1818 pInfo->address,
1819 MT2063_REG_LO1C_1,
1820 &pInfo->
1821 reg[MT2063_REG_LO1C_1], 2);
1822 Div = pInfo->reg[MT2063_REG_LO1C_1];
1823 Num = pInfo->reg[MT2063_REG_LO1C_2] & 0x3F;
1824 pInfo->AS_Data.f_LO1 =
1825 (pInfo->AS_Data.f_ref * Div) +
1826 MT2063_fLO_FractionalTerm(pInfo->AS_Data.
1827 f_ref, Num, 64);
1828 }
1829 *pValue = pInfo->AS_Data.f_LO1;
1830 break;
1831
1832 /* LO1 minimum step size */
1833 case MT2063_LO1_STEPSIZE:
1834 *pValue = pInfo->AS_Data.f_LO1_Step;
1835 break;
1836
1837 /* LO1 FracN keep-out region */
1838 case MT2063_LO1_FRACN_AVOID_PARAM:
1839 *pValue = pInfo->AS_Data.f_LO1_FracN_Avoid;
1840 break;
1841
1842 /* Current 1st IF in use */
1843 case MT2063_IF1_ACTUAL:
1844 *pValue = pInfo->f_IF1_actual;
1845 break;
1846
1847 /* Requested 1st IF */
1848 case MT2063_IF1_REQUEST:
1849 *pValue = pInfo->AS_Data.f_if1_Request;
1850 break;
1851
1852 /* Center of 1st IF SAW filter */
1853 case MT2063_IF1_CENTER:
1854 *pValue = pInfo->AS_Data.f_if1_Center;
1855 break;
1856
1857 /* Bandwidth of 1st IF SAW filter */
1858 case MT2063_IF1_BW:
1859 *pValue = pInfo->AS_Data.f_if1_bw;
1860 break;
1861
1862 /* zero-IF bandwidth */
1863 case MT2063_ZIF_BW:
1864 *pValue = pInfo->AS_Data.f_zif_bw;
1865 break;
1866
1867 /* LO2 Frequency */
1868 case MT2063_LO2_FREQ:
1869 {
1870 /* Read the actual tuner register values for LO2C_1, LO2C_2 and LO2C_3 */
1871 status |=
1872 MT2063_ReadSub(pInfo->hUserData,
1873 pInfo->address,
1874 MT2063_REG_LO2C_1,
1875 &pInfo->
1876 reg[MT2063_REG_LO2C_1], 3);
1877 Div =
1878 (pInfo->reg[MT2063_REG_LO2C_1] & 0xFE) >> 1;
1879 Num =
1880 ((pInfo->
1881 reg[MT2063_REG_LO2C_1] & 0x01) << 12) |
1882 (pInfo->
1883 reg[MT2063_REG_LO2C_2] << 4) | (pInfo->
1884 reg
1885 [MT2063_REG_LO2C_3]
1886 & 0x00F);
1887 pInfo->AS_Data.f_LO2 =
1888 (pInfo->AS_Data.f_ref * Div) +
1889 MT2063_fLO_FractionalTerm(pInfo->AS_Data.
1890 f_ref, Num, 8191);
1891 }
1892 *pValue = pInfo->AS_Data.f_LO2;
1893 break;
1894
1895 /* LO2 minimum step size */
1896 case MT2063_LO2_STEPSIZE:
1897 *pValue = pInfo->AS_Data.f_LO2_Step;
1898 break;
1899
1900 /* LO2 FracN keep-out region */
1901 case MT2063_LO2_FRACN_AVOID:
1902 *pValue = pInfo->AS_Data.f_LO2_FracN_Avoid;
1903 break;
1904
1905 /* output center frequency */
1906 case MT2063_OUTPUT_FREQ:
1907 *pValue = pInfo->AS_Data.f_out;
1908 break;
1909
1910 /* output bandwidth */
1911 case MT2063_OUTPUT_BW:
1912 *pValue = pInfo->AS_Data.f_out_bw - 750000;
1913 break;
1914
1915 /* min inter-tuner LO separation */
1916 case MT2063_LO_SEPARATION:
1917 *pValue = pInfo->AS_Data.f_min_LO_Separation;
1918 break;
1919
1920 /* ID of avoid-spurs algorithm in use */
1921 case MT2063_AS_ALG:
1922 *pValue = pInfo->AS_Data.nAS_Algorithm;
1923 break;
1924
1925 /* max # of intra-tuner harmonics */
1926 case MT2063_MAX_HARM1:
1927 *pValue = pInfo->AS_Data.maxH1;
1928 break;
1929
1930 /* max # of inter-tuner harmonics */
1931 case MT2063_MAX_HARM2:
1932 *pValue = pInfo->AS_Data.maxH2;
1933 break;
1934
1935 /* # of 1st IF exclusion zones */
1936 case MT2063_EXCL_ZONES:
1937 *pValue = pInfo->AS_Data.nZones;
1938 break;
1939
1940 /* # of spurs found/avoided */
1941 case MT2063_NUM_SPURS:
1942 *pValue = pInfo->AS_Data.nSpursFound;
1943 break;
1944
1945 /* >0 spurs avoided */
1946 case MT2063_SPUR_AVOIDED:
1947 *pValue = pInfo->AS_Data.bSpurAvoided;
1948 break;
1949
1950 /* >0 spurs in output (mathematically) */
1951 case MT2063_SPUR_PRESENT:
1952 *pValue = pInfo->AS_Data.bSpurPresent;
1953 break;
1954
1955 /* Predefined receiver setup combination */
1956 case MT2063_RCVR_MODE:
1957 *pValue = pInfo->rcvr_mode;
1958 break;
1959
1960 case MT2063_PD1:
1961 case MT2063_PD2:
1962 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001963 u8 mask = (param == MT2063_PD1 ? 0x01 : 0x03); /* PD1 vs PD2 */
1964 u8 orig = (pInfo->reg[MT2063_REG_BYP_CTRL]);
1965 u8 reg = (orig & 0xF1) | mask; /* Only set 3 bits (not 5) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001966 int i;
1967
1968 *pValue = 0;
1969
1970 /* Initiate ADC output to reg 0x0A */
1971 if (reg != orig)
1972 status |=
1973 MT2063_WriteSub(pInfo->hUserData,
1974 pInfo->address,
1975 MT2063_REG_BYP_CTRL,
1976 &reg, 1);
1977
1978 if (MT2063_IS_ERROR(status))
1979 return (status);
1980
1981 for (i = 0; i < 8; i++) {
1982 status |=
1983 MT2063_ReadSub(pInfo->hUserData,
1984 pInfo->address,
1985 MT2063_REG_ADC_OUT,
1986 &pInfo->
1987 reg
1988 [MT2063_REG_ADC_OUT],
1989 1);
1990
1991 if (MT2063_NO_ERROR(status))
1992 *pValue +=
1993 pInfo->
1994 reg[MT2063_REG_ADC_OUT];
1995 else {
1996 if (i)
1997 *pValue /= i;
1998 return (status);
1999 }
2000 }
2001 *pValue /= 8; /* divide by number of reads */
2002 *pValue >>= 2; /* only want 6 MSB's out of 8 */
2003
2004 /* Restore value of Register BYP_CTRL */
2005 if (reg != orig)
2006 status |=
2007 MT2063_WriteSub(pInfo->hUserData,
2008 pInfo->address,
2009 MT2063_REG_BYP_CTRL,
2010 &orig, 1);
2011 }
2012 break;
2013
2014 /* Get LNA attenuator code */
2015 case MT2063_ACLNA:
2016 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002017 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002018 status |=
2019 MT2063_GetReg(pInfo, MT2063_REG_XO_STATUS,
2020 &val);
2021 *pValue = val & 0x1f;
2022 }
2023 break;
2024
2025 /* Get RF attenuator code */
2026 case MT2063_ACRF:
2027 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002028 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002029 status |=
2030 MT2063_GetReg(pInfo, MT2063_REG_RF_STATUS,
2031 &val);
2032 *pValue = val & 0x1f;
2033 }
2034 break;
2035
2036 /* Get FIF attenuator code */
2037 case MT2063_ACFIF:
2038 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002039 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002040 status |=
2041 MT2063_GetReg(pInfo, MT2063_REG_FIF_STATUS,
2042 &val);
2043 *pValue = val & 0x1f;
2044 }
2045 break;
2046
2047 /* Get LNA attenuator limit */
2048 case MT2063_ACLNA_MAX:
2049 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002050 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002051 status |=
2052 MT2063_GetReg(pInfo, MT2063_REG_LNA_OV,
2053 &val);
2054 *pValue = val & 0x1f;
2055 }
2056 break;
2057
2058 /* Get RF attenuator limit */
2059 case MT2063_ACRF_MAX:
2060 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002061 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002062 status |=
2063 MT2063_GetReg(pInfo, MT2063_REG_RF_OV,
2064 &val);
2065 *pValue = val & 0x1f;
2066 }
2067 break;
2068
2069 /* Get FIF attenuator limit */
2070 case MT2063_ACFIF_MAX:
2071 {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002072 u8 val;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002073 status |=
2074 MT2063_GetReg(pInfo, MT2063_REG_FIF_OV,
2075 &val);
2076 *pValue = val & 0x1f;
2077 }
2078 break;
2079
2080 /* Get current used DNC output */
2081 case MT2063_DNC_OUTPUT_ENABLE:
2082 {
2083 if ((pInfo->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */
2084 if ((pInfo->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
2085 *pValue =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002086 (u32) MT2063_DNC_NONE;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002087 else
2088 *pValue =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002089 (u32) MT2063_DNC_2;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002090 } else { /* DNC1 is on */
2091
2092 if ((pInfo->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
2093 *pValue =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002094 (u32) MT2063_DNC_1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002095 else
2096 *pValue =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002097 (u32) MT2063_DNC_BOTH;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002098 }
2099 }
2100 break;
2101
2102 /* Get VGA Gain Code */
2103 case MT2063_VGAGC:
2104 *pValue =
2105 ((pInfo->reg[MT2063_REG_VGA_GAIN] & 0x0C) >> 2);
2106 break;
2107
2108 /* Get VGA bias current */
2109 case MT2063_VGAOI:
2110 *pValue = (pInfo->reg[MT2063_REG_RSVD_31] & 0x07);
2111 break;
2112
2113 /* Get TAGC setting */
2114 case MT2063_TAGC:
2115 *pValue = (pInfo->reg[MT2063_REG_RSVD_1E] & 0x03);
2116 break;
2117
2118 /* Get AMP Gain Code */
2119 case MT2063_AMPGC:
2120 *pValue = (pInfo->reg[MT2063_REG_TEMP_SEL] & 0x03);
2121 break;
2122
2123 /* Avoid DECT Frequencies */
2124 case MT2063_AVOID_DECT:
2125 *pValue = pInfo->AS_Data.avoidDECT;
2126 break;
2127
2128 /* Cleartune filter selection: 0 - by IC (default), 1 - by software */
2129 case MT2063_CTFILT_SW:
2130 *pValue = pInfo->ctfilt_sw;
2131 break;
2132
2133 case MT2063_EOP:
2134 default:
2135 status |= MT2063_ARG_RANGE;
2136 }
2137 }
2138 return (status);
2139}
2140
2141/****************************************************************************
2142**
2143** Name: MT2063_GetReg
2144**
2145** Description: Gets an MT2063 register.
2146**
2147** Parameters: h - Tuner handle (returned by MT2063_Open)
2148** reg - MT2063 register/subaddress location
2149** *val - MT2063 register/subaddress value
2150**
2151** Returns: status:
2152** MT_OK - No errors
2153** MT_COMM_ERR - Serial bus communications error
2154** MT_INV_HANDLE - Invalid tuner handle
2155** MT_ARG_NULL - Null pointer argument passed
2156** MT_ARG_RANGE - Argument out of range
2157**
2158** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
2159**
2160** Use this function if you need to read a register from
2161** the MT2063.
2162**
2163** Revision History:
2164**
2165** SCR Date Author Description
2166** -------------------------------------------------------------------------
2167** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2168**
2169****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002170static u32 MT2063_GetReg(void *h, u8 reg, u8 * val)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002171{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002172 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002173 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
2174
2175 /* Verify that the handle passed points to a valid tuner */
2176 if (MT2063_IsValidHandle(pInfo) == 0)
2177 status |= MT2063_INV_HANDLE;
2178
2179 if (val == NULL)
2180 status |= MT2063_ARG_NULL;
2181
2182 if (reg >= MT2063_REG_END_REGS)
2183 status |= MT2063_ARG_RANGE;
2184
2185 if (MT2063_NO_ERROR(status)) {
2186 status |=
2187 MT2063_ReadSub(pInfo->hUserData, pInfo->address, reg,
2188 &pInfo->reg[reg], 1);
2189 if (MT2063_NO_ERROR(status))
2190 *val = pInfo->reg[reg];
2191 }
2192
2193 return (status);
2194}
2195
2196/******************************************************************************
2197**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002198** Name: MT2063_SetReceiverMode
2199**
2200** Description: Set the MT2063 receiver mode
2201**
2202** --------------+----------------------------------------------
2203** Mode 0 : | MT2063_CABLE_QAM
2204** Mode 1 : | MT2063_CABLE_ANALOG
2205** Mode 2 : | MT2063_OFFAIR_COFDM
2206** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
2207** Mode 4 : | MT2063_OFFAIR_ANALOG
2208** Mode 5 : | MT2063_OFFAIR_8VSB
2209** --------------+----+----+----+----+-----+--------------------
2210** (DNC1GC & DNC2GC are the values, which are used, when the specific
2211** DNC Output is selected, the other is always off)
2212**
2213** |<---------- Mode -------------->|
2214** Reg Field | 0 | 1 | 2 | 3 | 4 | 5 |
2215** ------------+-----+-----+-----+-----+-----+-----+
2216** RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF
2217** LNARin | 0 | 0 | 3 | 3 | 3 | 3
2218** FIFFQen | 1 | 1 | 1 | 1 | 1 | 1
2219** FIFFq | 0 | 0 | 0 | 0 | 0 | 0
2220** DNC1gc | 0 | 0 | 0 | 0 | 0 | 0
2221** DNC2gc | 0 | 0 | 0 | 0 | 0 | 0
2222** GCU Auto | 1 | 1 | 1 | 1 | 1 | 1
2223** LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31
2224** LNA Target | 44 | 43 | 43 | 43 | 43 | 43
2225** ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0
2226** RF max Atn | 31 | 31 | 31 | 31 | 31 | 31
2227** PD1 Target | 36 | 36 | 38 | 38 | 36 | 38
2228** ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0
2229** FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5
2230** PD2 Target | 40 | 33 | 42 | 42 | 33 | 42
2231**
2232**
2233** Parameters: pInfo - ptr to MT2063_Info_t structure
2234** Mode - desired reciever mode
2235**
2236** Usage: status = MT2063_SetReceiverMode(hMT2063, Mode);
2237**
2238** Returns: status:
2239** MT_OK - No errors
2240** MT_COMM_ERR - Serial bus communications error
2241**
2242** Dependencies: MT2063_SetReg - Write a byte of data to a HW register.
2243** Assumes that the tuner cache is valid.
2244**
2245** Revision History:
2246**
2247** SCR Date Author Description
2248** -------------------------------------------------------------------------
2249** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2250** N/A 01-10-2007 PINZ Added additional GCU Settings, FIFF Calib will be triggered
2251** 155 10-01-2007 DAD Ver 1.06: Add receiver mode for SECAM positive
2252** modulation
2253** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
2254** N/A 10-22-2007 PINZ Ver 1.07: Changed some Registers at init to have
2255** the same settings as with MT Launcher
2256** N/A 10-30-2007 PINZ Add SetParam VGAGC & VGAOI
2257** Add SetParam DNC_OUTPUT_ENABLE
2258** Removed VGAGC from receiver mode,
2259** default now 1
2260** N/A 10-31-2007 PINZ Ver 1.08: Add SetParam TAGC, removed from rcvr-mode
2261** Add SetParam AMPGC, removed from rcvr-mode
2262** Corrected names of GCU values
2263** reorganized receiver modes, removed,
2264** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
2265** Actualized Receiver-Mode values
2266** N/A 11-12-2007 PINZ Ver 1.09: Actualized Receiver-Mode values
2267** N/A 11-27-2007 PINZ Improved buffered writing
2268** 01-03-2008 PINZ Ver 1.10: Added a trigger of BYPATNUP for
2269** correct wakeup of the LNA after shutdown
2270** Set AFCsd = 1 as default
2271** Changed CAP1sel default
2272** 01-14-2008 PINZ Ver 1.11: Updated gain settings
2273** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
2274** Split SetParam up to ACLNA / ACLNA_MAX
2275** removed ACLNA_INRC/DECR (+RF & FIF)
2276** removed GCUAUTO / BYPATNDN/UP
2277**
2278******************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002279static u32 MT2063_SetReceiverMode(struct MT2063_Info_t *pInfo,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002280 enum MT2063_RCVR_MODES Mode)
2281{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002282 u32 status = MT2063_OK; /* Status to be returned */
2283 u8 val;
2284 u32 longval;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002285
2286 if (Mode >= MT2063_NUM_RCVR_MODES)
2287 status = MT2063_ARG_RANGE;
2288
2289 /* RFAGCen */
2290 if (MT2063_NO_ERROR(status)) {
2291 val =
2292 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002293 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x40) | (RFAGCEN[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002294 ? 0x40 :
2295 0x00);
2296 if (pInfo->reg[MT2063_REG_PD1_TGT] != val) {
2297 status |= MT2063_SetReg(pInfo, MT2063_REG_PD1_TGT, val);
2298 }
2299 }
2300
2301 /* LNARin */
2302 if (MT2063_NO_ERROR(status)) {
2303 status |= MT2063_SetParam(pInfo, MT2063_LNA_RIN, LNARIN[Mode]);
2304 }
2305
2306 /* FIFFQEN and FIFFQ */
2307 if (MT2063_NO_ERROR(status)) {
2308 val =
2309 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002310 reg[MT2063_REG_FIFF_CTRL2] & (u8) ~ 0xF0) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002311 (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
2312 if (pInfo->reg[MT2063_REG_FIFF_CTRL2] != val) {
2313 status |=
2314 MT2063_SetReg(pInfo, MT2063_REG_FIFF_CTRL2, val);
2315 /* trigger FIFF calibration, needed after changing FIFFQ */
2316 val =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002317 (pInfo->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002318 status |=
2319 MT2063_SetReg(pInfo, MT2063_REG_FIFF_CTRL, val);
2320 val =
2321 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002322 reg[MT2063_REG_FIFF_CTRL] & (u8) ~ 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002323 status |=
2324 MT2063_SetReg(pInfo, MT2063_REG_FIFF_CTRL, val);
2325 }
2326 }
2327
2328 /* DNC1GC & DNC2GC */
2329 status |= MT2063_GetParam(pInfo, MT2063_DNC_OUTPUT_ENABLE, &longval);
2330 status |= MT2063_SetParam(pInfo, MT2063_DNC_OUTPUT_ENABLE, longval);
2331
2332 /* acLNAmax */
2333 if (MT2063_NO_ERROR(status)) {
2334 status |=
2335 MT2063_SetParam(pInfo, MT2063_ACLNA_MAX, ACLNAMAX[Mode]);
2336 }
2337
2338 /* LNATGT */
2339 if (MT2063_NO_ERROR(status)) {
2340 status |= MT2063_SetParam(pInfo, MT2063_LNA_TGT, LNATGT[Mode]);
2341 }
2342
2343 /* ACRF */
2344 if (MT2063_NO_ERROR(status)) {
2345 status |=
2346 MT2063_SetParam(pInfo, MT2063_ACRF_MAX, ACRFMAX[Mode]);
2347 }
2348
2349 /* PD1TGT */
2350 if (MT2063_NO_ERROR(status)) {
2351 status |= MT2063_SetParam(pInfo, MT2063_PD1_TGT, PD1TGT[Mode]);
2352 }
2353
2354 /* FIFATN */
2355 if (MT2063_NO_ERROR(status)) {
2356 status |=
2357 MT2063_SetParam(pInfo, MT2063_ACFIF_MAX, ACFIFMAX[Mode]);
2358 }
2359
2360 /* PD2TGT */
2361 if (MT2063_NO_ERROR(status)) {
2362 status |= MT2063_SetParam(pInfo, MT2063_PD2_TGT, PD2TGT[Mode]);
2363 }
2364
2365 /* Ignore ATN Overload */
2366 if (MT2063_NO_ERROR(status)) {
2367 val =
2368 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002369 reg[MT2063_REG_LNA_TGT] & (u8) ~ 0x80) | (RFOVDIS[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002370 ? 0x80 :
2371 0x00);
2372 if (pInfo->reg[MT2063_REG_LNA_TGT] != val) {
2373 status |= MT2063_SetReg(pInfo, MT2063_REG_LNA_TGT, val);
2374 }
2375 }
2376
2377 /* Ignore FIF Overload */
2378 if (MT2063_NO_ERROR(status)) {
2379 val =
2380 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002381 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x80) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002382 (FIFOVDIS[Mode] ? 0x80 : 0x00);
2383 if (pInfo->reg[MT2063_REG_PD1_TGT] != val) {
2384 status |= MT2063_SetReg(pInfo, MT2063_REG_PD1_TGT, val);
2385 }
2386 }
2387
2388 if (MT2063_NO_ERROR(status))
2389 pInfo->rcvr_mode = Mode;
2390
2391 return (status);
2392}
2393
2394/******************************************************************************
2395**
2396** Name: MT2063_ReInit
2397**
2398** Description: Initialize the tuner's register values.
2399**
2400** Parameters: h - Tuner handle (returned by MT2063_Open)
2401**
2402** Returns: status:
2403** MT_OK - No errors
2404** MT_TUNER_ID_ERR - Tuner Part/Rev code mismatch
2405** MT_INV_HANDLE - Invalid tuner handle
2406** MT_COMM_ERR - Serial bus communications error
2407**
2408** Dependencies: MT_ReadSub - Read byte(s) of data from the two-wire bus
2409** MT_WriteSub - Write byte(s) of data to the two-wire bus
2410**
2411** Revision History:
2412**
2413** SCR Date Author Description
2414** -------------------------------------------------------------------------
2415** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2416** 148 09-04-2007 RSK Ver 1.02: Corrected logic of Reg 3B Reference
2417** 153 09-07-2007 RSK Ver 1.03: Lock Time improvements
2418** N/A 10-31-2007 PINZ Ver 1.08: Changed values suitable to rcvr-mode 0
2419** N/A 11-12-2007 PINZ Ver 1.09: Changed values suitable to rcvr-mode 0
2420** N/A 01-03-2007 PINZ Ver 1.10: Added AFCsd = 1 into defaults
2421** N/A 01-04-2007 PINZ Ver 1.10: Changed CAP1sel default
2422** 01-14-2008 PINZ Ver 1.11: Updated gain settings
2423** 03-18-2008 PINZ Ver 1.13: Added Support for B3
2424** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
2425** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
2426**
2427******************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002428static u32 MT2063_ReInit(void *h)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002429{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002430 u8 all_resets = 0xF0; /* reset/load bits */
2431 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002432 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -03002433 u8 *def = NULL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002434
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002435 u8 MT2063B0_defaults[] = { /* Reg, Value */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002436 0x19, 0x05,
2437 0x1B, 0x1D,
2438 0x1C, 0x1F,
2439 0x1D, 0x0F,
2440 0x1E, 0x3F,
2441 0x1F, 0x0F,
2442 0x20, 0x3F,
2443 0x22, 0x21,
2444 0x23, 0x3F,
2445 0x24, 0x20,
2446 0x25, 0x3F,
2447 0x27, 0xEE,
2448 0x2C, 0x27, /* bit at 0x20 is cleared below */
2449 0x30, 0x03,
2450 0x2C, 0x07, /* bit at 0x20 is cleared here */
2451 0x2D, 0x87,
2452 0x2E, 0xAA,
2453 0x28, 0xE1, /* Set the FIFCrst bit here */
2454 0x28, 0xE0, /* Clear the FIFCrst bit here */
2455 0x00
2456 };
2457
2458 /* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002459 u8 MT2063B1_defaults[] = { /* Reg, Value */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002460 0x05, 0xF0,
2461 0x11, 0x10, /* New Enable AFCsd */
2462 0x19, 0x05,
2463 0x1A, 0x6C,
2464 0x1B, 0x24,
2465 0x1C, 0x28,
2466 0x1D, 0x8F,
2467 0x1E, 0x14,
2468 0x1F, 0x8F,
2469 0x20, 0x57,
2470 0x22, 0x21, /* New - ver 1.03 */
2471 0x23, 0x3C, /* New - ver 1.10 */
2472 0x24, 0x20, /* New - ver 1.03 */
2473 0x2C, 0x24, /* bit at 0x20 is cleared below */
2474 0x2D, 0x87, /* FIFFQ=0 */
2475 0x2F, 0xF3,
2476 0x30, 0x0C, /* New - ver 1.11 */
2477 0x31, 0x1B, /* New - ver 1.11 */
2478 0x2C, 0x04, /* bit at 0x20 is cleared here */
2479 0x28, 0xE1, /* Set the FIFCrst bit here */
2480 0x28, 0xE0, /* Clear the FIFCrst bit here */
2481 0x00
2482 };
2483
2484 /* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002485 u8 MT2063B3_defaults[] = { /* Reg, Value */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002486 0x05, 0xF0,
2487 0x19, 0x3D,
2488 0x2C, 0x24, /* bit at 0x20 is cleared below */
2489 0x2C, 0x04, /* bit at 0x20 is cleared here */
2490 0x28, 0xE1, /* Set the FIFCrst bit here */
2491 0x28, 0xE0, /* Clear the FIFCrst bit here */
2492 0x00
2493 };
2494
2495 /* Verify that the handle passed points to a valid tuner */
2496 if (MT2063_IsValidHandle(pInfo) == 0)
2497 status |= MT2063_INV_HANDLE;
2498
2499 /* Read the Part/Rev code from the tuner */
2500 if (MT2063_NO_ERROR(status)) {
2501 status |=
2502 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
2503 MT2063_REG_PART_REV, pInfo->reg, 1);
2504 }
2505
2506 if (MT2063_NO_ERROR(status) /* Check the part/rev code */
2507 &&((pInfo->reg[MT2063_REG_PART_REV] != MT2063_B0) /* MT2063 B0 */
2508 &&(pInfo->reg[MT2063_REG_PART_REV] != MT2063_B1) /* MT2063 B1 */
2509 &&(pInfo->reg[MT2063_REG_PART_REV] != MT2063_B3))) /* MT2063 B3 */
2510 status |= MT2063_TUNER_ID_ERR; /* Wrong tuner Part/Rev code */
2511
2512 /* Read the Part/Rev code (2nd byte) from the tuner */
2513 if (MT2063_NO_ERROR(status))
2514 status |=
2515 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
2516 MT2063_REG_RSVD_3B,
2517 &pInfo->reg[MT2063_REG_RSVD_3B], 1);
2518
2519 if (MT2063_NO_ERROR(status) /* Check the 2nd part/rev code */
2520 &&((pInfo->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) /* b7 != 0 ==> NOT MT2063 */
2521 status |= MT2063_TUNER_ID_ERR; /* Wrong tuner Part/Rev code */
2522
2523 /* Reset the tuner */
2524 if (MT2063_NO_ERROR(status))
2525 status |= MT2063_WriteSub(pInfo->hUserData,
2526 pInfo->address,
2527 MT2063_REG_LO2CQ_3, &all_resets, 1);
2528
2529 /* change all of the default values that vary from the HW reset values */
2530 /* def = (pInfo->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */
2531 switch (pInfo->reg[MT2063_REG_PART_REV]) {
2532 case MT2063_B3:
2533 def = MT2063B3_defaults;
2534 break;
2535
2536 case MT2063_B1:
2537 def = MT2063B1_defaults;
2538 break;
2539
2540 case MT2063_B0:
2541 def = MT2063B0_defaults;
2542 break;
2543
2544 default:
2545 status |= MT2063_TUNER_ID_ERR;
2546 break;
2547 }
2548
2549 while (MT2063_NO_ERROR(status) && *def) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002550 u8 reg = *def++;
2551 u8 val = *def++;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002552 status |=
2553 MT2063_WriteSub(pInfo->hUserData, pInfo->address, reg, &val,
2554 1);
2555 }
2556
2557 /* Wait for FIFF location to complete. */
2558 if (MT2063_NO_ERROR(status)) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002559 u32 FCRUN = 1;
2560 s32 maxReads = 10;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002561 while (MT2063_NO_ERROR(status) && (FCRUN != 0)
2562 && (maxReads-- > 0)) {
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002563 msleep(2);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002564 status |= MT2063_ReadSub(pInfo->hUserData,
2565 pInfo->address,
2566 MT2063_REG_XO_STATUS,
2567 &pInfo->
2568 reg[MT2063_REG_XO_STATUS], 1);
2569 FCRUN = (pInfo->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6;
2570 }
2571
2572 if (FCRUN != 0)
2573 status |= MT2063_TUNER_INIT_ERR | MT2063_TUNER_TIMEOUT;
2574
2575 if (MT2063_NO_ERROR(status)) /* Re-read FIFFC value */
2576 status |=
2577 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
2578 MT2063_REG_FIFFC,
2579 &pInfo->reg[MT2063_REG_FIFFC], 1);
2580 }
2581
2582 /* Read back all the registers from the tuner */
2583 if (MT2063_NO_ERROR(status))
2584 status |= MT2063_ReadSub(pInfo->hUserData,
2585 pInfo->address,
2586 MT2063_REG_PART_REV,
2587 pInfo->reg, MT2063_REG_END_REGS);
2588
2589 if (MT2063_NO_ERROR(status)) {
2590 /* Initialize the tuner state. */
2591 pInfo->version = MT2063_VERSION;
2592 pInfo->tuner_id = pInfo->reg[MT2063_REG_PART_REV];
2593 pInfo->AS_Data.f_ref = MT2063_REF_FREQ;
2594 pInfo->AS_Data.f_if1_Center =
2595 (pInfo->AS_Data.f_ref / 8) *
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002596 ((u32) pInfo->reg[MT2063_REG_FIFFC] + 640);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002597 pInfo->AS_Data.f_if1_bw = MT2063_IF1_BW;
2598 pInfo->AS_Data.f_out = 43750000UL;
2599 pInfo->AS_Data.f_out_bw = 6750000UL;
2600 pInfo->AS_Data.f_zif_bw = MT2063_ZIF_BW;
2601 pInfo->AS_Data.f_LO1_Step = pInfo->AS_Data.f_ref / 64;
2602 pInfo->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE;
2603 pInfo->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1;
2604 pInfo->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2;
2605 pInfo->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP;
2606 pInfo->AS_Data.f_if1_Request = pInfo->AS_Data.f_if1_Center;
2607 pInfo->AS_Data.f_LO1 = 2181000000UL;
2608 pInfo->AS_Data.f_LO2 = 1486249786UL;
2609 pInfo->f_IF1_actual = pInfo->AS_Data.f_if1_Center;
2610 pInfo->AS_Data.f_in =
2611 pInfo->AS_Data.f_LO1 - pInfo->f_IF1_actual;
2612 pInfo->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID;
2613 pInfo->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID;
2614 pInfo->num_regs = MT2063_REG_END_REGS;
2615 pInfo->AS_Data.avoidDECT = MT2063_AVOID_BOTH;
2616 pInfo->ctfilt_sw = 0;
2617 }
2618
2619 if (MT2063_NO_ERROR(status)) {
2620 pInfo->CTFiltMax[0] = 69230000;
2621 pInfo->CTFiltMax[1] = 105770000;
2622 pInfo->CTFiltMax[2] = 140350000;
2623 pInfo->CTFiltMax[3] = 177110000;
2624 pInfo->CTFiltMax[4] = 212860000;
2625 pInfo->CTFiltMax[5] = 241130000;
2626 pInfo->CTFiltMax[6] = 274370000;
2627 pInfo->CTFiltMax[7] = 309820000;
2628 pInfo->CTFiltMax[8] = 342450000;
2629 pInfo->CTFiltMax[9] = 378870000;
2630 pInfo->CTFiltMax[10] = 416210000;
2631 pInfo->CTFiltMax[11] = 456500000;
2632 pInfo->CTFiltMax[12] = 495790000;
2633 pInfo->CTFiltMax[13] = 534530000;
2634 pInfo->CTFiltMax[14] = 572610000;
2635 pInfo->CTFiltMax[15] = 598970000;
2636 pInfo->CTFiltMax[16] = 635910000;
2637 pInfo->CTFiltMax[17] = 672130000;
2638 pInfo->CTFiltMax[18] = 714840000;
2639 pInfo->CTFiltMax[19] = 739660000;
2640 pInfo->CTFiltMax[20] = 770410000;
2641 pInfo->CTFiltMax[21] = 814660000;
2642 pInfo->CTFiltMax[22] = 846950000;
2643 pInfo->CTFiltMax[23] = 867820000;
2644 pInfo->CTFiltMax[24] = 915980000;
2645 pInfo->CTFiltMax[25] = 947450000;
2646 pInfo->CTFiltMax[26] = 983110000;
2647 pInfo->CTFiltMax[27] = 1021630000;
2648 pInfo->CTFiltMax[28] = 1061870000;
2649 pInfo->CTFiltMax[29] = 1098330000;
2650 pInfo->CTFiltMax[30] = 1138990000;
2651 }
2652
2653 /*
2654 ** Fetch the FCU osc value and use it and the fRef value to
2655 ** scale all of the Band Max values
2656 */
2657 if (MT2063_NO_ERROR(status)) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002658 u32 fcu_osc;
2659 u32 i;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002660
2661 pInfo->reg[MT2063_REG_CTUNE_CTRL] = 0x0A;
2662 status |=
2663 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
2664 MT2063_REG_CTUNE_CTRL,
2665 &pInfo->reg[MT2063_REG_CTUNE_CTRL], 1);
2666 /* Read the ClearTune filter calibration value */
2667 status |=
2668 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
2669 MT2063_REG_FIFFC,
2670 &pInfo->reg[MT2063_REG_FIFFC], 1);
2671 fcu_osc = pInfo->reg[MT2063_REG_FIFFC];
2672
2673 pInfo->reg[MT2063_REG_CTUNE_CTRL] = 0x00;
2674 status |=
2675 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
2676 MT2063_REG_CTUNE_CTRL,
2677 &pInfo->reg[MT2063_REG_CTUNE_CTRL], 1);
2678
2679 /* Adjust each of the values in the ClearTune filter cross-over table */
2680 for (i = 0; i < 31; i++) {
2681 pInfo->CTFiltMax[i] =
2682 (pInfo->CTFiltMax[i] / 768) * (fcu_osc + 640);
2683 }
2684 }
2685
2686 return (status);
2687}
2688
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002689/****************************************************************************
2690**
2691** Name: MT2063_SetParam
2692**
2693** Description: Sets a tuning algorithm parameter.
2694**
2695** This function provides access to the internals of the
2696** tuning algorithm. You can override many of the tuning
2697** algorithm defaults using this function.
2698**
2699** Parameters: h - Tuner handle (returned by MT2063_Open)
2700** param - Tuning algorithm parameter
2701** (see enum MT2063_Param)
2702** nValue - value to be set
2703**
2704** param Description
2705** ---------------------- --------------------------------
2706** MT2063_SRO_FREQ crystal frequency
2707** MT2063_STEPSIZE minimum tuning step size
2708** MT2063_LO1_FREQ LO1 frequency
2709** MT2063_LO1_STEPSIZE LO1 minimum step size
2710** MT2063_LO1_FRACN_AVOID LO1 FracN keep-out region
2711** MT2063_IF1_REQUEST Requested 1st IF
2712** MT2063_ZIF_BW zero-IF bandwidth
2713** MT2063_LO2_FREQ LO2 frequency
2714** MT2063_LO2_STEPSIZE LO2 minimum step size
2715** MT2063_LO2_FRACN_AVOID LO2 FracN keep-out region
2716** MT2063_OUTPUT_FREQ output center frequency
2717** MT2063_OUTPUT_BW output bandwidth
2718** MT2063_LO_SEPARATION min inter-tuner LO separation
2719** MT2063_MAX_HARM1 max # of intra-tuner harmonics
2720** MT2063_MAX_HARM2 max # of inter-tuner harmonics
2721** MT2063_RCVR_MODE Predefined modes
2722** MT2063_LNA_RIN Set LNA Rin (*)
2723** MT2063_LNA_TGT Set target power level at LNA (*)
2724** MT2063_PD1_TGT Set target power level at PD1 (*)
2725** MT2063_PD2_TGT Set target power level at PD2 (*)
2726** MT2063_ACLNA_MAX LNA attenuator limit (*)
2727** MT2063_ACRF_MAX RF attenuator limit (*)
2728** MT2063_ACFIF_MAX FIF attenuator limit (*)
2729** MT2063_DNC_OUTPUT_ENABLE DNC output selection
2730** MT2063_VGAGC VGA gain code
2731** MT2063_VGAOI VGA output current
2732** MT2063_TAGC TAGC setting
2733** MT2063_AMPGC AMP gain code
2734** MT2063_AVOID_DECT Avoid DECT Frequencies
2735** MT2063_CTFILT_SW Cleartune filter selection
2736**
2737** (*) This parameter is set by MT2063_RCVR_MODE, do not call
2738** additionally.
2739**
2740** Usage: status |= MT2063_SetParam(hMT2063,
2741** MT2063_STEPSIZE,
2742** 50000);
2743**
2744** Returns: status:
2745** MT_OK - No errors
2746** MT_INV_HANDLE - Invalid tuner handle
2747** MT_ARG_NULL - Null pointer argument passed
2748** MT_ARG_RANGE - Invalid parameter requested
2749** or set value out of range
2750** or non-writable parameter
2751**
2752** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
2753**
2754** See Also: MT2063_GetParam, MT2063_Open
2755**
2756** Revision History:
2757**
2758** SCR Date Author Description
2759** -------------------------------------------------------------------------
2760** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2761** 154 09-13-2007 RSK Ver 1.05: Get/SetParam changes for LOx_FREQ
2762** 10-31-2007 PINZ Ver 1.08: Get/SetParam add VGAGC, VGAOI, AMPGC, TAGC
2763** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
2764** Split SetParam up to ACLNA / ACLNA_MAX
2765** removed ACLNA_INRC/DECR (+RF & FIF)
2766** removed GCUAUTO / BYPATNDN/UP
2767** 175 I 06-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
2768** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
2769** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
2770**
2771****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002772static u32 MT2063_SetParam(void *h, enum MT2063_Param param, u32 nValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002773{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002774 u32 status = MT2063_OK; /* Status to be returned */
2775 u8 val = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002776 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
2777
2778 /* Verify that the handle passed points to a valid tuner */
2779 if (MT2063_IsValidHandle(pInfo) == 0)
2780 status |= MT2063_INV_HANDLE;
2781
2782 if (MT2063_NO_ERROR(status)) {
2783 switch (param) {
2784 /* crystal frequency */
2785 case MT2063_SRO_FREQ:
2786 pInfo->AS_Data.f_ref = nValue;
2787 pInfo->AS_Data.f_LO1_FracN_Avoid = 0;
2788 pInfo->AS_Data.f_LO2_FracN_Avoid = nValue / 80 - 1;
2789 pInfo->AS_Data.f_LO1_Step = nValue / 64;
2790 pInfo->AS_Data.f_if1_Center =
2791 (pInfo->AS_Data.f_ref / 8) *
2792 (pInfo->reg[MT2063_REG_FIFFC] + 640);
2793 break;
2794
2795 /* minimum tuning step size */
2796 case MT2063_STEPSIZE:
2797 pInfo->AS_Data.f_LO2_Step = nValue;
2798 break;
2799
2800 /* LO1 frequency */
2801 case MT2063_LO1_FREQ:
2802 {
2803 /* Note: LO1 and LO2 are BOTH written at toggle of LDLOos */
2804 /* Capture the Divider and Numerator portions of other LO */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002805 u8 tempLO2CQ[3];
2806 u8 tempLO2C[3];
2807 u8 tmpOneShot;
2808 u32 Div, FracN;
2809 u8 restore = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002810
2811 /* Buffer the queue for restoration later and get actual LO2 values. */
2812 status |=
2813 MT2063_ReadSub(pInfo->hUserData,
2814 pInfo->address,
2815 MT2063_REG_LO2CQ_1,
2816 &(tempLO2CQ[0]), 3);
2817 status |=
2818 MT2063_ReadSub(pInfo->hUserData,
2819 pInfo->address,
2820 MT2063_REG_LO2C_1,
2821 &(tempLO2C[0]), 3);
2822
2823 /* clear the one-shot bits */
2824 tempLO2CQ[2] = tempLO2CQ[2] & 0x0F;
2825 tempLO2C[2] = tempLO2C[2] & 0x0F;
2826
2827 /* only write the queue values if they are different from the actual. */
2828 if ((tempLO2CQ[0] != tempLO2C[0]) ||
2829 (tempLO2CQ[1] != tempLO2C[1]) ||
2830 (tempLO2CQ[2] != tempLO2C[2])) {
2831 /* put actual LO2 value into queue (with 0 in one-shot bits) */
2832 status |=
2833 MT2063_WriteSub(pInfo->hUserData,
2834 pInfo->address,
2835 MT2063_REG_LO2CQ_1,
2836 &(tempLO2C[0]), 3);
2837
2838 if (status == MT2063_OK) {
2839 /* cache the bytes just written. */
2840 pInfo->reg[MT2063_REG_LO2CQ_1] =
2841 tempLO2C[0];
2842 pInfo->reg[MT2063_REG_LO2CQ_2] =
2843 tempLO2C[1];
2844 pInfo->reg[MT2063_REG_LO2CQ_3] =
2845 tempLO2C[2];
2846 }
2847 restore = 1;
2848 }
2849
2850 /* Calculate the Divider and Numberator components of LO1 */
2851 status =
2852 MT2063_CalcLO1Mult(&Div, &FracN, nValue,
2853 pInfo->AS_Data.f_ref /
2854 64,
2855 pInfo->AS_Data.f_ref);
2856 pInfo->reg[MT2063_REG_LO1CQ_1] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002857 (u8) (Div & 0x00FF);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002858 pInfo->reg[MT2063_REG_LO1CQ_2] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002859 (u8) (FracN);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002860 status |=
2861 MT2063_WriteSub(pInfo->hUserData,
2862 pInfo->address,
2863 MT2063_REG_LO1CQ_1,
2864 &pInfo->
2865 reg[MT2063_REG_LO1CQ_1], 2);
2866
2867 /* set the one-shot bit to load the pair of LO values */
2868 tmpOneShot = tempLO2CQ[2] | 0xE0;
2869 status |=
2870 MT2063_WriteSub(pInfo->hUserData,
2871 pInfo->address,
2872 MT2063_REG_LO2CQ_3,
2873 &tmpOneShot, 1);
2874
2875 /* only restore the queue values if they were different from the actual. */
2876 if (restore) {
2877 /* put actual LO2 value into queue (0 in one-shot bits) */
2878 status |=
2879 MT2063_WriteSub(pInfo->hUserData,
2880 pInfo->address,
2881 MT2063_REG_LO2CQ_1,
2882 &(tempLO2CQ[0]), 3);
2883
2884 /* cache the bytes just written. */
2885 pInfo->reg[MT2063_REG_LO2CQ_1] =
2886 tempLO2CQ[0];
2887 pInfo->reg[MT2063_REG_LO2CQ_2] =
2888 tempLO2CQ[1];
2889 pInfo->reg[MT2063_REG_LO2CQ_3] =
2890 tempLO2CQ[2];
2891 }
2892
2893 MT2063_GetParam(pInfo->hUserData,
2894 MT2063_LO1_FREQ,
2895 &pInfo->AS_Data.f_LO1);
2896 }
2897 break;
2898
2899 /* LO1 minimum step size */
2900 case MT2063_LO1_STEPSIZE:
2901 pInfo->AS_Data.f_LO1_Step = nValue;
2902 break;
2903
2904 /* LO1 FracN keep-out region */
2905 case MT2063_LO1_FRACN_AVOID_PARAM:
2906 pInfo->AS_Data.f_LO1_FracN_Avoid = nValue;
2907 break;
2908
2909 /* Requested 1st IF */
2910 case MT2063_IF1_REQUEST:
2911 pInfo->AS_Data.f_if1_Request = nValue;
2912 break;
2913
2914 /* zero-IF bandwidth */
2915 case MT2063_ZIF_BW:
2916 pInfo->AS_Data.f_zif_bw = nValue;
2917 break;
2918
2919 /* LO2 frequency */
2920 case MT2063_LO2_FREQ:
2921 {
2922 /* Note: LO1 and LO2 are BOTH written at toggle of LDLOos */
2923 /* Capture the Divider and Numerator portions of other LO */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002924 u8 tempLO1CQ[2];
2925 u8 tempLO1C[2];
2926 u32 Div2;
2927 u32 FracN2;
2928 u8 tmpOneShot;
2929 u8 restore = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002930
2931 /* Buffer the queue for restoration later and get actual LO2 values. */
2932 status |=
2933 MT2063_ReadSub(pInfo->hUserData,
2934 pInfo->address,
2935 MT2063_REG_LO1CQ_1,
2936 &(tempLO1CQ[0]), 2);
2937 status |=
2938 MT2063_ReadSub(pInfo->hUserData,
2939 pInfo->address,
2940 MT2063_REG_LO1C_1,
2941 &(tempLO1C[0]), 2);
2942
2943 /* only write the queue values if they are different from the actual. */
2944 if ((tempLO1CQ[0] != tempLO1C[0])
2945 || (tempLO1CQ[1] != tempLO1C[1])) {
2946 /* put actual LO1 value into queue */
2947 status |=
2948 MT2063_WriteSub(pInfo->hUserData,
2949 pInfo->address,
2950 MT2063_REG_LO1CQ_1,
2951 &(tempLO1C[0]), 2);
2952
2953 /* cache the bytes just written. */
2954 pInfo->reg[MT2063_REG_LO1CQ_1] =
2955 tempLO1C[0];
2956 pInfo->reg[MT2063_REG_LO1CQ_2] =
2957 tempLO1C[1];
2958 restore = 1;
2959 }
2960
2961 /* Calculate the Divider and Numberator components of LO2 */
2962 status =
2963 MT2063_CalcLO2Mult(&Div2, &FracN2, nValue,
2964 pInfo->AS_Data.f_ref /
2965 8191,
2966 pInfo->AS_Data.f_ref);
2967 pInfo->reg[MT2063_REG_LO2CQ_1] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002968 (u8) ((Div2 << 1) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002969 ((FracN2 >> 12) & 0x01)) & 0xFF;
2970 pInfo->reg[MT2063_REG_LO2CQ_2] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002971 (u8) ((FracN2 >> 4) & 0xFF);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002972 pInfo->reg[MT2063_REG_LO2CQ_3] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002973 (u8) ((FracN2 & 0x0F));
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002974 status |=
2975 MT2063_WriteSub(pInfo->hUserData,
2976 pInfo->address,
2977 MT2063_REG_LO1CQ_1,
2978 &pInfo->
2979 reg[MT2063_REG_LO1CQ_1], 3);
2980
2981 /* set the one-shot bit to load the LO values */
2982 tmpOneShot =
2983 pInfo->reg[MT2063_REG_LO2CQ_3] | 0xE0;
2984 status |=
2985 MT2063_WriteSub(pInfo->hUserData,
2986 pInfo->address,
2987 MT2063_REG_LO2CQ_3,
2988 &tmpOneShot, 1);
2989
2990 /* only restore LO1 queue value if they were different from the actual. */
2991 if (restore) {
2992 /* put previous LO1 queue value back into queue */
2993 status |=
2994 MT2063_WriteSub(pInfo->hUserData,
2995 pInfo->address,
2996 MT2063_REG_LO1CQ_1,
2997 &(tempLO1CQ[0]), 2);
2998
2999 /* cache the bytes just written. */
3000 pInfo->reg[MT2063_REG_LO1CQ_1] =
3001 tempLO1CQ[0];
3002 pInfo->reg[MT2063_REG_LO1CQ_2] =
3003 tempLO1CQ[1];
3004 }
3005
3006 MT2063_GetParam(pInfo->hUserData,
3007 MT2063_LO2_FREQ,
3008 &pInfo->AS_Data.f_LO2);
3009 }
3010 break;
3011
3012 /* LO2 minimum step size */
3013 case MT2063_LO2_STEPSIZE:
3014 pInfo->AS_Data.f_LO2_Step = nValue;
3015 break;
3016
3017 /* LO2 FracN keep-out region */
3018 case MT2063_LO2_FRACN_AVOID:
3019 pInfo->AS_Data.f_LO2_FracN_Avoid = nValue;
3020 break;
3021
3022 /* output center frequency */
3023 case MT2063_OUTPUT_FREQ:
3024 pInfo->AS_Data.f_out = nValue;
3025 break;
3026
3027 /* output bandwidth */
3028 case MT2063_OUTPUT_BW:
3029 pInfo->AS_Data.f_out_bw = nValue + 750000;
3030 break;
3031
3032 /* min inter-tuner LO separation */
3033 case MT2063_LO_SEPARATION:
3034 pInfo->AS_Data.f_min_LO_Separation = nValue;
3035 break;
3036
3037 /* max # of intra-tuner harmonics */
3038 case MT2063_MAX_HARM1:
3039 pInfo->AS_Data.maxH1 = nValue;
3040 break;
3041
3042 /* max # of inter-tuner harmonics */
3043 case MT2063_MAX_HARM2:
3044 pInfo->AS_Data.maxH2 = nValue;
3045 break;
3046
3047 case MT2063_RCVR_MODE:
3048 status |=
3049 MT2063_SetReceiverMode(pInfo,
3050 (enum MT2063_RCVR_MODES)
3051 nValue);
3052 break;
3053
3054 /* Set LNA Rin -- nValue is desired value */
3055 case MT2063_LNA_RIN:
3056 val =
3057 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003058 reg[MT2063_REG_CTRL_2C] & (u8) ~ 0x03) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003059 (nValue & 0x03);
3060 if (pInfo->reg[MT2063_REG_CTRL_2C] != val) {
3061 status |=
3062 MT2063_SetReg(pInfo, MT2063_REG_CTRL_2C,
3063 val);
3064 }
3065 break;
3066
3067 /* Set target power level at LNA -- nValue is desired value */
3068 case MT2063_LNA_TGT:
3069 val =
3070 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003071 reg[MT2063_REG_LNA_TGT] & (u8) ~ 0x3F) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003072 (nValue & 0x3F);
3073 if (pInfo->reg[MT2063_REG_LNA_TGT] != val) {
3074 status |=
3075 MT2063_SetReg(pInfo, MT2063_REG_LNA_TGT,
3076 val);
3077 }
3078 break;
3079
3080 /* Set target power level at PD1 -- nValue is desired value */
3081 case MT2063_PD1_TGT:
3082 val =
3083 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003084 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x3F) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003085 (nValue & 0x3F);
3086 if (pInfo->reg[MT2063_REG_PD1_TGT] != val) {
3087 status |=
3088 MT2063_SetReg(pInfo, MT2063_REG_PD1_TGT,
3089 val);
3090 }
3091 break;
3092
3093 /* Set target power level at PD2 -- nValue is desired value */
3094 case MT2063_PD2_TGT:
3095 val =
3096 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003097 reg[MT2063_REG_PD2_TGT] & (u8) ~ 0x3F) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003098 (nValue & 0x3F);
3099 if (pInfo->reg[MT2063_REG_PD2_TGT] != val) {
3100 status |=
3101 MT2063_SetReg(pInfo, MT2063_REG_PD2_TGT,
3102 val);
3103 }
3104 break;
3105
3106 /* Set LNA atten limit -- nValue is desired value */
3107 case MT2063_ACLNA_MAX:
3108 val =
3109 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003110 reg[MT2063_REG_LNA_OV] & (u8) ~ 0x1F) | (nValue
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003111 &
3112 0x1F);
3113 if (pInfo->reg[MT2063_REG_LNA_OV] != val) {
3114 status |=
3115 MT2063_SetReg(pInfo, MT2063_REG_LNA_OV,
3116 val);
3117 }
3118 break;
3119
3120 /* Set RF atten limit -- nValue is desired value */
3121 case MT2063_ACRF_MAX:
3122 val =
3123 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003124 reg[MT2063_REG_RF_OV] & (u8) ~ 0x1F) | (nValue
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003125 &
3126 0x1F);
3127 if (pInfo->reg[MT2063_REG_RF_OV] != val) {
3128 status |=
3129 MT2063_SetReg(pInfo, MT2063_REG_RF_OV, val);
3130 }
3131 break;
3132
3133 /* Set FIF atten limit -- nValue is desired value, max. 5 if no B3 */
3134 case MT2063_ACFIF_MAX:
3135 if (pInfo->reg[MT2063_REG_PART_REV] != MT2063_B3
3136 && nValue > 5)
3137 nValue = 5;
3138 val =
3139 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003140 reg[MT2063_REG_FIF_OV] & (u8) ~ 0x1F) | (nValue
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003141 &
3142 0x1F);
3143 if (pInfo->reg[MT2063_REG_FIF_OV] != val) {
3144 status |=
3145 MT2063_SetReg(pInfo, MT2063_REG_FIF_OV,
3146 val);
3147 }
3148 break;
3149
3150 case MT2063_DNC_OUTPUT_ENABLE:
3151 /* selects, which DNC output is used */
3152 switch ((enum MT2063_DNC_Output_Enable)nValue) {
3153 case MT2063_DNC_NONE:
3154 {
3155 val = (pInfo->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
3156 if (pInfo->reg[MT2063_REG_DNC_GAIN] !=
3157 val)
3158 status |=
3159 MT2063_SetReg(h,
3160 MT2063_REG_DNC_GAIN,
3161 val);
3162
3163 val = (pInfo->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
3164 if (pInfo->reg[MT2063_REG_VGA_GAIN] !=
3165 val)
3166 status |=
3167 MT2063_SetReg(h,
3168 MT2063_REG_VGA_GAIN,
3169 val);
3170
3171 val = (pInfo->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
3172 if (pInfo->reg[MT2063_REG_RSVD_20] !=
3173 val)
3174 status |=
3175 MT2063_SetReg(h,
3176 MT2063_REG_RSVD_20,
3177 val);
3178
3179 break;
3180 }
3181 case MT2063_DNC_1:
3182 {
3183 val = (pInfo->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[pInfo->rcvr_mode] & 0x03); /* Set DNC1GC=x */
3184 if (pInfo->reg[MT2063_REG_DNC_GAIN] !=
3185 val)
3186 status |=
3187 MT2063_SetReg(h,
3188 MT2063_REG_DNC_GAIN,
3189 val);
3190
3191 val = (pInfo->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
3192 if (pInfo->reg[MT2063_REG_VGA_GAIN] !=
3193 val)
3194 status |=
3195 MT2063_SetReg(h,
3196 MT2063_REG_VGA_GAIN,
3197 val);
3198
3199 val = (pInfo->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
3200 if (pInfo->reg[MT2063_REG_RSVD_20] !=
3201 val)
3202 status |=
3203 MT2063_SetReg(h,
3204 MT2063_REG_RSVD_20,
3205 val);
3206
3207 break;
3208 }
3209 case MT2063_DNC_2:
3210 {
3211 val = (pInfo->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
3212 if (pInfo->reg[MT2063_REG_DNC_GAIN] !=
3213 val)
3214 status |=
3215 MT2063_SetReg(h,
3216 MT2063_REG_DNC_GAIN,
3217 val);
3218
3219 val = (pInfo->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[pInfo->rcvr_mode] & 0x03); /* Set DNC2GC=x */
3220 if (pInfo->reg[MT2063_REG_VGA_GAIN] !=
3221 val)
3222 status |=
3223 MT2063_SetReg(h,
3224 MT2063_REG_VGA_GAIN,
3225 val);
3226
3227 val = (pInfo->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
3228 if (pInfo->reg[MT2063_REG_RSVD_20] !=
3229 val)
3230 status |=
3231 MT2063_SetReg(h,
3232 MT2063_REG_RSVD_20,
3233 val);
3234
3235 break;
3236 }
3237 case MT2063_DNC_BOTH:
3238 {
3239 val = (pInfo->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[pInfo->rcvr_mode] & 0x03); /* Set DNC1GC=x */
3240 if (pInfo->reg[MT2063_REG_DNC_GAIN] !=
3241 val)
3242 status |=
3243 MT2063_SetReg(h,
3244 MT2063_REG_DNC_GAIN,
3245 val);
3246
3247 val = (pInfo->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[pInfo->rcvr_mode] & 0x03); /* Set DNC2GC=x */
3248 if (pInfo->reg[MT2063_REG_VGA_GAIN] !=
3249 val)
3250 status |=
3251 MT2063_SetReg(h,
3252 MT2063_REG_VGA_GAIN,
3253 val);
3254
3255 val = (pInfo->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
3256 if (pInfo->reg[MT2063_REG_RSVD_20] !=
3257 val)
3258 status |=
3259 MT2063_SetReg(h,
3260 MT2063_REG_RSVD_20,
3261 val);
3262
3263 break;
3264 }
3265 default:
3266 break;
3267 }
3268 break;
3269
3270 case MT2063_VGAGC:
3271 /* Set VGA gain code */
3272 val =
3273 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003274 reg[MT2063_REG_VGA_GAIN] & (u8) ~ 0x0C) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003275 ((nValue & 0x03) << 2);
3276 if (pInfo->reg[MT2063_REG_VGA_GAIN] != val) {
3277 status |=
3278 MT2063_SetReg(pInfo, MT2063_REG_VGA_GAIN,
3279 val);
3280 }
3281 break;
3282
3283 case MT2063_VGAOI:
3284 /* Set VGA bias current */
3285 val =
3286 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003287 reg[MT2063_REG_RSVD_31] & (u8) ~ 0x07) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003288 (nValue & 0x07);
3289 if (pInfo->reg[MT2063_REG_RSVD_31] != val) {
3290 status |=
3291 MT2063_SetReg(pInfo, MT2063_REG_RSVD_31,
3292 val);
3293 }
3294 break;
3295
3296 case MT2063_TAGC:
3297 /* Set TAGC */
3298 val =
3299 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003300 reg[MT2063_REG_RSVD_1E] & (u8) ~ 0x03) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003301 (nValue & 0x03);
3302 if (pInfo->reg[MT2063_REG_RSVD_1E] != val) {
3303 status |=
3304 MT2063_SetReg(pInfo, MT2063_REG_RSVD_1E,
3305 val);
3306 }
3307 break;
3308
3309 case MT2063_AMPGC:
3310 /* Set Amp gain code */
3311 val =
3312 (pInfo->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003313 reg[MT2063_REG_TEMP_SEL] & (u8) ~ 0x03) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003314 (nValue & 0x03);
3315 if (pInfo->reg[MT2063_REG_TEMP_SEL] != val) {
3316 status |=
3317 MT2063_SetReg(pInfo, MT2063_REG_TEMP_SEL,
3318 val);
3319 }
3320 break;
3321
3322 /* Avoid DECT Frequencies */
3323 case MT2063_AVOID_DECT:
3324 {
3325 enum MT2063_DECT_Avoid_Type newAvoidSetting =
3326 (enum MT2063_DECT_Avoid_Type)nValue;
3327 if ((newAvoidSetting >=
3328 MT2063_NO_DECT_AVOIDANCE)
3329 && (newAvoidSetting <= MT2063_AVOID_BOTH)) {
3330 pInfo->AS_Data.avoidDECT =
3331 newAvoidSetting;
3332 }
3333 }
3334 break;
3335
3336 /* Cleartune filter selection: 0 - by IC (default), 1 - by software */
3337 case MT2063_CTFILT_SW:
3338 pInfo->ctfilt_sw = (nValue & 0x01);
3339 break;
3340
3341 /* These parameters are read-only */
3342 case MT2063_IC_ADDR:
3343 case MT2063_MAX_OPEN:
3344 case MT2063_NUM_OPEN:
3345 case MT2063_INPUT_FREQ:
3346 case MT2063_IF1_ACTUAL:
3347 case MT2063_IF1_CENTER:
3348 case MT2063_IF1_BW:
3349 case MT2063_AS_ALG:
3350 case MT2063_EXCL_ZONES:
3351 case MT2063_SPUR_AVOIDED:
3352 case MT2063_NUM_SPURS:
3353 case MT2063_SPUR_PRESENT:
3354 case MT2063_ACLNA:
3355 case MT2063_ACRF:
3356 case MT2063_ACFIF:
3357 case MT2063_EOP:
3358 default:
3359 status |= MT2063_ARG_RANGE;
3360 }
3361 }
3362 return (status);
3363}
3364
3365/****************************************************************************
3366**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003367** Name: MT2063_ClearPowerMaskBits
3368**
3369** Description: Clears the power-down mask bits for various sections of
3370** the MT2063
3371**
3372** Parameters: h - Tuner handle (returned by MT2063_Open)
3373** Bits - Mask bits to be cleared.
3374**
3375** See definition of MT2063_Mask_Bits type for description
3376** of each of the power bits.
3377**
3378** Returns: status:
3379** MT_OK - No errors
3380** MT_INV_HANDLE - Invalid tuner handle
3381** MT_COMM_ERR - Serial bus communications error
3382**
3383** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3384**
3385** Revision History:
3386**
3387** SCR Date Author Description
3388** -------------------------------------------------------------------------
3389** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3390**
3391****************************************************************************/
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -03003392static u32 MT2063_ClearPowerMaskBits(struct MT2063_Info_t *pInfo, enum MT2063_Mask_Bits Bits)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003393{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003394 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003395
3396 /* Verify that the handle passed points to a valid tuner */
3397 if (MT2063_IsValidHandle(pInfo) == 0)
3398 status = MT2063_INV_HANDLE;
3399 else {
3400 Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */
3401 if ((Bits & 0xFF00) != 0) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003402 pInfo->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003403 status |=
3404 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3405 MT2063_REG_PWR_2,
3406 &pInfo->reg[MT2063_REG_PWR_2], 1);
3407 }
3408 if ((Bits & 0xFF) != 0) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003409 pInfo->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003410 status |=
3411 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3412 MT2063_REG_PWR_1,
3413 &pInfo->reg[MT2063_REG_PWR_1], 1);
3414 }
3415 }
3416
3417 return (status);
3418}
3419
3420/****************************************************************************
3421**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003422** Name: MT2063_SoftwareShutdown
3423**
3424** Description: Enables or disables software shutdown function. When
3425** Shutdown==1, any section whose power mask is set will be
3426** shutdown.
3427**
3428** Parameters: h - Tuner handle (returned by MT2063_Open)
3429** Shutdown - 1 = shutdown the masked sections, otherwise
3430** power all sections on
3431**
3432** Returns: status:
3433** MT_OK - No errors
3434** MT_INV_HANDLE - Invalid tuner handle
3435** MT_COMM_ERR - Serial bus communications error
3436**
3437** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3438**
3439** Revision History:
3440**
3441** SCR Date Author Description
3442** -------------------------------------------------------------------------
3443** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3444** 01-03-2008 PINZ Ver 1.xx: Added a trigger of BYPATNUP for
3445** correct wakeup of the LNA
3446**
3447****************************************************************************/
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -03003448static u32 MT2063_SoftwareShutdown(struct MT2063_Info_t *pInfo, u8 Shutdown)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003449{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003450 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003451
3452 /* Verify that the handle passed points to a valid tuner */
3453 if (MT2063_IsValidHandle(pInfo) == 0) {
3454 status = MT2063_INV_HANDLE;
3455 } else {
3456 if (Shutdown == 1)
3457 pInfo->reg[MT2063_REG_PWR_1] |= 0x04; /* Turn the bit on */
3458 else
3459 pInfo->reg[MT2063_REG_PWR_1] &= ~0x04; /* Turn off the bit */
3460
3461 status |=
3462 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3463 MT2063_REG_PWR_1,
3464 &pInfo->reg[MT2063_REG_PWR_1], 1);
3465
3466 if (Shutdown != 1) {
3467 pInfo->reg[MT2063_REG_BYP_CTRL] =
3468 (pInfo->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40;
3469 status |=
3470 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3471 MT2063_REG_BYP_CTRL,
3472 &pInfo->reg[MT2063_REG_BYP_CTRL],
3473 1);
3474 pInfo->reg[MT2063_REG_BYP_CTRL] =
3475 (pInfo->reg[MT2063_REG_BYP_CTRL] & 0x9F);
3476 status |=
3477 MT2063_WriteSub(pInfo->hUserData, pInfo->address,
3478 MT2063_REG_BYP_CTRL,
3479 &pInfo->reg[MT2063_REG_BYP_CTRL],
3480 1);
3481 }
3482 }
3483
3484 return (status);
3485}
3486
3487/****************************************************************************
3488**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003489** Name: MT2063_SetReg
3490**
3491** Description: Sets an MT2063 register.
3492**
3493** Parameters: h - Tuner handle (returned by MT2063_Open)
3494** reg - MT2063 register/subaddress location
3495** val - MT2063 register/subaddress value
3496**
3497** Returns: status:
3498** MT_OK - No errors
3499** MT_COMM_ERR - Serial bus communications error
3500** MT_INV_HANDLE - Invalid tuner handle
3501** MT_ARG_RANGE - Argument out of range
3502**
3503** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
3504**
3505** Use this function if you need to override a default
3506** register value
3507**
3508** Revision History:
3509**
3510** SCR Date Author Description
3511** -------------------------------------------------------------------------
3512** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3513**
3514****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03003515static u32 MT2063_SetReg(void *h, u8 reg, u8 val)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003516{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003517 u32 status = MT2063_OK; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003518 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
3519
3520 /* Verify that the handle passed points to a valid tuner */
3521 if (MT2063_IsValidHandle(pInfo) == 0)
3522 status |= MT2063_INV_HANDLE;
3523
3524 if (reg >= MT2063_REG_END_REGS)
3525 status |= MT2063_ARG_RANGE;
3526
3527 if (MT2063_NO_ERROR(status)) {
3528 status |=
3529 MT2063_WriteSub(pInfo->hUserData, pInfo->address, reg, &val,
3530 1);
3531 if (MT2063_NO_ERROR(status))
3532 pInfo->reg[reg] = val;
3533 }
3534
3535 return (status);
3536}
3537
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003538static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003539{
3540 return f_ref * (f_LO / f_ref)
3541 + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step);
3542}
3543
3544/****************************************************************************
3545**
3546** Name: fLO_FractionalTerm
3547**
3548** Description: Calculates the portion contributed by FracN / denom.
3549**
3550** This function preserves maximum precision without
3551** risk of overflow. It accurately calculates
3552** f_ref * num / denom to within 1 HZ with fixed math.
3553**
3554** Parameters: num - Fractional portion of the multiplier
3555** denom - denominator portion of the ratio
3556** This routine successfully handles denom values
3557** up to and including 2^18.
3558** f_Ref - SRO frequency. This calculation handles
3559** f_ref as two separate 14-bit fields.
3560** Therefore, a maximum value of 2^28-1
3561** may safely be used for f_ref. This is
3562** the genesis of the magic number "14" and the
3563** magic mask value of 0x03FFF.
3564**
3565** Returns: f_ref * num / denom
3566**
3567** Revision History:
3568**
3569** SCR Date Author Description
3570** -------------------------------------------------------------------------
3571** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3572**
3573****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003574static u32 MT2063_fLO_FractionalTerm(u32 f_ref,
3575 u32 num, u32 denom)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003576{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003577 u32 t1 = (f_ref >> 14) * num;
3578 u32 term1 = t1 / denom;
3579 u32 loss = t1 % denom;
3580 u32 term2 =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003581 (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom;
3582 return ((term1 << 14) + term2);
3583}
3584
3585/****************************************************************************
3586**
3587** Name: CalcLO1Mult
3588**
3589** Description: Calculates Integer divider value and the numerator
3590** value for a FracN PLL.
3591**
3592** This function assumes that the f_LO and f_Ref are
3593** evenly divisible by f_LO_Step.
3594**
3595** Parameters: Div - OUTPUT: Whole number portion of the multiplier
3596** FracN - OUTPUT: Fractional portion of the multiplier
3597** f_LO - desired LO frequency.
3598** f_LO_Step - Minimum step size for the LO (in Hz).
3599** f_Ref - SRO frequency.
3600** f_Avoid - Range of PLL frequencies to avoid near
3601** integer multiples of f_Ref (in Hz).
3602**
3603** Returns: Recalculated LO frequency.
3604**
3605** Revision History:
3606**
3607** SCR Date Author Description
3608** -------------------------------------------------------------------------
3609** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3610**
3611****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003612static u32 MT2063_CalcLO1Mult(u32 * Div,
3613 u32 * FracN,
3614 u32 f_LO,
3615 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003616{
3617 /* Calculate the whole number portion of the divider */
3618 *Div = f_LO / f_Ref;
3619
3620 /* Calculate the numerator value (round to nearest f_LO_Step) */
3621 *FracN =
3622 (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
3623 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
3624
3625 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64);
3626}
3627
3628/****************************************************************************
3629**
3630** Name: CalcLO2Mult
3631**
3632** Description: Calculates Integer divider value and the numerator
3633** value for a FracN PLL.
3634**
3635** This function assumes that the f_LO and f_Ref are
3636** evenly divisible by f_LO_Step.
3637**
3638** Parameters: Div - OUTPUT: Whole number portion of the multiplier
3639** FracN - OUTPUT: Fractional portion of the multiplier
3640** f_LO - desired LO frequency.
3641** f_LO_Step - Minimum step size for the LO (in Hz).
3642** f_Ref - SRO frequency.
3643** f_Avoid - Range of PLL frequencies to avoid near
3644** integer multiples of f_Ref (in Hz).
3645**
3646** Returns: Recalculated LO frequency.
3647**
3648** Revision History:
3649**
3650** SCR Date Author Description
3651** -------------------------------------------------------------------------
3652** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3653**
3654****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003655static u32 MT2063_CalcLO2Mult(u32 * Div,
3656 u32 * FracN,
3657 u32 f_LO,
3658 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003659{
3660 /* Calculate the whole number portion of the divider */
3661 *Div = f_LO / f_Ref;
3662
3663 /* Calculate the numerator value (round to nearest f_LO_Step) */
3664 *FracN =
3665 (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
3666 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
3667
3668 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN,
3669 8191);
3670}
3671
3672/****************************************************************************
3673**
3674** Name: FindClearTuneFilter
3675**
3676** Description: Calculate the corrrect ClearTune filter to be used for
3677** a given input frequency.
3678**
3679** Parameters: pInfo - ptr to tuner data structure
3680** f_in - RF input center frequency (in Hz).
3681**
3682** Returns: ClearTune filter number (0-31)
3683**
3684** Dependencies: MUST CALL MT2064_Open BEFORE FindClearTuneFilter!
3685**
3686** Revision History:
3687**
3688** SCR Date Author Description
3689** -------------------------------------------------------------------------
3690** 04-10-2008 PINZ Ver 1.14: Use software-controlled ClearTune
3691** cross-over frequency values.
3692**
3693****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003694static u32 FindClearTuneFilter(struct MT2063_Info_t *pInfo, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003695{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003696 u32 RFBand;
3697 u32 idx; /* index loop */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003698
3699 /*
3700 ** Find RF Band setting
3701 */
3702 RFBand = 31; /* def when f_in > all */
3703 for (idx = 0; idx < 31; ++idx) {
3704 if (pInfo->CTFiltMax[idx] >= f_in) {
3705 RFBand = idx;
3706 break;
3707 }
3708 }
3709 return (RFBand);
3710}
3711
3712/****************************************************************************
3713**
3714** Name: MT2063_Tune
3715**
3716** Description: Change the tuner's tuned frequency to RFin.
3717**
3718** Parameters: h - Open handle to the tuner (from MT2063_Open).
3719** f_in - RF input center frequency (in Hz).
3720**
3721** Returns: status:
3722** MT_OK - No errors
3723** MT_INV_HANDLE - Invalid tuner handle
3724** MT_UPC_UNLOCK - Upconverter PLL unlocked
3725** MT_DNC_UNLOCK - Downconverter PLL unlocked
3726** MT_COMM_ERR - Serial bus communications error
3727** MT_SPUR_CNT_MASK - Count of avoided LO spurs
3728** MT_SPUR_PRESENT - LO spur possible in output
3729** MT_FIN_RANGE - Input freq out of range
3730** MT_FOUT_RANGE - Output freq out of range
3731** MT_UPC_RANGE - Upconverter freq out of range
3732** MT_DNC_RANGE - Downconverter freq out of range
3733**
3734** Dependencies: MUST CALL MT2063_Open BEFORE MT2063_Tune!
3735**
3736** MT_ReadSub - Read data from the two-wire serial bus
3737** MT_WriteSub - Write data to the two-wire serial bus
3738** MT_Sleep - Delay execution for x milliseconds
3739** MT2063_GetLocked - Checks to see if LO1 and LO2 are locked
3740**
3741** Revision History:
3742**
3743** SCR Date Author Description
3744** -------------------------------------------------------------------------
3745** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
3746** 04-10-2008 PINZ Ver 1.05: Use software-controlled ClearTune
3747** cross-over frequency values.
3748** 175 I 16-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
3749** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
3750** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
3751**
3752****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03003753static u32 MT2063_Tune(void *h, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003754{ /* RF input center frequency */
3755 struct MT2063_Info_t *pInfo = (struct MT2063_Info_t *)h;
3756
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003757 u32 status = MT2063_OK; /* status of operation */
3758 u32 LO1; /* 1st LO register value */
3759 u32 Num1; /* Numerator for LO1 reg. value */
3760 u32 f_IF1; /* 1st IF requested */
3761 u32 LO2; /* 2nd LO register value */
3762 u32 Num2; /* Numerator for LO2 reg. value */
3763 u32 ofLO1, ofLO2; /* last time's LO frequencies */
3764 u32 ofin, ofout; /* last time's I/O frequencies */
3765 u8 fiffc = 0x80; /* FIFF center freq from tuner */
3766 u32 fiffof; /* Offset from FIFF center freq */
3767 const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */
3768 u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */
3769 u8 val;
3770 u32 RFBand;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003771
3772 /* Verify that the handle passed points to a valid tuner */
3773 if (MT2063_IsValidHandle(pInfo) == 0)
3774 return MT2063_INV_HANDLE;
3775
3776 /* Check the input and output frequency ranges */
3777 if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ))
3778 status |= MT2063_FIN_RANGE;
3779
3780 if ((pInfo->AS_Data.f_out < MT2063_MIN_FOUT_FREQ)
3781 || (pInfo->AS_Data.f_out > MT2063_MAX_FOUT_FREQ))
3782 status |= MT2063_FOUT_RANGE;
3783
3784 /*
3785 ** Save original LO1 and LO2 register values
3786 */
3787 ofLO1 = pInfo->AS_Data.f_LO1;
3788 ofLO2 = pInfo->AS_Data.f_LO2;
3789 ofin = pInfo->AS_Data.f_in;
3790 ofout = pInfo->AS_Data.f_out;
3791
3792 /*
3793 ** Find and set RF Band setting
3794 */
3795 if (pInfo->ctfilt_sw == 1) {
3796 val = (pInfo->reg[MT2063_REG_CTUNE_CTRL] | 0x08);
3797 if (pInfo->reg[MT2063_REG_CTUNE_CTRL] != val) {
3798 status |=
3799 MT2063_SetReg(pInfo, MT2063_REG_CTUNE_CTRL, val);
3800 }
3801 val = pInfo->reg[MT2063_REG_CTUNE_OV];
3802 RFBand = FindClearTuneFilter(pInfo, f_in);
3803 pInfo->reg[MT2063_REG_CTUNE_OV] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003804 (u8) ((pInfo->reg[MT2063_REG_CTUNE_OV] & ~0x1F)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003805 | RFBand);
3806 if (pInfo->reg[MT2063_REG_CTUNE_OV] != val) {
3807 status |=
3808 MT2063_SetReg(pInfo, MT2063_REG_CTUNE_OV, val);
3809 }
3810 }
3811
3812 /*
3813 ** Read the FIFF Center Frequency from the tuner
3814 */
3815 if (MT2063_NO_ERROR(status)) {
3816 status |=
3817 MT2063_ReadSub(pInfo->hUserData, pInfo->address,
3818 MT2063_REG_FIFFC,
3819 &pInfo->reg[MT2063_REG_FIFFC], 1);
3820 fiffc = pInfo->reg[MT2063_REG_FIFFC];
3821 }
3822 /*
3823 ** Assign in the requested values
3824 */
3825 pInfo->AS_Data.f_in = f_in;
3826 /* Request a 1st IF such that LO1 is on a step size */
3827 pInfo->AS_Data.f_if1_Request =
3828 MT2063_Round_fLO(pInfo->AS_Data.f_if1_Request + f_in,
3829 pInfo->AS_Data.f_LO1_Step,
3830 pInfo->AS_Data.f_ref) - f_in;
3831
3832 /*
3833 ** Calculate frequency settings. f_IF1_FREQ + f_in is the
3834 ** desired LO1 frequency
3835 */
3836 MT2063_ResetExclZones(&pInfo->AS_Data);
3837
3838 f_IF1 = MT2063_ChooseFirstIF(&pInfo->AS_Data);
3839
3840 pInfo->AS_Data.f_LO1 =
3841 MT2063_Round_fLO(f_IF1 + f_in, pInfo->AS_Data.f_LO1_Step,
3842 pInfo->AS_Data.f_ref);
3843
3844 pInfo->AS_Data.f_LO2 =
3845 MT2063_Round_fLO(pInfo->AS_Data.f_LO1 - pInfo->AS_Data.f_out - f_in,
3846 pInfo->AS_Data.f_LO2_Step, pInfo->AS_Data.f_ref);
3847
3848 /*
3849 ** Check for any LO spurs in the output bandwidth and adjust
3850 ** the LO settings to avoid them if needed
3851 */
3852 status |= MT2063_AvoidSpurs(h, &pInfo->AS_Data);
3853 /*
3854 ** MT_AvoidSpurs spurs may have changed the LO1 & LO2 values.
3855 ** Recalculate the LO frequencies and the values to be placed
3856 ** in the tuning registers.
3857 */
3858 pInfo->AS_Data.f_LO1 =
3859 MT2063_CalcLO1Mult(&LO1, &Num1, pInfo->AS_Data.f_LO1,
3860 pInfo->AS_Data.f_LO1_Step, pInfo->AS_Data.f_ref);
3861 pInfo->AS_Data.f_LO2 =
3862 MT2063_Round_fLO(pInfo->AS_Data.f_LO1 - pInfo->AS_Data.f_out - f_in,
3863 pInfo->AS_Data.f_LO2_Step, pInfo->AS_Data.f_ref);
3864 pInfo->AS_Data.f_LO2 =
3865 MT2063_CalcLO2Mult(&LO2, &Num2, pInfo->AS_Data.f_LO2,
3866 pInfo->AS_Data.f_LO2_Step, pInfo->AS_Data.f_ref);
3867
3868 /*
3869 ** Check the upconverter and downconverter frequency ranges
3870 */
3871 if ((pInfo->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ)
3872 || (pInfo->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ))
3873 status |= MT2063_UPC_RANGE;
3874 if ((pInfo->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ)
3875 || (pInfo->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ))
3876 status |= MT2063_DNC_RANGE;
3877 /* LO2 Lock bit was in a different place for B0 version */
3878 if (pInfo->tuner_id == MT2063_B0)
3879 LO2LK = 0x40;
3880
3881 /*
3882 ** If we have the same LO frequencies and we're already locked,
3883 ** then skip re-programming the LO registers.
3884 */
3885 if ((ofLO1 != pInfo->AS_Data.f_LO1)
3886 || (ofLO2 != pInfo->AS_Data.f_LO2)
3887 || ((pInfo->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) !=
3888 (LO1LK | LO2LK))) {
3889 /*
3890 ** Calculate the FIFFOF register value
3891 **
3892 ** IF1_Actual
3893 ** FIFFOF = ------------ - 8 * FIFFC - 4992
3894 ** f_ref/64
3895 */
3896 fiffof =
3897 (pInfo->AS_Data.f_LO1 -
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003898 f_in) / (pInfo->AS_Data.f_ref / 64) - 8 * (u32) fiffc -
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003899 4992;
3900 if (fiffof > 0xFF)
3901 fiffof = 0xFF;
3902
3903 /*
3904 ** Place all of the calculated values into the local tuner
3905 ** register fields.
3906 */
3907 if (MT2063_NO_ERROR(status)) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003908 pInfo->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */
3909 pInfo->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */
3910 pInfo->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003911 |(Num2 >> 12)); /* NUM2q (hi) */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003912 pInfo->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */
3913 pInfo->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003914
3915 /*
3916 ** Now write out the computed register values
3917 ** IMPORTANT: There is a required order for writing
3918 ** (0x05 must follow all the others).
3919 */
3920 status |= MT2063_WriteSub(pInfo->hUserData, pInfo->address, MT2063_REG_LO1CQ_1, &pInfo->reg[MT2063_REG_LO1CQ_1], 5); /* 0x01 - 0x05 */
3921 if (pInfo->tuner_id == MT2063_B0) {
3922 /* Re-write the one-shot bits to trigger the tune operation */
3923 status |= MT2063_WriteSub(pInfo->hUserData, pInfo->address, MT2063_REG_LO2CQ_3, &pInfo->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */
3924 }
3925 /* Write out the FIFF offset only if it's changing */
3926 if (pInfo->reg[MT2063_REG_FIFF_OFFSET] !=
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003927 (u8) fiffof) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003928 pInfo->reg[MT2063_REG_FIFF_OFFSET] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003929 (u8) fiffof;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003930 status |=
3931 MT2063_WriteSub(pInfo->hUserData,
3932 pInfo->address,
3933 MT2063_REG_FIFF_OFFSET,
3934 &pInfo->
3935 reg[MT2063_REG_FIFF_OFFSET],
3936 1);
3937 }
3938 }
3939
3940 /*
3941 ** Check for LO's locking
3942 */
3943
3944 if (MT2063_NO_ERROR(status)) {
3945 status |= MT2063_GetLocked(h);
3946 }
3947 /*
3948 ** If we locked OK, assign calculated data to MT2063_Info_t structure
3949 */
3950 if (MT2063_NO_ERROR(status)) {
3951 pInfo->f_IF1_actual = pInfo->AS_Data.f_LO1 - f_in;
3952 }
3953 }
3954
3955 return (status);
3956}
3957
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03003958static u32 MT_Tune_atv(void *h, u32 f_in, u32 bw_in,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003959 enum MTTune_atv_standard tv_type)
3960{
3961
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003962 u32 status = MT2063_OK;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003963
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003964 s32 pict_car = 0;
3965 s32 pict2chanb_vsb = 0;
3966 s32 pict2chanb_snd = 0;
3967 s32 pict2snd1 = 0;
3968 s32 pict2snd2 = 0;
3969 s32 ch_bw = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003970
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03003971 s32 if_mid = 0;
3972 s32 rcvr_mode = 0;
3973 u32 mode_get = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003974
3975 switch (tv_type) {
3976 case MTTUNEA_PAL_B:{
3977 pict_car = 38900000;
3978 ch_bw = 8000000;
3979 pict2chanb_vsb = -1250000;
3980 pict2snd1 = 5500000;
3981 pict2snd2 = 5742000;
3982 rcvr_mode = 1;
3983 break;
3984 }
3985 case MTTUNEA_PAL_G:{
3986 pict_car = 38900000;
3987 ch_bw = 7000000;
3988 pict2chanb_vsb = -1250000;
3989 pict2snd1 = 5500000;
3990 pict2snd2 = 0;
3991 rcvr_mode = 1;
3992 break;
3993 }
3994 case MTTUNEA_PAL_I:{
3995 pict_car = 38900000;
3996 ch_bw = 8000000;
3997 pict2chanb_vsb = -1250000;
3998 pict2snd1 = 6000000;
3999 pict2snd2 = 0;
4000 rcvr_mode = 1;
4001 break;
4002 }
4003 case MTTUNEA_PAL_L:{
4004 pict_car = 38900000;
4005 ch_bw = 8000000;
4006 pict2chanb_vsb = -1250000;
4007 pict2snd1 = 6500000;
4008 pict2snd2 = 0;
4009 rcvr_mode = 1;
4010 break;
4011 }
4012 case MTTUNEA_PAL_MN:{
4013 pict_car = 38900000;
4014 ch_bw = 6000000;
4015 pict2chanb_vsb = -1250000;
4016 pict2snd1 = 4500000;
4017 pict2snd2 = 0;
4018 rcvr_mode = 1;
4019 break;
4020 }
4021 case MTTUNEA_PAL_DK:{
4022 pict_car = 38900000;
4023 ch_bw = 8000000;
4024 pict2chanb_vsb = -1250000;
4025 pict2snd1 = 6500000;
4026 pict2snd2 = 0;
4027 rcvr_mode = 1;
4028 break;
4029 }
4030 case MTTUNEA_DIGITAL:{
4031 pict_car = 36125000;
4032 ch_bw = 8000000;
4033 pict2chanb_vsb = -(ch_bw / 2);
4034 pict2snd1 = 0;
4035 pict2snd2 = 0;
4036 rcvr_mode = 2;
4037 break;
4038 }
4039 case MTTUNEA_FMRADIO:{
4040 pict_car = 38900000;
4041 ch_bw = 8000000;
4042 pict2chanb_vsb = -(ch_bw / 2);
4043 pict2snd1 = 0;
4044 pict2snd2 = 0;
4045 rcvr_mode = 4;
4046 //f_in -= 2900000;
4047 break;
4048 }
4049 case MTTUNEA_DVBC:{
4050 pict_car = 36125000;
4051 ch_bw = 8000000;
4052 pict2chanb_vsb = -(ch_bw / 2);
4053 pict2snd1 = 0;
4054 pict2snd2 = 0;
4055 rcvr_mode = MT2063_CABLE_QAM;
4056 break;
4057 }
4058 case MTTUNEA_DVBT:{
4059 pict_car = 36125000;
4060 ch_bw = bw_in; //8000000
4061 pict2chanb_vsb = -(ch_bw / 2);
4062 pict2snd1 = 0;
4063 pict2snd2 = 0;
4064 rcvr_mode = MT2063_OFFAIR_COFDM;
4065 break;
4066 }
4067 case MTTUNEA_UNKNOWN:
4068 break;
4069 default:
4070 break;
4071 }
4072
4073 pict2chanb_snd = pict2chanb_vsb - ch_bw;
4074 if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
4075
4076 status |= MT2063_SetParam(h, MT2063_STEPSIZE, 125000);
4077 status |= MT2063_SetParam(h, MT2063_OUTPUT_FREQ, if_mid);
4078 status |= MT2063_SetParam(h, MT2063_OUTPUT_BW, ch_bw);
4079 status |= MT2063_GetParam(h, MT2063_RCVR_MODE, &mode_get);
4080
4081 status |= MT2063_SetParam(h, MT2063_RCVR_MODE, rcvr_mode);
4082 status |= MT2063_Tune(h, (f_in + (pict2chanb_vsb + (ch_bw / 2))));
4083 status |= MT2063_GetParam(h, MT2063_RCVR_MODE, &mode_get);
4084
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004085 return (u32) status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004086}
4087
4088static int mt2063_init(struct dvb_frontend *fe)
4089{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004090 u32 status = MT2063_ERROR;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004091 struct mt2063_state *state = fe->tuner_priv;
4092
4093 status = MT2063_Open(0xC0, &(state->MT2063_ht), fe);
4094 status |= MT2063_SoftwareShutdown(state->MT2063_ht, 1);
4095 status |= MT2063_ClearPowerMaskBits(state->MT2063_ht, MT2063_ALL_SD);
4096
4097 if (MT2063_OK != status) {
4098 printk("%s %d error status = 0x%x!!\n", __func__, __LINE__,
4099 status);
4100 return -1;
4101 }
4102
4103 return 0;
4104}
4105
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004106static int mt2063_get_status(struct dvb_frontend *fe, u32 * status)
4107{
4108 int rc = 0;
4109
4110 //get tuner lock status
4111
4112 return rc;
4113}
4114
4115static int mt2063_get_state(struct dvb_frontend *fe,
4116 enum tuner_param param, struct tuner_state *state)
4117{
4118 struct mt2063_state *mt2063State = fe->tuner_priv;
4119
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004120 switch (param) {
4121 case DVBFE_TUNER_FREQUENCY:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004122 //get frequency
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004123 break;
4124 case DVBFE_TUNER_TUNERSTEP:
4125 break;
4126 case DVBFE_TUNER_IFFREQ:
4127 break;
4128 case DVBFE_TUNER_BANDWIDTH:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004129 //get bandwidth
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004130 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004131 case DVBFE_TUNER_REFCLOCK:
4132 state->refclock =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004133 (u32)
4134 MT2063_GetLocked((void *) (mt2063State->MT2063_ht));
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004135 break;
4136 default:
4137 break;
4138 }
4139
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004140 return (int)state->refclock;
4141}
4142
4143static int mt2063_set_state(struct dvb_frontend *fe,
4144 enum tuner_param param, struct tuner_state *state)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004145{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004146 struct mt2063_state *mt2063State = fe->tuner_priv;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004147 u32 status = MT2063_OK;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004148
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004149 switch (param) {
4150 case DVBFE_TUNER_FREQUENCY:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004151 //set frequency
4152
4153 status =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004154 MT_Tune_atv((void *) (mt2063State->MT2063_ht),
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004155 state->frequency, state->bandwidth,
4156 mt2063State->tv_type);
4157
4158 mt2063State->frequency = state->frequency;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004159 break;
4160 case DVBFE_TUNER_TUNERSTEP:
4161 break;
4162 case DVBFE_TUNER_IFFREQ:
4163 break;
4164 case DVBFE_TUNER_BANDWIDTH:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004165 //set bandwidth
4166 mt2063State->bandwidth = state->bandwidth;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004167 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004168 case DVBFE_TUNER_REFCLOCK:
4169
4170 break;
4171 case DVBFE_TUNER_OPEN:
4172 status = MT2063_Open(MT2063_I2C, &(mt2063State->MT2063_ht), fe);
4173 break;
4174 case DVBFE_TUNER_SOFTWARE_SHUTDOWN:
4175 status = MT2063_SoftwareShutdown(mt2063State->MT2063_ht, 1);
4176 break;
4177 case DVBFE_TUNER_CLEAR_POWER_MASKBITS:
4178 status =
4179 MT2063_ClearPowerMaskBits(mt2063State->MT2063_ht,
4180 MT2063_ALL_SD);
4181 break;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004182 default:
4183 break;
4184 }
4185
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004186 return (int)status;
4187}
4188
4189static int mt2063_release(struct dvb_frontend *fe)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004190{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004191 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004192
4193 fe->tuner_priv = NULL;
4194 kfree(state);
4195
4196 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004197}
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004198
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004199static struct dvb_tuner_ops mt2063_ops = {
4200 .info = {
4201 .name = "MT2063 Silicon Tuner",
4202 .frequency_min = 45000000,
4203 .frequency_max = 850000000,
4204 .frequency_step = 0,
4205 },
4206
4207 .init = mt2063_init,
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03004208 .sleep = MT2063_Sleep,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004209 .get_status = mt2063_get_status,
4210 .get_state = mt2063_get_state,
4211 .set_state = mt2063_set_state,
4212 .release = mt2063_release
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004213};
4214
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004215struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
4216 struct mt2063_config *config,
4217 struct i2c_adapter *i2c)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004218{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004219 struct mt2063_state *state = NULL;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004220
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004221 state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004222 if (state == NULL)
4223 goto error;
4224
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004225 state->config = config;
4226 state->i2c = i2c;
4227 state->frontend = fe;
4228 state->reference = config->refclock / 1000; /* kHz */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03004229 state->MT2063_init = false;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004230 fe->tuner_priv = state;
4231 fe->ops.tuner_ops = mt2063_ops;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004232
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004233 printk("%s: Attaching MT2063 \n", __func__);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004234 return fe;
4235
4236error:
4237 kfree(state);
4238 return NULL;
4239}
4240
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004241EXPORT_SYMBOL(mt2063_attach);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03004242MODULE_PARM_DESC(verbose, "Set Verbosity level");
4243
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03004244MODULE_AUTHOR("Henry");
4245MODULE_DESCRIPTION("MT2063 Silicon tuner");
4246MODULE_LICENSE("GPL");