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