blob: 4f634ad24e14dc5f41803092435fa4305500b9cd [file] [log] [blame]
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001#include <linux/init.h>
2#include <linux/kernel.h>
3#include <linux/module.h>
4#include <linux/string.h>
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03005#include <linux/videodev2.h>
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03006
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03007#include "mt2063.h"
8
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03009static unsigned int verbose;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -030010module_param(verbose, int, 0644);
11
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -030012/* positive error codes used internally */
Mauro Carvalho Chehab29a0a4f2011-07-20 23:44:10 -030013
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -030014/* Info: Unavoidable LO-related spur may be present in the output */
Mauro Carvalho Chehab29a0a4f2011-07-20 23:44:10 -030015#define MT2063_SPUR_PRESENT_ERR (0x00800000)
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030016
17/* Info: Mask of bits used for # of LO-related spurs that were avoided during tuning */
18#define MT2063_SPUR_CNT_MASK (0x001f0000)
19#define MT2063_SPUR_SHIFT (16)
20
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030021/* Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */
22#define MT2063_UPC_RANGE (0x04000000)
23
24/* Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */
25#define MT2063_DNC_RANGE (0x08000000)
26
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030027/*
28 * Constant defining the version of the following structure
29 * and therefore the API for this code.
30 *
31 * When compiling the tuner driver, the preprocessor will
32 * check against this version number to make sure that
33 * it matches the version that the tuner driver knows about.
34 */
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030035
36/* DECT Frequency Avoidance */
37#define MT2063_DECT_AVOID_US_FREQS 0x00000001
38
39#define MT2063_DECT_AVOID_EURO_FREQS 0x00000002
40
41#define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0)
42
43#define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0)
44
45enum MT2063_DECT_Avoid_Type {
46 MT2063_NO_DECT_AVOIDANCE = 0, /* Do not create DECT exclusion zones. */
47 MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS, /* Avoid US DECT frequencies. */
48 MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS, /* Avoid European DECT frequencies. */
49 MT2063_AVOID_BOTH /* Avoid both regions. Not typically used. */
50};
51
52#define MT2063_MAX_ZONES 48
53
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030054struct MT2063_ExclZone_t {
55 u32 min_;
56 u32 max_;
57 struct MT2063_ExclZone_t *next_;
58};
59
60/*
61 * Structure of data needed for Spur Avoidance
62 */
63struct MT2063_AvoidSpursData_t {
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030064 u32 f_ref;
65 u32 f_in;
66 u32 f_LO1;
67 u32 f_if1_Center;
68 u32 f_if1_Request;
69 u32 f_if1_bw;
70 u32 f_LO2;
71 u32 f_out;
72 u32 f_out_bw;
73 u32 f_LO1_Step;
74 u32 f_LO2_Step;
75 u32 f_LO1_FracN_Avoid;
76 u32 f_LO2_FracN_Avoid;
77 u32 f_zif_bw;
78 u32 f_min_LO_Separation;
79 u32 maxH1;
80 u32 maxH2;
81 enum MT2063_DECT_Avoid_Type avoidDECT;
82 u32 bSpurPresent;
83 u32 bSpurAvoided;
84 u32 nSpursFound;
85 u32 nZones;
86 struct MT2063_ExclZone_t *freeZones;
87 struct MT2063_ExclZone_t *usedZones;
88 struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES];
89};
90
91/*
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030092 * Parameter for function MT2063_SetPowerMask that specifies the power down
93 * of various sections of the MT2063.
94 */
95enum MT2063_Mask_Bits {
96 MT2063_REG_SD = 0x0040, /* Shutdown regulator */
97 MT2063_SRO_SD = 0x0020, /* Shutdown SRO */
98 MT2063_AFC_SD = 0x0010, /* Shutdown AFC A/D */
99 MT2063_PD_SD = 0x0002, /* Enable power detector shutdown */
100 MT2063_PDADC_SD = 0x0001, /* Enable power detector A/D shutdown */
101 MT2063_VCO_SD = 0x8000, /* Enable VCO shutdown */
102 MT2063_LTX_SD = 0x4000, /* Enable LTX shutdown */
103 MT2063_LT1_SD = 0x2000, /* Enable LT1 shutdown */
104 MT2063_LNA_SD = 0x1000, /* Enable LNA shutdown */
105 MT2063_UPC_SD = 0x0800, /* Enable upconverter shutdown */
106 MT2063_DNC_SD = 0x0400, /* Enable downconverter shutdown */
107 MT2063_VGA_SD = 0x0200, /* Enable VGA shutdown */
108 MT2063_AMP_SD = 0x0100, /* Enable AMP shutdown */
109 MT2063_ALL_SD = 0xFF73, /* All shutdown bits for this tuner */
110 MT2063_NONE_SD = 0x0000 /* No shutdown bits */
111};
112
113/*
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300114 * Parameter for selecting tuner mode
115 */
116enum MT2063_RCVR_MODES {
117 MT2063_CABLE_QAM = 0, /* Digital cable */
118 MT2063_CABLE_ANALOG, /* Analog cable */
119 MT2063_OFFAIR_COFDM, /* Digital offair */
120 MT2063_OFFAIR_COFDM_SAWLESS, /* Digital offair without SAW */
121 MT2063_OFFAIR_ANALOG, /* Analog offair */
122 MT2063_OFFAIR_8VSB, /* Analog offair */
123 MT2063_NUM_RCVR_MODES
124};
125
126/*
127 * Possible values for MT2063_DNC_OUTPUT
128 */
129enum MT2063_DNC_Output_Enable {
130 MT2063_DNC_NONE = 0,
131 MT2063_DNC_1,
132 MT2063_DNC_2,
133 MT2063_DNC_BOTH
134};
135
136/*
137** Two-wire serial bus subaddresses of the tuner registers.
138** Also known as the tuner's register addresses.
139*/
140enum MT2063_Register_Offsets {
141 MT2063_REG_PART_REV = 0, /* 0x00: Part/Rev Code */
142 MT2063_REG_LO1CQ_1, /* 0x01: LO1C Queued Byte 1 */
143 MT2063_REG_LO1CQ_2, /* 0x02: LO1C Queued Byte 2 */
144 MT2063_REG_LO2CQ_1, /* 0x03: LO2C Queued Byte 1 */
145 MT2063_REG_LO2CQ_2, /* 0x04: LO2C Queued Byte 2 */
146 MT2063_REG_LO2CQ_3, /* 0x05: LO2C Queued Byte 3 */
147 MT2063_REG_RSVD_06, /* 0x06: Reserved */
148 MT2063_REG_LO_STATUS, /* 0x07: LO Status */
149 MT2063_REG_FIFFC, /* 0x08: FIFF Center */
150 MT2063_REG_CLEARTUNE, /* 0x09: ClearTune Filter */
151 MT2063_REG_ADC_OUT, /* 0x0A: ADC_OUT */
152 MT2063_REG_LO1C_1, /* 0x0B: LO1C Byte 1 */
153 MT2063_REG_LO1C_2, /* 0x0C: LO1C Byte 2 */
154 MT2063_REG_LO2C_1, /* 0x0D: LO2C Byte 1 */
155 MT2063_REG_LO2C_2, /* 0x0E: LO2C Byte 2 */
156 MT2063_REG_LO2C_3, /* 0x0F: LO2C Byte 3 */
157 MT2063_REG_RSVD_10, /* 0x10: Reserved */
158 MT2063_REG_PWR_1, /* 0x11: PWR Byte 1 */
159 MT2063_REG_PWR_2, /* 0x12: PWR Byte 2 */
160 MT2063_REG_TEMP_STATUS, /* 0x13: Temp Status */
161 MT2063_REG_XO_STATUS, /* 0x14: Crystal Status */
162 MT2063_REG_RF_STATUS, /* 0x15: RF Attn Status */
163 MT2063_REG_FIF_STATUS, /* 0x16: FIF Attn Status */
164 MT2063_REG_LNA_OV, /* 0x17: LNA Attn Override */
165 MT2063_REG_RF_OV, /* 0x18: RF Attn Override */
166 MT2063_REG_FIF_OV, /* 0x19: FIF Attn Override */
167 MT2063_REG_LNA_TGT, /* 0x1A: Reserved */
168 MT2063_REG_PD1_TGT, /* 0x1B: Pwr Det 1 Target */
169 MT2063_REG_PD2_TGT, /* 0x1C: Pwr Det 2 Target */
170 MT2063_REG_RSVD_1D, /* 0x1D: Reserved */
171 MT2063_REG_RSVD_1E, /* 0x1E: Reserved */
172 MT2063_REG_RSVD_1F, /* 0x1F: Reserved */
173 MT2063_REG_RSVD_20, /* 0x20: Reserved */
174 MT2063_REG_BYP_CTRL, /* 0x21: Bypass Control */
175 MT2063_REG_RSVD_22, /* 0x22: Reserved */
176 MT2063_REG_RSVD_23, /* 0x23: Reserved */
177 MT2063_REG_RSVD_24, /* 0x24: Reserved */
178 MT2063_REG_RSVD_25, /* 0x25: Reserved */
179 MT2063_REG_RSVD_26, /* 0x26: Reserved */
180 MT2063_REG_RSVD_27, /* 0x27: Reserved */
181 MT2063_REG_FIFF_CTRL, /* 0x28: FIFF Control */
182 MT2063_REG_FIFF_OFFSET, /* 0x29: FIFF Offset */
183 MT2063_REG_CTUNE_CTRL, /* 0x2A: Reserved */
184 MT2063_REG_CTUNE_OV, /* 0x2B: Reserved */
185 MT2063_REG_CTRL_2C, /* 0x2C: Reserved */
186 MT2063_REG_FIFF_CTRL2, /* 0x2D: Fiff Control */
187 MT2063_REG_RSVD_2E, /* 0x2E: Reserved */
188 MT2063_REG_DNC_GAIN, /* 0x2F: DNC Control */
189 MT2063_REG_VGA_GAIN, /* 0x30: VGA Gain Ctrl */
190 MT2063_REG_RSVD_31, /* 0x31: Reserved */
191 MT2063_REG_TEMP_SEL, /* 0x32: Temperature Selection */
192 MT2063_REG_RSVD_33, /* 0x33: Reserved */
193 MT2063_REG_RSVD_34, /* 0x34: Reserved */
194 MT2063_REG_RSVD_35, /* 0x35: Reserved */
195 MT2063_REG_RSVD_36, /* 0x36: Reserved */
196 MT2063_REG_RSVD_37, /* 0x37: Reserved */
197 MT2063_REG_RSVD_38, /* 0x38: Reserved */
198 MT2063_REG_RSVD_39, /* 0x39: Reserved */
199 MT2063_REG_RSVD_3A, /* 0x3A: Reserved */
200 MT2063_REG_RSVD_3B, /* 0x3B: Reserved */
201 MT2063_REG_RSVD_3C, /* 0x3C: Reserved */
202 MT2063_REG_END_REGS
203};
204
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300205struct mt2063_state {
206 struct i2c_adapter *i2c;
207
208 const struct mt2063_config *config;
209 struct dvb_tuner_ops ops;
210 struct dvb_frontend *frontend;
211 struct tuner_state status;
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300212
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300213 u32 frequency;
214 u32 srate;
215 u32 bandwidth;
216 u32 reference;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300217
218 u32 tuner_id;
219 struct MT2063_AvoidSpursData_t AS_Data;
220 u32 f_IF1_actual;
221 u32 rcvr_mode;
222 u32 ctfilt_sw;
223 u32 CTFiltMax[31];
224 u32 num_regs;
225 u8 reg[MT2063_REG_END_REGS];
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300226};
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300227
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300228/*
229 * mt2063_write - Write data into the I2C bus
230 */
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300231static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300232{
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300233 struct dvb_frontend *fe = state->frontend;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300234 int ret;
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300235 u8 buf[60];
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300236 struct i2c_msg msg = {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300237 .addr = state->config->tuner_address,
238 .flags = 0,
239 .buf = buf,
240 .len = len + 1
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300241 };
242
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300243 msg.buf[0] = reg;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300244 memcpy(msg.buf + 1, data, len);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300245
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -0300246 if (fe->ops.i2c_gate_ctrl)
247 fe->ops.i2c_gate_ctrl(fe, 1);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300248 ret = i2c_transfer(state->i2c, &msg, 1);
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -0300249 if (fe->ops.i2c_gate_ctrl)
250 fe->ops.i2c_gate_ctrl(fe, 0);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300251
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300252 if (ret < 0)
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -0300253 printk(KERN_ERR "%s error ret=%d\n", __func__, ret);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300254
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300255 return ret;
256}
257
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300258/*
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300259 * mt2063_write - Write register data into the I2C bus, caching the value
260 */
261static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val)
262{
263 u32 status;
264
265 if (reg >= MT2063_REG_END_REGS)
266 return -ERANGE;
267
268 status = mt2063_write(state, reg, &val, 1);
269 if (status < 0)
270 return status;
271
272 state->reg[reg] = val;
273
274 return 0;
275}
276
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300277/*
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300278 * mt2063_read - Read data from the I2C bus
279 */
280static u32 mt2063_read(struct mt2063_state *state,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300281 u8 subAddress, u8 *pData, u32 cnt)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300282{
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300283 u32 status = 0; /* Status to be returned */
284 struct dvb_frontend *fe = state->frontend;
285 u32 i = 0;
286
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -0300287 if (fe->ops.i2c_gate_ctrl)
288 fe->ops.i2c_gate_ctrl(fe, 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300289
290 for (i = 0; i < cnt; i++) {
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300291 int ret;
292 u8 b0[] = { subAddress + i };
293 struct i2c_msg msg[] = {
294 {
295 .addr = state->config->tuner_address,
296 .flags = I2C_M_RD,
297 .buf = b0,
298 .len = 1
299 }, {
300 .addr = state->config->tuner_address,
301 .flags = I2C_M_RD,
302 .buf = pData + 1,
303 .len = 1
304 }
305 };
306
307 ret = i2c_transfer(state->i2c, msg, 2);
308 if (ret < 0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300309 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300310 }
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -0300311 if (fe->ops.i2c_gate_ctrl)
312 fe->ops.i2c_gate_ctrl(fe, 0);
313
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -0300314 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300315}
316
Mauro Carvalho Chehabe930b3a2011-07-21 03:02:16 -0300317/*
318 * FIXME: Is this really needed?
319 */
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300320static int MT2063_Sleep(struct dvb_frontend *fe)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300321{
322 /*
323 ** ToDo: Add code here to implement a OS blocking
324 ** for a period of "nMinDelayTime" milliseconds.
325 */
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300326 msleep(10);
327
328 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300329}
330
Mauro Carvalho Chehabe930b3a2011-07-21 03:02:16 -0300331/*
332 * Microtune spur avoidance
333 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300334
335/* Implement ceiling, floor functions. */
336#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300337#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300338
339struct MT2063_FIFZone_t {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300340 s32 min_;
341 s32 max_;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300342};
343
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300344static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t
345 *pAS_Info,
346 struct MT2063_ExclZone_t *pPrevNode)
347{
348 struct MT2063_ExclZone_t *pNode;
349 /* Check for a node in the free list */
350 if (pAS_Info->freeZones != NULL) {
351 /* Use one from the free list */
352 pNode = pAS_Info->freeZones;
353 pAS_Info->freeZones = pNode->next_;
354 } else {
355 /* Grab a node from the array */
356 pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones];
357 }
358
359 if (pPrevNode != NULL) {
360 pNode->next_ = pPrevNode->next_;
361 pPrevNode->next_ = pNode;
362 } else { /* insert at the beginning of the list */
363
364 pNode->next_ = pAS_Info->usedZones;
365 pAS_Info->usedZones = pNode;
366 }
367
368 pAS_Info->nZones++;
369 return pNode;
370}
371
372static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t
373 *pAS_Info,
374 struct MT2063_ExclZone_t *pPrevNode,
375 struct MT2063_ExclZone_t
376 *pNodeToRemove)
377{
378 struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_;
379
380 /* Make previous node point to the subsequent node */
381 if (pPrevNode != NULL)
382 pPrevNode->next_ = pNext;
383
384 /* Add pNodeToRemove to the beginning of the freeZones */
385 pNodeToRemove->next_ = pAS_Info->freeZones;
386 pAS_Info->freeZones = pNodeToRemove;
387
388 /* Decrement node count */
389 pAS_Info->nZones--;
390
391 return pNext;
392}
393
394/*****************************************************************************
395**
396** Name: MT_AddExclZone
397**
398** Description: Add (and merge) an exclusion zone into the list.
399** If the range (f_min, f_max) is totally outside the
400** 1st IF BW, ignore the entry.
401** If the range (f_min, f_max) is negative, ignore the entry.
402**
403** Revision History:
404**
405** SCR Date Author Description
406** -------------------------------------------------------------------------
407** 103 01-31-2005 DAD Ver 1.14: In MT_AddExclZone(), if the range
408** (f_min, f_max) < 0, ignore the entry.
409**
410*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300411static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -0300412 u32 f_min, u32 f_max)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300413{
414 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
415 struct MT2063_ExclZone_t *pPrev = NULL;
416 struct MT2063_ExclZone_t *pNext = NULL;
417
418 /* Check to see if this overlaps the 1st IF filter */
419 if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2)))
420 && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2)))
421 && (f_min < f_max)) {
422 /*
423 ** 1 2 3 4 5 6
424 **
425 ** New entry: |---| |--| |--| |-| |---| |--|
426 ** or or or or or
427 ** Existing: |--| |--| |--| |---| |-| |--|
428 */
429
430 /* Check for our place in the list */
431 while ((pNode != NULL) && (pNode->max_ < f_min)) {
432 pPrev = pNode;
433 pNode = pNode->next_;
434 }
435
436 if ((pNode != NULL) && (pNode->min_ < f_max)) {
437 /* Combine me with pNode */
438 if (f_min < pNode->min_)
439 pNode->min_ = f_min;
440 if (f_max > pNode->max_)
441 pNode->max_ = f_max;
442 } else {
443 pNode = InsertNode(pAS_Info, pPrev);
444 pNode->min_ = f_min;
445 pNode->max_ = f_max;
446 }
447
448 /* Look for merging possibilities */
449 pNext = pNode->next_;
450 while ((pNext != NULL) && (pNext->min_ < pNode->max_)) {
451 if (pNext->max_ > pNode->max_)
452 pNode->max_ = pNext->max_;
453 pNext = RemoveNode(pAS_Info, pNode, pNext); /* Remove pNext, return ptr to pNext->next */
454 }
455 }
456}
457
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300458/*
459** Reset all exclusion zones.
460** Add zones to protect the PLL FracN regions near zero
461**
462** N/A I 06-17-2008 RSK Ver 1.19: Refactoring avoidance of DECT
463** frequencies into MT_ResetExclZones().
464*/
465static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info)
466{
467 u32 center;
468
469 pAS_Info->nZones = 0; /* this clears the used list */
470 pAS_Info->usedZones = NULL; /* reset ptr */
471 pAS_Info->freeZones = NULL; /* reset ptr */
472
473 center =
474 pAS_Info->f_ref *
475 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 +
476 pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in;
477 while (center <
478 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
479 pAS_Info->f_LO1_FracN_Avoid) {
480 /* Exclude LO1 FracN */
481 MT2063_AddExclZone(pAS_Info,
482 center - pAS_Info->f_LO1_FracN_Avoid,
483 center - 1);
484 MT2063_AddExclZone(pAS_Info, center + 1,
485 center + pAS_Info->f_LO1_FracN_Avoid);
486 center += pAS_Info->f_ref;
487 }
488
489 center =
490 pAS_Info->f_ref *
491 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 -
492 pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out;
493 while (center <
494 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
495 pAS_Info->f_LO2_FracN_Avoid) {
496 /* Exclude LO2 FracN */
497 MT2063_AddExclZone(pAS_Info,
498 center - pAS_Info->f_LO2_FracN_Avoid,
499 center - 1);
500 MT2063_AddExclZone(pAS_Info, center + 1,
501 center + pAS_Info->f_LO2_FracN_Avoid);
502 center += pAS_Info->f_ref;
503 }
504
505 if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
506 /* Exclude LO1 values that conflict with DECT channels */
507 MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */
508 MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */
509 MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */
510 MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */
511 MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */
512 }
513
514 if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
515 MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */
516 MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */
517 MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */
518 MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */
519 MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */
520 MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */
521 MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */
522 MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */
523 MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */
524 MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */
525 }
526}
527
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300528/*****************************************************************************
529**
530** Name: MT_ChooseFirstIF
531**
532** Description: Choose the best available 1st IF
533** If f_Desired is not excluded, choose that first.
534** Otherwise, return the value closest to f_Center that is
535** not excluded
536**
537** Revision History:
538**
539** SCR Date Author Description
540** -------------------------------------------------------------------------
541** 117 03-29-2007 RSK Ver 1.15: Re-wrote to match search order from
542** tuner DLL.
543** 147 07-27-2007 RSK Ver 1.17: Corrected calculation (-) to (+)
544** Added logic to force f_Center within 1/2 f_Step.
545**
546*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300547static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300548{
549 /*
550 ** Update "f_Desired" to be the nearest "combinational-multiple" of "f_LO1_Step".
551 ** The resulting number, F_LO1 must be a multiple of f_LO1_Step. And F_LO1 is the arithmetic sum
552 ** of f_in + f_Center. Neither f_in, nor f_Center must be a multiple of f_LO1_Step.
553 ** However, the sum must be.
554 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300555 const u32 f_Desired =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300556 pAS_Info->f_LO1_Step *
557 ((pAS_Info->f_if1_Request + pAS_Info->f_in +
558 pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) -
559 pAS_Info->f_in;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300560 const u32 f_Step =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300561 (pAS_Info->f_LO1_Step >
562 pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info->
563 f_LO2_Step;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300564 u32 f_Center;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300565
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300566 s32 i;
567 s32 j = 0;
568 u32 bDesiredExcluded = 0;
569 u32 bZeroExcluded = 0;
570 s32 tmpMin, tmpMax;
571 s32 bestDiff;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300572 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
573 struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES];
574
575 if (pAS_Info->nZones == 0)
576 return f_Desired;
577
578 /* f_Center needs to be an integer multiple of f_Step away from f_Desired */
579 if (pAS_Info->f_if1_Center > f_Desired)
580 f_Center =
581 f_Desired +
582 f_Step *
583 ((pAS_Info->f_if1_Center - f_Desired +
584 f_Step / 2) / f_Step);
585 else
586 f_Center =
587 f_Desired -
588 f_Step *
589 ((f_Desired - pAS_Info->f_if1_Center +
590 f_Step / 2) / f_Step);
591
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300592 /* Take MT_ExclZones, center around f_Center and change the resolution to f_Step */
593 while (pNode != NULL) {
594 /* floor function */
595 tmpMin =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300596 floor((s32) (pNode->min_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300597
598 /* ceil function */
599 tmpMax =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300600 ceil((s32) (pNode->max_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300601
602 if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired))
603 bDesiredExcluded = 1;
604
605 if ((tmpMin < 0) && (tmpMax > 0))
606 bZeroExcluded = 1;
607
608 /* See if this zone overlaps the previous */
609 if ((j > 0) && (tmpMin < zones[j - 1].max_))
610 zones[j - 1].max_ = tmpMax;
611 else {
612 /* Add new zone */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300613 zones[j].min_ = tmpMin;
614 zones[j].max_ = tmpMax;
615 j++;
616 }
617 pNode = pNode->next_;
618 }
619
620 /*
621 ** If the desired is okay, return with it
622 */
623 if (bDesiredExcluded == 0)
624 return f_Desired;
625
626 /*
627 ** If the desired is excluded and the center is okay, return with it
628 */
629 if (bZeroExcluded == 0)
630 return f_Center;
631
632 /* Find the value closest to 0 (f_Center) */
633 bestDiff = zones[0].min_;
634 for (i = 0; i < j; i++) {
635 if (abs(zones[i].min_) < abs(bestDiff))
636 bestDiff = zones[i].min_;
637 if (abs(zones[i].max_) < abs(bestDiff))
638 bestDiff = zones[i].max_;
639 }
640
641 if (bestDiff < 0)
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300642 return f_Center - ((u32) (-bestDiff) * f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300643
644 return f_Center + (bestDiff * f_Step);
645}
646
647/****************************************************************************
648**
649** Name: gcd
650**
651** Description: Uses Euclid's algorithm
652**
653** Parameters: u, v - unsigned values whose GCD is desired.
654**
655** Global: None
656**
657** Returns: greatest common divisor of u and v, if either value
658** is 0, the other value is returned as the result.
659**
660** Dependencies: None.
661**
662** Revision History:
663**
664** SCR Date Author Description
665** -------------------------------------------------------------------------
666** N/A 06-01-2004 JWS Original
667** N/A 08-03-2004 DAD Changed to Euclid's since it can handle
668** unsigned numbers.
669**
670****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300671static u32 MT2063_gcd(u32 u, u32 v)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300672{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300673 u32 r;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300674
675 while (v != 0) {
676 r = u % v;
677 u = v;
678 v = r;
679 }
680
681 return u;
682}
683
684/****************************************************************************
685**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300686** Name: IsSpurInBand
687**
688** Description: Checks to see if a spur will be present within the IF's
689** bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW)
690**
691** ma mb mc md
692** <--+-+-+-------------------+-------------------+-+-+-->
693** | ^ 0 ^ |
694** ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^
695** a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2
696**
697** Note that some equations are doubled to prevent round-off
698** problems when calculating fIFBW/2
699**
700** Parameters: pAS_Info - Avoid Spurs information block
701** fm - If spur, amount f_IF1 has to move negative
702** fp - If spur, amount f_IF1 has to move positive
703**
704** Global: None
705**
706** Returns: 1 if an LO spur would be present, otherwise 0.
707**
708** Dependencies: None.
709**
710** Revision History:
711**
712** SCR Date Author Description
713** -------------------------------------------------------------------------
714** N/A 11-28-2002 DAD Implemented algorithm from applied patent
715**
716****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300717static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -0300718 u32 *fm, u32 * fp)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300719{
720 /*
721 ** Calculate LO frequency settings.
722 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300723 u32 n, n0;
724 const u32 f_LO1 = pAS_Info->f_LO1;
725 const u32 f_LO2 = pAS_Info->f_LO2;
726 const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2;
727 const u32 c = d - pAS_Info->f_out_bw;
728 const u32 f = pAS_Info->f_zif_bw / 2;
Mauro Carvalho Chehabd0dcc2d2011-07-21 02:30:19 -0300729 const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300730 s32 f_nsLO1, f_nsLO2;
731 s32 f_Spur;
732 u32 ma, mb, mc, md, me, mf;
733 u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300734 *fm = 0;
735
736 /*
737 ** For each edge (d, c & f), calculate a scale, based on the gcd
738 ** of f_LO1, f_LO2 and the edge value. Use the larger of this
739 ** gcd-based scale factor or f_Scale.
740 */
741 lo_gcd = MT2063_gcd(f_LO1, f_LO2);
Mauro Carvalho Chehabfd1126c2011-07-21 03:30:57 -0300742 gd_Scale = max((u32) MT2063_gcd(lo_gcd, d), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300743 hgds = gd_Scale / 2;
Mauro Carvalho Chehabfd1126c2011-07-21 03:30:57 -0300744 gc_Scale = max((u32) MT2063_gcd(lo_gcd, c), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300745 hgcs = gc_Scale / 2;
Mauro Carvalho Chehabfd1126c2011-07-21 03:30:57 -0300746 gf_Scale = max((u32) MT2063_gcd(lo_gcd, f), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300747 hgfs = gf_Scale / 2;
748
Mauro Carvalho Chehabe930b3a2011-07-21 03:02:16 -0300749 n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300750
751 /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */
752 for (n = n0; n <= pAS_Info->maxH1; ++n) {
753 md = (n * ((f_LO1 + hgds) / gd_Scale) -
754 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
755
756 /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */
757 if (md >= pAS_Info->maxH1)
758 break;
759
760 ma = (n * ((f_LO1 + hgds) / gd_Scale) +
761 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
762
763 /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */
764 if (md == ma)
765 continue;
766
767 mc = (n * ((f_LO1 + hgcs) / gc_Scale) -
768 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
769 if (mc != md) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300770 f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale));
771 f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale));
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300772 f_Spur =
773 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
774 n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale);
775
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300776 *fp = ((f_Spur - (s32) c) / (mc - n)) + 1;
777 *fm = (((s32) d - f_Spur) / (mc - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300778 return 1;
779 }
780
781 /* Location of Zero-IF-spur to be checked */
782 me = (n * ((f_LO1 + hgfs) / gf_Scale) +
783 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
784 mf = (n * ((f_LO1 + hgfs) / gf_Scale) -
785 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
786 if (me != mf) {
787 f_nsLO1 = n * (f_LO1 / gf_Scale);
788 f_nsLO2 = me * (f_LO2 / gf_Scale);
789 f_Spur =
790 (gf_Scale * (f_nsLO1 - f_nsLO2)) +
791 n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale);
792
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300793 *fp = ((f_Spur + (s32) f) / (me - n)) + 1;
794 *fm = (((s32) f - f_Spur) / (me - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300795 return 1;
796 }
797
798 mb = (n * ((f_LO1 + hgcs) / gc_Scale) +
799 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
800 if (ma != mb) {
801 f_nsLO1 = n * (f_LO1 / gc_Scale);
802 f_nsLO2 = ma * (f_LO2 / gc_Scale);
803 f_Spur =
804 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
805 n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale);
806
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300807 *fp = (((s32) d + f_Spur) / (ma - n)) + 1;
808 *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300809 return 1;
810 }
811 }
812
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300813 /* No spurs found */
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300814 return 0;
815}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300816
817/*****************************************************************************
818**
819** Name: MT_AvoidSpurs
820**
821** Description: Main entry point to avoid spurs.
822** Checks for existing spurs in present LO1, LO2 freqs
823** and if present, chooses spur-free LO1, LO2 combination
824** that tunes the same input/output frequencies.
825**
826** Revision History:
827**
828** SCR Date Author Description
829** -------------------------------------------------------------------------
830** 096 04-06-2005 DAD Ver 1.11: Fix divide by 0 error if maxH==0.
831**
832*****************************************************************************/
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -0300833static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300834{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300835 u32 status = 0;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300836 u32 fm, fp; /* restricted range on LO's */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300837 pAS_Info->bSpurAvoided = 0;
838 pAS_Info->nSpursFound = 0;
839
840 if (pAS_Info->maxH1 == 0)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300841 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300842
843 /*
844 ** Avoid LO Generated Spurs
845 **
846 ** Make sure that have no LO-related spurs within the IF output
847 ** bandwidth.
848 **
849 ** If there is an LO spur in this band, start at the current IF1 frequency
850 ** and work out until we find a spur-free frequency or run up against the
851 ** 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they
852 ** will be unchanged if a spur-free setting is not found.
853 */
854 pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
855 if (pAS_Info->bSpurPresent) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300856 u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */
857 u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */
858 u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */
859 u32 delta_IF1;
860 u32 new_IF1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300861
862 /*
863 ** Spur was found, attempt to find a spur-free 1st IF
864 */
865 do {
866 pAS_Info->nSpursFound++;
867
868 /* Raise f_IF1_upper, if needed */
869 MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp);
870
871 /* Choose next IF1 that is closest to f_IF1_CENTER */
872 new_IF1 = MT2063_ChooseFirstIF(pAS_Info);
873
874 if (new_IF1 > zfIF1) {
875 pAS_Info->f_LO1 += (new_IF1 - zfIF1);
876 pAS_Info->f_LO2 += (new_IF1 - zfIF1);
877 } else {
878 pAS_Info->f_LO1 -= (zfIF1 - new_IF1);
879 pAS_Info->f_LO2 -= (zfIF1 - new_IF1);
880 }
881 zfIF1 = new_IF1;
882
883 if (zfIF1 > pAS_Info->f_if1_Center)
884 delta_IF1 = zfIF1 - pAS_Info->f_if1_Center;
885 else
886 delta_IF1 = pAS_Info->f_if1_Center - zfIF1;
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -0300887
888 pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300889 /*
890 ** Continue while the new 1st IF is still within the 1st IF bandwidth
891 ** and there is a spur in the band (again)
892 */
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -0300893 } while ((2 * delta_IF1 + pAS_Info->f_out_bw <= pAS_Info->f_if1_bw) && pAS_Info->bSpurPresent);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300894
895 /*
896 ** Use the LO-spur free values found. If the search went all the way to
897 ** the 1st IF band edge and always found spurs, just leave the original
898 ** choice. It's as "good" as any other.
899 */
900 if (pAS_Info->bSpurPresent == 1) {
901 status |= MT2063_SPUR_PRESENT_ERR;
902 pAS_Info->f_LO1 = zfLO1;
903 pAS_Info->f_LO2 = zfLO2;
904 } else
905 pAS_Info->bSpurAvoided = 1;
906 }
907
908 status |=
909 ((pAS_Info->
910 nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK);
911
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -0300912 return status;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300913}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300914
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300915
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300916/*
Mauro Carvalho Chehab66aea302011-07-21 03:57:10 -0300917 * Constants used by the tuning algorithm
918 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300919#define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */
920#define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */
921#define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */
922#define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */
923#define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */
924#define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */
925#define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */
926#define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */
927#define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */
928#define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */
929#define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */
930#define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */
931#define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */
932#define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */
933#define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */
934#define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */
935#define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */
936#define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */
937
938/*
939** Define the supported Part/Rev codes for the MT2063
940*/
941#define MT2063_B0 (0x9B)
942#define MT2063_B1 (0x9C)
943#define MT2063_B2 (0x9D)
944#define MT2063_B3 (0x9E)
945
946/*
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300947** Constants for setting receiver modes.
948** (6 modes defined at this time, enumerated by MT2063_RCVR_MODES)
949** (DNC1GC & DNC2GC are the values, which are used, when the specific
950** DNC Output is selected, the other is always off)
951**
952** If PAL-L or L' is received, set:
953** MT2063_SetParam(hMT2063,MT2063_TAGC,1);
954**
955** --------------+----------------------------------------------
956** Mode 0 : | MT2063_CABLE_QAM
957** Mode 1 : | MT2063_CABLE_ANALOG
958** Mode 2 : | MT2063_OFFAIR_COFDM
959** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
960** Mode 4 : | MT2063_OFFAIR_ANALOG
961** Mode 5 : | MT2063_OFFAIR_8VSB
962** --------------+----+----+----+----+-----+-----+--------------
963** Mode | 0 | 1 | 2 | 3 | 4 | 5 |
964** --------------+----+----+----+----+-----+-----+
965**
966**
967*/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300968static const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 };
969static const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 };
970static const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 };
971static const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 };
972static const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 };
973static const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 };
974static const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 };
975static const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 };
976static const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
977static const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 };
978static const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 };
979static const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
980static const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 };
981static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 };
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300982
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -0300983/**
984 * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked
985 *
986 * @state: struct mt2063_state pointer
987 *
988 * This function returns 0, if no lock, 1 if locked and a value < 1 if error
989 */
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -0300990static unsigned int mt2063_lockStatus(struct mt2063_state *state)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300991{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300992 const u32 nMaxWait = 100; /* wait a maximum of 100 msec */
993 const u32 nPollRate = 2; /* poll status bits every 2 ms */
994 const u32 nMaxLoops = nMaxWait / nPollRate;
995 const u8 LO1LK = 0x80;
996 u8 LO2LK = 0x08;
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -0300997 u32 status;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300998 u32 nDelays = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300999
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001000 /* LO2 Lock bit was in a different place for B0 version */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001001 if (state->tuner_id == MT2063_B0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001002 LO2LK = 0x40;
1003
1004 do {
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001005 status = mt2063_read(state, MT2063_REG_LO_STATUS,
1006 &state->reg[MT2063_REG_LO_STATUS], 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001007
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001008 if (status < 0)
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001009 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001010
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001011 if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) ==
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001012 (LO1LK | LO2LK)) {
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001013 return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001014 }
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001015 msleep(nPollRate); /* Wait between retries */
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001016 } while (++nDelays < nMaxLoops);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001017
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001018 /*
1019 * Got no lock or partial lock
1020 */
1021 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001022}
1023
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001024/*
1025 * mt2063_set_dnc_output_enable()
1026 */
1027static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state,
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001028 enum MT2063_DNC_Output_Enable *pValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001029{
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001030 if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */
1031 if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
1032 *pValue = MT2063_DNC_NONE;
1033 else
1034 *pValue = MT2063_DNC_2;
1035 } else { /* DNC1 is on */
1036 if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
1037 *pValue = MT2063_DNC_1;
1038 else
1039 *pValue = MT2063_DNC_BOTH;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001040 }
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001041 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001042}
1043
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001044/*
1045 * mt2063_set_dnc_output_enable()
1046 */
1047static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state,
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001048 enum MT2063_DNC_Output_Enable nValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001049{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001050 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001051 u8 val = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001052
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001053 /* selects, which DNC output is used */
1054 switch (nValue) {
1055 case MT2063_DNC_NONE:
1056 {
1057 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
1058 if (state->reg[MT2063_REG_DNC_GAIN] !=
1059 val)
1060 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001061 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001062 MT2063_REG_DNC_GAIN,
1063 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001064
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001065 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
1066 if (state->reg[MT2063_REG_VGA_GAIN] !=
1067 val)
1068 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001069 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001070 MT2063_REG_VGA_GAIN,
1071 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001072
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001073 val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
1074 if (state->reg[MT2063_REG_RSVD_20] !=
1075 val)
1076 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001077 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001078 MT2063_REG_RSVD_20,
1079 val);
1080
1081 break;
1082 }
1083 case MT2063_DNC_1:
1084 {
1085 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */
1086 if (state->reg[MT2063_REG_DNC_GAIN] !=
1087 val)
1088 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001089 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001090 MT2063_REG_DNC_GAIN,
1091 val);
1092
1093 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
1094 if (state->reg[MT2063_REG_VGA_GAIN] !=
1095 val)
1096 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001097 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001098 MT2063_REG_VGA_GAIN,
1099 val);
1100
1101 val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
1102 if (state->reg[MT2063_REG_RSVD_20] !=
1103 val)
1104 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001105 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001106 MT2063_REG_RSVD_20,
1107 val);
1108
1109 break;
1110 }
1111 case MT2063_DNC_2:
1112 {
1113 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
1114 if (state->reg[MT2063_REG_DNC_GAIN] !=
1115 val)
1116 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001117 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001118 MT2063_REG_DNC_GAIN,
1119 val);
1120
1121 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */
1122 if (state->reg[MT2063_REG_VGA_GAIN] !=
1123 val)
1124 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001125 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001126 MT2063_REG_VGA_GAIN,
1127 val);
1128
1129 val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
1130 if (state->reg[MT2063_REG_RSVD_20] !=
1131 val)
1132 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001133 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001134 MT2063_REG_RSVD_20,
1135 val);
1136
1137 break;
1138 }
1139 case MT2063_DNC_BOTH:
1140 {
1141 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */
1142 if (state->reg[MT2063_REG_DNC_GAIN] !=
1143 val)
1144 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001145 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001146 MT2063_REG_DNC_GAIN,
1147 val);
1148
1149 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */
1150 if (state->reg[MT2063_REG_VGA_GAIN] !=
1151 val)
1152 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001153 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001154 MT2063_REG_VGA_GAIN,
1155 val);
1156
1157 val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
1158 if (state->reg[MT2063_REG_RSVD_20] !=
1159 val)
1160 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001161 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001162 MT2063_REG_RSVD_20,
1163 val);
1164
1165 break;
1166 }
1167 default:
1168 break;
1169 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001170
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001171 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001172}
1173
1174/******************************************************************************
1175**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001176** Name: MT2063_SetReceiverMode
1177**
1178** Description: Set the MT2063 receiver mode
1179**
1180** --------------+----------------------------------------------
1181** Mode 0 : | MT2063_CABLE_QAM
1182** Mode 1 : | MT2063_CABLE_ANALOG
1183** Mode 2 : | MT2063_OFFAIR_COFDM
1184** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
1185** Mode 4 : | MT2063_OFFAIR_ANALOG
1186** Mode 5 : | MT2063_OFFAIR_8VSB
1187** --------------+----+----+----+----+-----+--------------------
1188** (DNC1GC & DNC2GC are the values, which are used, when the specific
1189** DNC Output is selected, the other is always off)
1190**
1191** |<---------- Mode -------------->|
1192** Reg Field | 0 | 1 | 2 | 3 | 4 | 5 |
1193** ------------+-----+-----+-----+-----+-----+-----+
1194** RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF
1195** LNARin | 0 | 0 | 3 | 3 | 3 | 3
1196** FIFFQen | 1 | 1 | 1 | 1 | 1 | 1
1197** FIFFq | 0 | 0 | 0 | 0 | 0 | 0
1198** DNC1gc | 0 | 0 | 0 | 0 | 0 | 0
1199** DNC2gc | 0 | 0 | 0 | 0 | 0 | 0
1200** GCU Auto | 1 | 1 | 1 | 1 | 1 | 1
1201** LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31
1202** LNA Target | 44 | 43 | 43 | 43 | 43 | 43
1203** ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0
1204** RF max Atn | 31 | 31 | 31 | 31 | 31 | 31
1205** PD1 Target | 36 | 36 | 38 | 38 | 36 | 38
1206** ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0
1207** FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5
1208** PD2 Target | 40 | 33 | 42 | 42 | 33 | 42
1209**
1210**
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001211** Parameters: state - ptr to mt2063_state structure
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001212** Mode - desired reciever mode
1213**
1214** Usage: status = MT2063_SetReceiverMode(hMT2063, Mode);
1215**
1216** Returns: status:
1217** MT_OK - No errors
1218** MT_COMM_ERR - Serial bus communications error
1219**
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001220** Dependencies: mt2063_setreg - Write a byte of data to a HW register.
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001221** Assumes that the tuner cache is valid.
1222**
1223** Revision History:
1224**
1225** SCR Date Author Description
1226** -------------------------------------------------------------------------
1227** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1228** N/A 01-10-2007 PINZ Added additional GCU Settings, FIFF Calib will be triggered
1229** 155 10-01-2007 DAD Ver 1.06: Add receiver mode for SECAM positive
1230** modulation
1231** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
1232** N/A 10-22-2007 PINZ Ver 1.07: Changed some Registers at init to have
1233** the same settings as with MT Launcher
1234** N/A 10-30-2007 PINZ Add SetParam VGAGC & VGAOI
1235** Add SetParam DNC_OUTPUT_ENABLE
1236** Removed VGAGC from receiver mode,
1237** default now 1
1238** N/A 10-31-2007 PINZ Ver 1.08: Add SetParam TAGC, removed from rcvr-mode
1239** Add SetParam AMPGC, removed from rcvr-mode
1240** Corrected names of GCU values
1241** reorganized receiver modes, removed,
1242** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
1243** Actualized Receiver-Mode values
1244** N/A 11-12-2007 PINZ Ver 1.09: Actualized Receiver-Mode values
1245** N/A 11-27-2007 PINZ Improved buffered writing
1246** 01-03-2008 PINZ Ver 1.10: Added a trigger of BYPATNUP for
1247** correct wakeup of the LNA after shutdown
1248** Set AFCsd = 1 as default
1249** Changed CAP1sel default
1250** 01-14-2008 PINZ Ver 1.11: Updated gain settings
1251** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
1252** Split SetParam up to ACLNA / ACLNA_MAX
1253** removed ACLNA_INRC/DECR (+RF & FIF)
1254** removed GCUAUTO / BYPATNDN/UP
1255**
1256******************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001257static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001258 enum MT2063_RCVR_MODES Mode)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001259{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001260 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001261 u8 val;
1262 u32 longval;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001263
1264 if (Mode >= MT2063_NUM_RCVR_MODES)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001265 status = -ERANGE;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001266
1267 /* RFAGCen */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001268 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001269 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001270 (state->
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001271 reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001272 ? 0x40 :
1273 0x00);
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001274 if (state->reg[MT2063_REG_PD1_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001275 status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001276 }
1277
1278 /* LNARin */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001279 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001280 u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001281 (LNARIN[Mode] & 0x03);
1282 if (state->reg[MT2063_REG_CTRL_2C] != val)
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001283 status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001284 }
1285
1286 /* FIFFQEN and FIFFQ */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001287 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001288 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001289 (state->
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001290 reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001291 (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001292 if (state->reg[MT2063_REG_FIFF_CTRL2] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001293 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001294 mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001295 /* trigger FIFF calibration, needed after changing FIFFQ */
1296 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001297 (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001298 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001299 mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001300 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001301 (state->
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001302 reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001303 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001304 mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001305 }
1306 }
1307
1308 /* DNC1GC & DNC2GC */
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001309 status |= mt2063_get_dnc_output_enable(state, &longval);
1310 status |= mt2063_set_dnc_output_enable(state, longval);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001311
1312 /* acLNAmax */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001313 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001314 u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001315 (ACLNAMAX[Mode] & 0x1F);
1316 if (state->reg[MT2063_REG_LNA_OV] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001317 status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001318 }
1319
1320 /* LNATGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001321 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001322 u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001323 (LNATGT[Mode] & 0x3F);
1324 if (state->reg[MT2063_REG_LNA_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001325 status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001326 }
1327
1328 /* ACRF */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001329 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001330 u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) |
1331 (ACRFMAX[Mode] & 0x1F);
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001332 if (state->reg[MT2063_REG_RF_OV] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001333 status |= mt2063_setreg(state, MT2063_REG_RF_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001334 }
1335
1336 /* PD1TGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001337 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001338 u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001339 (PD1TGT[Mode] & 0x3F);
1340 if (state->reg[MT2063_REG_PD1_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001341 status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001342 }
1343
1344 /* FIFATN */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001345 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001346 u8 val = ACFIFMAX[Mode];
1347 if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5)
1348 val = 5;
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001349 val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001350 (val & 0x1F);
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001351 if (state->reg[MT2063_REG_FIF_OV] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001352 status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001353 }
1354
1355 /* PD2TGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001356 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001357 u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001358 (PD2TGT[Mode] & 0x3F);
1359 if (state->reg[MT2063_REG_PD2_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001360 status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001361 }
1362
1363 /* Ignore ATN Overload */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001364 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001365 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) |
1366 (RFOVDIS[Mode] ? 0x80 : 0x00);
1367 if (state->reg[MT2063_REG_LNA_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001368 status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001369 }
1370
1371 /* Ignore FIF Overload */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001372 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001373 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) |
1374 (FIFOVDIS[Mode] ? 0x80 : 0x00);
1375 if (state->reg[MT2063_REG_PD1_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001376 status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001377 }
1378
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001379 if (status >= 0)
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001380 state->rcvr_mode = Mode;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001381
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001382 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001383}
1384
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001385/****************************************************************************
1386**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001387** Name: MT2063_ClearPowerMaskBits
1388**
1389** Description: Clears the power-down mask bits for various sections of
1390** the MT2063
1391**
1392** Parameters: h - Tuner handle (returned by MT2063_Open)
1393** Bits - Mask bits to be cleared.
1394**
1395** See definition of MT2063_Mask_Bits type for description
1396** of each of the power bits.
1397**
1398** Returns: status:
1399** MT_OK - No errors
1400** MT_INV_HANDLE - Invalid tuner handle
1401** MT_COMM_ERR - Serial bus communications error
1402**
1403** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
1404**
1405** Revision History:
1406**
1407** SCR Date Author Description
1408** -------------------------------------------------------------------------
1409** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1410**
1411****************************************************************************/
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001412static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state,
1413 enum MT2063_Mask_Bits Bits)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001414{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001415 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001416
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001417 Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */
1418 if ((Bits & 0xFF00) != 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001419 state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001420 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001421 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001422 MT2063_REG_PWR_2,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001423 &state->reg[MT2063_REG_PWR_2], 1);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001424 }
1425 if ((Bits & 0xFF) != 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001426 state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001427 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001428 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001429 MT2063_REG_PWR_1,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001430 &state->reg[MT2063_REG_PWR_1], 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001431 }
1432
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001433 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001434}
1435
1436/****************************************************************************
1437**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001438** Name: MT2063_SoftwareShutdown
1439**
1440** Description: Enables or disables software shutdown function. When
1441** Shutdown==1, any section whose power mask is set will be
1442** shutdown.
1443**
1444** Parameters: h - Tuner handle (returned by MT2063_Open)
1445** Shutdown - 1 = shutdown the masked sections, otherwise
1446** power all sections on
1447**
1448** Returns: status:
1449** MT_OK - No errors
1450** MT_INV_HANDLE - Invalid tuner handle
1451** MT_COMM_ERR - Serial bus communications error
1452**
1453** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
1454**
1455** Revision History:
1456**
1457** SCR Date Author Description
1458** -------------------------------------------------------------------------
1459** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1460** 01-03-2008 PINZ Ver 1.xx: Added a trigger of BYPATNUP for
1461** correct wakeup of the LNA
1462**
1463****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001464static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001465{
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001466 u32 status; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001467
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001468 if (Shutdown == 1)
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001469 state->reg[MT2063_REG_PWR_1] |= 0x04; /* Turn the bit on */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001470 else
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001471 state->reg[MT2063_REG_PWR_1] &= ~0x04; /* Turn off the bit */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001472
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001473 status = mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001474 MT2063_REG_PWR_1,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001475 &state->reg[MT2063_REG_PWR_1], 1);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001476
1477 if (Shutdown != 1) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001478 state->reg[MT2063_REG_BYP_CTRL] =
1479 (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001480 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001481 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001482 MT2063_REG_BYP_CTRL,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001483 &state->reg[MT2063_REG_BYP_CTRL],
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001484 1);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001485 state->reg[MT2063_REG_BYP_CTRL] =
1486 (state->reg[MT2063_REG_BYP_CTRL] & 0x9F);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001487 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001488 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001489 MT2063_REG_BYP_CTRL,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001490 &state->reg[MT2063_REG_BYP_CTRL],
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001491 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001492 }
1493
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001494 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001495}
1496
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001497static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001498{
1499 return f_ref * (f_LO / f_ref)
1500 + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step);
1501}
1502
1503/****************************************************************************
1504**
1505** Name: fLO_FractionalTerm
1506**
1507** Description: Calculates the portion contributed by FracN / denom.
1508**
1509** This function preserves maximum precision without
1510** risk of overflow. It accurately calculates
1511** f_ref * num / denom to within 1 HZ with fixed math.
1512**
1513** Parameters: num - Fractional portion of the multiplier
1514** denom - denominator portion of the ratio
1515** This routine successfully handles denom values
1516** up to and including 2^18.
1517** f_Ref - SRO frequency. This calculation handles
1518** f_ref as two separate 14-bit fields.
1519** Therefore, a maximum value of 2^28-1
1520** may safely be used for f_ref. This is
1521** the genesis of the magic number "14" and the
1522** magic mask value of 0x03FFF.
1523**
1524** Returns: f_ref * num / denom
1525**
1526** Revision History:
1527**
1528** SCR Date Author Description
1529** -------------------------------------------------------------------------
1530** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1531**
1532****************************************************************************/
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001533static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001534{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001535 u32 t1 = (f_ref >> 14) * num;
1536 u32 term1 = t1 / denom;
1537 u32 loss = t1 % denom;
1538 u32 term2 =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001539 (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom;
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001540 return (term1 << 14) + term2;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001541}
1542
1543/****************************************************************************
1544**
1545** Name: CalcLO1Mult
1546**
1547** Description: Calculates Integer divider value and the numerator
1548** value for a FracN PLL.
1549**
1550** This function assumes that the f_LO and f_Ref are
1551** evenly divisible by f_LO_Step.
1552**
1553** Parameters: Div - OUTPUT: Whole number portion of the multiplier
1554** FracN - OUTPUT: Fractional portion of the multiplier
1555** f_LO - desired LO frequency.
1556** f_LO_Step - Minimum step size for the LO (in Hz).
1557** f_Ref - SRO frequency.
1558** f_Avoid - Range of PLL frequencies to avoid near
1559** integer multiples of f_Ref (in Hz).
1560**
1561** Returns: Recalculated LO frequency.
1562**
1563** Revision History:
1564**
1565** SCR Date Author Description
1566** -------------------------------------------------------------------------
1567** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1568**
1569****************************************************************************/
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001570static u32 MT2063_CalcLO1Mult(u32 *Div,
1571 u32 *FracN,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001572 u32 f_LO,
1573 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001574{
1575 /* Calculate the whole number portion of the divider */
1576 *Div = f_LO / f_Ref;
1577
1578 /* Calculate the numerator value (round to nearest f_LO_Step) */
1579 *FracN =
1580 (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
1581 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
1582
1583 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64);
1584}
1585
1586/****************************************************************************
1587**
1588** Name: CalcLO2Mult
1589**
1590** Description: Calculates Integer divider value and the numerator
1591** value for a FracN PLL.
1592**
1593** This function assumes that the f_LO and f_Ref are
1594** evenly divisible by f_LO_Step.
1595**
1596** Parameters: Div - OUTPUT: Whole number portion of the multiplier
1597** FracN - OUTPUT: Fractional portion of the multiplier
1598** f_LO - desired LO frequency.
1599** f_LO_Step - Minimum step size for the LO (in Hz).
1600** f_Ref - SRO frequency.
1601** f_Avoid - Range of PLL frequencies to avoid near
1602** integer multiples of f_Ref (in Hz).
1603**
1604** Returns: Recalculated LO frequency.
1605**
1606** Revision History:
1607**
1608** SCR Date Author Description
1609** -------------------------------------------------------------------------
1610** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1611**
1612****************************************************************************/
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001613static u32 MT2063_CalcLO2Mult(u32 *Div,
1614 u32 *FracN,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001615 u32 f_LO,
1616 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001617{
1618 /* Calculate the whole number portion of the divider */
1619 *Div = f_LO / f_Ref;
1620
1621 /* Calculate the numerator value (round to nearest f_LO_Step) */
1622 *FracN =
1623 (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
1624 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
1625
1626 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN,
1627 8191);
1628}
1629
1630/****************************************************************************
1631**
1632** Name: FindClearTuneFilter
1633**
1634** Description: Calculate the corrrect ClearTune filter to be used for
1635** a given input frequency.
1636**
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001637** Parameters: state - ptr to tuner data structure
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001638** f_in - RF input center frequency (in Hz).
1639**
1640** Returns: ClearTune filter number (0-31)
1641**
1642** Dependencies: MUST CALL MT2064_Open BEFORE FindClearTuneFilter!
1643**
1644** Revision History:
1645**
1646** SCR Date Author Description
1647** -------------------------------------------------------------------------
1648** 04-10-2008 PINZ Ver 1.14: Use software-controlled ClearTune
1649** cross-over frequency values.
1650**
1651****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001652static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001653{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001654 u32 RFBand;
1655 u32 idx; /* index loop */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001656
1657 /*
1658 ** Find RF Band setting
1659 */
1660 RFBand = 31; /* def when f_in > all */
1661 for (idx = 0; idx < 31; ++idx) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001662 if (state->CTFiltMax[idx] >= f_in) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001663 RFBand = idx;
1664 break;
1665 }
1666 }
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001667 return RFBand;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001668}
1669
1670/****************************************************************************
1671**
1672** Name: MT2063_Tune
1673**
1674** Description: Change the tuner's tuned frequency to RFin.
1675**
1676** Parameters: h - Open handle to the tuner (from MT2063_Open).
1677** f_in - RF input center frequency (in Hz).
1678**
1679** Returns: status:
1680** MT_OK - No errors
1681** MT_INV_HANDLE - Invalid tuner handle
1682** MT_UPC_UNLOCK - Upconverter PLL unlocked
1683** MT_DNC_UNLOCK - Downconverter PLL unlocked
1684** MT_COMM_ERR - Serial bus communications error
1685** MT_SPUR_CNT_MASK - Count of avoided LO spurs
1686** MT_SPUR_PRESENT - LO spur possible in output
1687** MT_FIN_RANGE - Input freq out of range
1688** MT_FOUT_RANGE - Output freq out of range
1689** MT_UPC_RANGE - Upconverter freq out of range
1690** MT_DNC_RANGE - Downconverter freq out of range
1691**
1692** Dependencies: MUST CALL MT2063_Open BEFORE MT2063_Tune!
1693**
1694** MT_ReadSub - Read data from the two-wire serial bus
1695** MT_WriteSub - Write data to the two-wire serial bus
1696** MT_Sleep - Delay execution for x milliseconds
1697** MT2063_GetLocked - Checks to see if LO1 and LO2 are locked
1698**
1699** Revision History:
1700**
1701** SCR Date Author Description
1702** -------------------------------------------------------------------------
1703** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1704** 04-10-2008 PINZ Ver 1.05: Use software-controlled ClearTune
1705** cross-over frequency values.
1706** 175 I 16-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
1707** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
1708** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
1709**
1710****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001711static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001712{ /* RF input center frequency */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001713
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001714 u32 status = 0; /* status of operation */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001715 u32 LO1; /* 1st LO register value */
1716 u32 Num1; /* Numerator for LO1 reg. value */
1717 u32 f_IF1; /* 1st IF requested */
1718 u32 LO2; /* 2nd LO register value */
1719 u32 Num2; /* Numerator for LO2 reg. value */
1720 u32 ofLO1, ofLO2; /* last time's LO frequencies */
1721 u32 ofin, ofout; /* last time's I/O frequencies */
1722 u8 fiffc = 0x80; /* FIFF center freq from tuner */
1723 u32 fiffof; /* Offset from FIFF center freq */
1724 const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */
1725 u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */
1726 u8 val;
1727 u32 RFBand;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001728
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001729 /* Check the input and output frequency ranges */
1730 if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ))
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001731 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001732
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001733 if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ)
1734 || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ))
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001735 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001736
1737 /*
1738 ** Save original LO1 and LO2 register values
1739 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001740 ofLO1 = state->AS_Data.f_LO1;
1741 ofLO2 = state->AS_Data.f_LO2;
1742 ofin = state->AS_Data.f_in;
1743 ofout = state->AS_Data.f_out;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001744
1745 /*
1746 ** Find and set RF Band setting
1747 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001748 if (state->ctfilt_sw == 1) {
1749 val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08);
1750 if (state->reg[MT2063_REG_CTUNE_CTRL] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001751 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001752 mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001753 }
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001754 val = state->reg[MT2063_REG_CTUNE_OV];
1755 RFBand = FindClearTuneFilter(state, f_in);
1756 state->reg[MT2063_REG_CTUNE_OV] =
1757 (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001758 | RFBand);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001759 if (state->reg[MT2063_REG_CTUNE_OV] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001760 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001761 mt2063_setreg(state, MT2063_REG_CTUNE_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001762 }
1763 }
1764
1765 /*
1766 ** Read the FIFF Center Frequency from the tuner
1767 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001768 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001769 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001770 mt2063_read(state,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001771 MT2063_REG_FIFFC,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001772 &state->reg[MT2063_REG_FIFFC], 1);
1773 fiffc = state->reg[MT2063_REG_FIFFC];
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001774 }
1775 /*
1776 ** Assign in the requested values
1777 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001778 state->AS_Data.f_in = f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001779 /* Request a 1st IF such that LO1 is on a step size */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001780 state->AS_Data.f_if1_Request =
1781 MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in,
1782 state->AS_Data.f_LO1_Step,
1783 state->AS_Data.f_ref) - f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001784
1785 /*
1786 ** Calculate frequency settings. f_IF1_FREQ + f_in is the
1787 ** desired LO1 frequency
1788 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001789 MT2063_ResetExclZones(&state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001790
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001791 f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001792
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001793 state->AS_Data.f_LO1 =
1794 MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step,
1795 state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001796
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001797 state->AS_Data.f_LO2 =
1798 MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
1799 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001800
1801 /*
1802 ** Check for any LO spurs in the output bandwidth and adjust
1803 ** the LO settings to avoid them if needed
1804 */
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001805 status |= MT2063_AvoidSpurs(&state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001806 /*
1807 ** MT_AvoidSpurs spurs may have changed the LO1 & LO2 values.
1808 ** Recalculate the LO frequencies and the values to be placed
1809 ** in the tuning registers.
1810 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001811 state->AS_Data.f_LO1 =
1812 MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1,
1813 state->AS_Data.f_LO1_Step, state->AS_Data.f_ref);
1814 state->AS_Data.f_LO2 =
1815 MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
1816 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
1817 state->AS_Data.f_LO2 =
1818 MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2,
1819 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001820
1821 /*
1822 ** Check the upconverter and downconverter frequency ranges
1823 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001824 if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ)
1825 || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001826 status |= MT2063_UPC_RANGE;
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001827 if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ)
1828 || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001829 status |= MT2063_DNC_RANGE;
1830 /* LO2 Lock bit was in a different place for B0 version */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001831 if (state->tuner_id == MT2063_B0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001832 LO2LK = 0x40;
1833
1834 /*
1835 ** If we have the same LO frequencies and we're already locked,
1836 ** then skip re-programming the LO registers.
1837 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001838 if ((ofLO1 != state->AS_Data.f_LO1)
1839 || (ofLO2 != state->AS_Data.f_LO2)
1840 || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) !=
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001841 (LO1LK | LO2LK))) {
1842 /*
1843 ** Calculate the FIFFOF register value
1844 **
1845 ** IF1_Actual
1846 ** FIFFOF = ------------ - 8 * FIFFC - 4992
1847 ** f_ref/64
1848 */
1849 fiffof =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001850 (state->AS_Data.f_LO1 -
1851 f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc -
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001852 4992;
1853 if (fiffof > 0xFF)
1854 fiffof = 0xFF;
1855
1856 /*
1857 ** Place all of the calculated values into the local tuner
1858 ** register fields.
1859 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001860 if (status >= 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001861 state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */
1862 state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */
1863 state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001864 |(Num2 >> 12)); /* NUM2q (hi) */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001865 state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */
1866 state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001867
1868 /*
1869 ** Now write out the computed register values
1870 ** IMPORTANT: There is a required order for writing
1871 ** (0x05 must follow all the others).
1872 */
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001873 status |= mt2063_write(state, MT2063_REG_LO1CQ_1, &state->reg[MT2063_REG_LO1CQ_1], 5); /* 0x01 - 0x05 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001874 if (state->tuner_id == MT2063_B0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001875 /* Re-write the one-shot bits to trigger the tune operation */
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001876 status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001877 }
1878 /* Write out the FIFF offset only if it's changing */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001879 if (state->reg[MT2063_REG_FIFF_OFFSET] !=
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001880 (u8) fiffof) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001881 state->reg[MT2063_REG_FIFF_OFFSET] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001882 (u8) fiffof;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001883 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001884 mt2063_write(state,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001885 MT2063_REG_FIFF_OFFSET,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001886 &state->
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001887 reg[MT2063_REG_FIFF_OFFSET],
1888 1);
1889 }
1890 }
1891
1892 /*
1893 ** Check for LO's locking
1894 */
1895
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001896 if (status < 0)
1897 return status;
1898
1899 status = mt2063_lockStatus(state);
1900 if (status < 0)
1901 return status;
1902 if (!status)
1903 return -EINVAL; /* Couldn't lock */
1904
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001905 /*
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001906 * If we locked OK, assign calculated data to mt2063_state structure
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001907 */
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001908 state->f_IF1_actual = state->AS_Data.f_LO1 - f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001909 }
1910
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001911 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001912}
1913
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001914static const u8 MT2063B0_defaults[] = {
1915 /* Reg, Value */
1916 0x19, 0x05,
1917 0x1B, 0x1D,
1918 0x1C, 0x1F,
1919 0x1D, 0x0F,
1920 0x1E, 0x3F,
1921 0x1F, 0x0F,
1922 0x20, 0x3F,
1923 0x22, 0x21,
1924 0x23, 0x3F,
1925 0x24, 0x20,
1926 0x25, 0x3F,
1927 0x27, 0xEE,
1928 0x2C, 0x27, /* bit at 0x20 is cleared below */
1929 0x30, 0x03,
1930 0x2C, 0x07, /* bit at 0x20 is cleared here */
1931 0x2D, 0x87,
1932 0x2E, 0xAA,
1933 0x28, 0xE1, /* Set the FIFCrst bit here */
1934 0x28, 0xE0, /* Clear the FIFCrst bit here */
1935 0x00
1936};
1937
1938/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
1939static const u8 MT2063B1_defaults[] = {
1940 /* Reg, Value */
1941 0x05, 0xF0,
1942 0x11, 0x10, /* New Enable AFCsd */
1943 0x19, 0x05,
1944 0x1A, 0x6C,
1945 0x1B, 0x24,
1946 0x1C, 0x28,
1947 0x1D, 0x8F,
1948 0x1E, 0x14,
1949 0x1F, 0x8F,
1950 0x20, 0x57,
1951 0x22, 0x21, /* New - ver 1.03 */
1952 0x23, 0x3C, /* New - ver 1.10 */
1953 0x24, 0x20, /* New - ver 1.03 */
1954 0x2C, 0x24, /* bit at 0x20 is cleared below */
1955 0x2D, 0x87, /* FIFFQ=0 */
1956 0x2F, 0xF3,
1957 0x30, 0x0C, /* New - ver 1.11 */
1958 0x31, 0x1B, /* New - ver 1.11 */
1959 0x2C, 0x04, /* bit at 0x20 is cleared here */
1960 0x28, 0xE1, /* Set the FIFCrst bit here */
1961 0x28, 0xE0, /* Clear the FIFCrst bit here */
1962 0x00
1963};
1964
1965/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
1966static const u8 MT2063B3_defaults[] = {
1967 /* Reg, Value */
1968 0x05, 0xF0,
1969 0x19, 0x3D,
1970 0x2C, 0x24, /* bit at 0x20 is cleared below */
1971 0x2C, 0x04, /* bit at 0x20 is cleared here */
1972 0x28, 0xE1, /* Set the FIFCrst bit here */
1973 0x28, 0xE0, /* Clear the FIFCrst bit here */
1974 0x00
1975};
1976
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001977static int mt2063_init(struct dvb_frontend *fe)
1978{
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001979 u32 status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001980 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001981 u8 all_resets = 0xF0; /* reset/load bits */
1982 const u8 *def = NULL;
1983 u32 FCRUN;
1984 s32 maxReads;
1985 u32 fcu_osc;
1986 u32 i;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001987
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001988 state->rcvr_mode = MT2063_CABLE_QAM;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001989
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001990 /* Read the Part/Rev code from the tuner */
1991 status = mt2063_read(state, MT2063_REG_PART_REV, state->reg, 1);
1992 if (status < 0)
1993 return status;
1994
1995 /* Check the part/rev code */
1996 if (((state->reg[MT2063_REG_PART_REV] != MT2063_B0) /* MT2063 B0 */
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001997 && (state->reg[MT2063_REG_PART_REV] != MT2063_B1) /* MT2063 B1 */
1998 && (state->reg[MT2063_REG_PART_REV] != MT2063_B3))) /* MT2063 B3 */
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001999 return -ENODEV; /* Wrong tuner Part/Rev code */
2000
2001 /* Check the 2nd byte of the Part/Rev code from the tuner */
2002 status = mt2063_read(state, MT2063_REG_RSVD_3B,
2003 &state->reg[MT2063_REG_RSVD_3B], 1);
2004
2005 /* b7 != 0 ==> NOT MT2063 */
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03002006 if (status < 0 || ((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00))
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002007 return -ENODEV; /* Wrong tuner Part/Rev code */
2008
2009 /* Reset the tuner */
2010 status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1);
2011 if (status < 0)
2012 return status;
2013
2014 /* change all of the default values that vary from the HW reset values */
2015 /* def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */
2016 switch (state->reg[MT2063_REG_PART_REV]) {
2017 case MT2063_B3:
2018 def = MT2063B3_defaults;
2019 break;
2020
2021 case MT2063_B1:
2022 def = MT2063B1_defaults;
2023 break;
2024
2025 case MT2063_B0:
2026 def = MT2063B0_defaults;
2027 break;
2028
2029 default:
2030 return -ENODEV;
2031 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002032 }
2033
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002034 while (status >= 0 && *def) {
2035 u8 reg = *def++;
2036 u8 val = *def++;
2037 status = mt2063_write(state, reg, &val, 1);
2038 }
2039 if (status < 0)
2040 return status;
2041
2042 /* Wait for FIFF location to complete. */
2043 FCRUN = 1;
2044 maxReads = 10;
2045 while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) {
2046 msleep(2);
2047 status = mt2063_read(state,
2048 MT2063_REG_XO_STATUS,
2049 &state->
2050 reg[MT2063_REG_XO_STATUS], 1);
2051 FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6;
2052 }
2053
2054 if (FCRUN != 0 || status < 0)
2055 return -ENODEV;
2056
2057 status = mt2063_read(state,
2058 MT2063_REG_FIFFC,
2059 &state->reg[MT2063_REG_FIFFC], 1);
2060 if (status < 0)
2061 return status;
2062
2063 /* Read back all the registers from the tuner */
2064 status = mt2063_read(state,
2065 MT2063_REG_PART_REV,
2066 state->reg, MT2063_REG_END_REGS);
2067 if (status < 0)
2068 return status;
2069
2070 /* Initialize the tuner state. */
2071 state->tuner_id = state->reg[MT2063_REG_PART_REV];
2072 state->AS_Data.f_ref = MT2063_REF_FREQ;
2073 state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) *
2074 ((u32) state->reg[MT2063_REG_FIFFC] + 640);
2075 state->AS_Data.f_if1_bw = MT2063_IF1_BW;
2076 state->AS_Data.f_out = 43750000UL;
2077 state->AS_Data.f_out_bw = 6750000UL;
2078 state->AS_Data.f_zif_bw = MT2063_ZIF_BW;
2079 state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64;
2080 state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE;
2081 state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1;
2082 state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2;
2083 state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP;
2084 state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center;
2085 state->AS_Data.f_LO1 = 2181000000UL;
2086 state->AS_Data.f_LO2 = 1486249786UL;
2087 state->f_IF1_actual = state->AS_Data.f_if1_Center;
2088 state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual;
2089 state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID;
2090 state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID;
2091 state->num_regs = MT2063_REG_END_REGS;
2092 state->AS_Data.avoidDECT = MT2063_AVOID_BOTH;
2093 state->ctfilt_sw = 0;
2094
2095 state->CTFiltMax[0] = 69230000;
2096 state->CTFiltMax[1] = 105770000;
2097 state->CTFiltMax[2] = 140350000;
2098 state->CTFiltMax[3] = 177110000;
2099 state->CTFiltMax[4] = 212860000;
2100 state->CTFiltMax[5] = 241130000;
2101 state->CTFiltMax[6] = 274370000;
2102 state->CTFiltMax[7] = 309820000;
2103 state->CTFiltMax[8] = 342450000;
2104 state->CTFiltMax[9] = 378870000;
2105 state->CTFiltMax[10] = 416210000;
2106 state->CTFiltMax[11] = 456500000;
2107 state->CTFiltMax[12] = 495790000;
2108 state->CTFiltMax[13] = 534530000;
2109 state->CTFiltMax[14] = 572610000;
2110 state->CTFiltMax[15] = 598970000;
2111 state->CTFiltMax[16] = 635910000;
2112 state->CTFiltMax[17] = 672130000;
2113 state->CTFiltMax[18] = 714840000;
2114 state->CTFiltMax[19] = 739660000;
2115 state->CTFiltMax[20] = 770410000;
2116 state->CTFiltMax[21] = 814660000;
2117 state->CTFiltMax[22] = 846950000;
2118 state->CTFiltMax[23] = 867820000;
2119 state->CTFiltMax[24] = 915980000;
2120 state->CTFiltMax[25] = 947450000;
2121 state->CTFiltMax[26] = 983110000;
2122 state->CTFiltMax[27] = 1021630000;
2123 state->CTFiltMax[28] = 1061870000;
2124 state->CTFiltMax[29] = 1098330000;
2125 state->CTFiltMax[30] = 1138990000;
2126
2127 /*
2128 ** Fetch the FCU osc value and use it and the fRef value to
2129 ** scale all of the Band Max values
2130 */
2131
2132 state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A;
2133 status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
2134 &state->reg[MT2063_REG_CTUNE_CTRL], 1);
2135 if (status < 0)
2136 return status;
2137
2138 /* Read the ClearTune filter calibration value */
2139 status = mt2063_read(state, MT2063_REG_FIFFC,
2140 &state->reg[MT2063_REG_FIFFC], 1);
2141 if (status < 0)
2142 return status;
2143
2144 fcu_osc = state->reg[MT2063_REG_FIFFC];
2145
2146 state->reg[MT2063_REG_CTUNE_CTRL] = 0x00;
2147 status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
2148 &state->reg[MT2063_REG_CTUNE_CTRL], 1);
2149 if (status < 0)
2150 return status;
2151
2152 /* Adjust each of the values in the ClearTune filter cross-over table */
2153 for (i = 0; i < 31; i++)
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03002154 state->CTFiltMax[i] = (state->CTFiltMax[i] / 768) * (fcu_osc + 640);
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002155
2156 status = MT2063_SoftwareShutdown(state, 1);
2157 if (status < 0)
2158 return status;
2159 status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
2160 if (status < 0)
2161 return status;
2162
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002163 return 0;
2164}
2165
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002166static int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002167{
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002168 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002169 int status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002170
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002171 *tuner_status = 0;
2172 status = mt2063_lockStatus(state);
2173 if (status < 0)
2174 return status;
2175 if (status)
2176 *tuner_status = TUNER_STATUS_LOCKED;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002177
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002178 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002179}
2180
2181static int mt2063_release(struct dvb_frontend *fe)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002182{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002183 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002184
2185 fe->tuner_priv = NULL;
2186 kfree(state);
2187
2188 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002189}
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002190
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002191static int mt2063_set_analog_params(struct dvb_frontend *fe,
2192 struct analog_parameters *params)
2193{
2194 struct mt2063_state *state = fe->tuner_priv;
2195 s32 pict_car = 0;
2196 s32 pict2chanb_vsb = 0;
2197 s32 pict2chanb_snd = 0;
2198 s32 pict2snd1 = 0;
2199 s32 pict2snd2 = 0;
2200 s32 ch_bw = 0;
2201 s32 if_mid = 0;
2202 s32 rcvr_mode = 0;
2203 int status;
2204
2205 switch (params->mode) {
2206 case V4L2_TUNER_RADIO:
2207 pict_car = 38900000;
2208 ch_bw = 8000000;
2209 pict2chanb_vsb = -(ch_bw / 2);
2210 pict2snd1 = 0;
2211 pict2snd2 = 0;
2212 rcvr_mode = MT2063_OFFAIR_ANALOG;
2213 break;
2214 case V4L2_TUNER_ANALOG_TV:
2215 rcvr_mode = MT2063_CABLE_ANALOG;
2216 if (params->std & ~V4L2_STD_MN) {
2217 pict_car = 38900000;
2218 ch_bw = 6000000;
2219 pict2chanb_vsb = -1250000;
2220 pict2snd1 = 4500000;
2221 pict2snd2 = 0;
2222 } else if (params->std & V4L2_STD_PAL_I) {
2223 pict_car = 38900000;
2224 ch_bw = 8000000;
2225 pict2chanb_vsb = -1250000;
2226 pict2snd1 = 6000000;
2227 pict2snd2 = 0;
2228 } else if (params->std & V4L2_STD_PAL_B) {
2229 pict_car = 38900000;
2230 ch_bw = 8000000;
2231 pict2chanb_vsb = -1250000;
2232 pict2snd1 = 5500000;
2233 pict2snd2 = 5742000;
2234 } else if (params->std & V4L2_STD_PAL_G) {
2235 pict_car = 38900000;
2236 ch_bw = 7000000;
2237 pict2chanb_vsb = -1250000;
2238 pict2snd1 = 5500000;
2239 pict2snd2 = 0;
2240 } else if (params->std & V4L2_STD_PAL_DK) {
2241 pict_car = 38900000;
2242 ch_bw = 8000000;
2243 pict2chanb_vsb = -1250000;
2244 pict2snd1 = 6500000;
2245 pict2snd2 = 0;
2246 } else { /* PAL-L */
2247 pict_car = 38900000;
2248 ch_bw = 8000000;
2249 pict2chanb_vsb = -1250000;
2250 pict2snd1 = 6500000;
2251 pict2snd2 = 0;
2252 }
2253 break;
2254 }
2255 pict2chanb_snd = pict2chanb_vsb - ch_bw;
2256 if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
2257
2258 state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */
2259 state->AS_Data.f_out = if_mid;
2260 state->AS_Data.f_out_bw = ch_bw + 750000;
2261 status = MT2063_SetReceiverMode(state, rcvr_mode);
2262 if (status < 0)
2263 return status;
2264
2265 status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2))));
2266 if (status < 0)
2267 return status;
2268
2269 state->frequency = params->frequency;
2270 return 0;
2271}
2272
2273/*
2274 * As defined on EN 300 429, the DVB-C roll-off factor is 0.15.
2275 * So, the amount of the needed bandwith is given by:
2276 * Bw = Symbol_rate * (1 + 0.15)
2277 * As such, the maximum symbol rate supported by 6 MHz is given by:
2278 * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
2279 */
2280#define MAX_SYMBOL_RATE_6MHz 5217391
2281
2282static int mt2063_set_params(struct dvb_frontend *fe,
2283 struct dvb_frontend_parameters *params)
2284{
2285 struct mt2063_state *state = fe->tuner_priv;
2286 int status;
2287 s32 pict_car = 0;
2288 s32 pict2chanb_vsb = 0;
2289 s32 pict2chanb_snd = 0;
2290 s32 pict2snd1 = 0;
2291 s32 pict2snd2 = 0;
2292 s32 ch_bw = 0;
2293 s32 if_mid = 0;
2294 s32 rcvr_mode = 0;
2295
2296 switch (fe->ops.info.type) {
2297 case FE_OFDM:
2298 switch (params->u.ofdm.bandwidth) {
2299 case BANDWIDTH_6_MHZ:
2300 ch_bw = 6000000;
2301 break;
2302 case BANDWIDTH_7_MHZ:
2303 ch_bw = 7000000;
2304 break;
2305 case BANDWIDTH_8_MHZ:
2306 ch_bw = 8000000;
2307 break;
2308 default:
2309 return -EINVAL;
2310 }
2311 rcvr_mode = MT2063_OFFAIR_COFDM;
2312 pict_car = 36125000;
2313 pict2chanb_vsb = -(ch_bw / 2);
2314 pict2snd1 = 0;
2315 pict2snd2 = 0;
2316 break;
2317 case FE_QAM:
2318 /*
2319 * Using a 8MHz bandwidth sometimes fail
2320 * with 6MHz-spaced channels, due to inter-carrier
2321 * interference. So, it is better to narrow-down the filter
2322 */
2323 if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz)
2324 ch_bw = 6000000;
2325 else
2326 ch_bw = 8000000;
2327 rcvr_mode = MT2063_CABLE_QAM;
2328 pict_car = 36125000;
2329 pict2snd1 = 0;
2330 pict2snd2 = 0;
2331 pict2chanb_vsb = -(ch_bw / 2);
2332 break;
2333 default:
2334 return -EINVAL;
2335 }
2336 pict2chanb_snd = pict2chanb_vsb - ch_bw;
2337 if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
2338
2339 state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */
2340 state->AS_Data.f_out = if_mid;
2341 state->AS_Data.f_out_bw = ch_bw + 750000;
2342 status = MT2063_SetReceiverMode(state, rcvr_mode);
2343 if (status < 0)
2344 return status;
2345
2346 status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2))));
2347
2348 if (status < 0)
2349 return status;
2350
2351 state->frequency = params->frequency;
2352 return 0;
2353}
2354
2355static int mt2063_get_frequency(struct dvb_frontend *fe, u32 *freq)
2356{
2357 struct mt2063_state *state = fe->tuner_priv;
2358
2359 *freq = state->frequency;
2360 return 0;
2361}
2362
2363static int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
2364{
2365 struct mt2063_state *state = fe->tuner_priv;
2366
2367 *bw = state->AS_Data.f_out_bw - 750000;
2368 return 0;
2369}
2370
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002371static struct dvb_tuner_ops mt2063_ops = {
2372 .info = {
2373 .name = "MT2063 Silicon Tuner",
2374 .frequency_min = 45000000,
2375 .frequency_max = 850000000,
2376 .frequency_step = 0,
2377 },
2378
2379 .init = mt2063_init,
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002380 .sleep = MT2063_Sleep,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002381 .get_status = mt2063_get_status,
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002382 .set_analog_params = mt2063_set_analog_params,
2383 .set_params = mt2063_set_params,
2384 .get_frequency = mt2063_get_frequency,
2385 .get_bandwidth = mt2063_get_bandwidth,
2386 .release = mt2063_release,
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002387};
2388
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002389struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
2390 struct mt2063_config *config,
2391 struct i2c_adapter *i2c)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002392{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002393 struct mt2063_state *state = NULL;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002394
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002395 state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002396 if (state == NULL)
2397 goto error;
2398
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002399 state->config = config;
2400 state->i2c = i2c;
2401 state->frontend = fe;
2402 state->reference = config->refclock / 1000; /* kHz */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002403 fe->tuner_priv = state;
2404 fe->ops.tuner_ops = mt2063_ops;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002405
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03002406 printk(KERN_INFO "%s: Attaching MT2063\n", __func__);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002407 return fe;
2408
2409error:
2410 kfree(state);
2411 return NULL;
2412}
Mauro Carvalho Chehab3d497002011-07-21 11:00:59 -03002413EXPORT_SYMBOL_GPL(mt2063_attach);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002414
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03002415/*
2416 * Ancillary routines visible outside mt2063
2417 * FIXME: Remove them in favor of using standard tuner callbacks
2418 */
2419unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe)
2420{
2421 struct mt2063_state *state = fe->tuner_priv;
2422 int err = 0;
2423
2424 err = MT2063_SoftwareShutdown(state, 1);
2425 if (err < 0)
2426 printk(KERN_ERR "%s: Couldn't shutdown\n", __func__);
2427
2428 return err;
2429}
2430EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown);
2431
2432unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe)
2433{
2434 struct mt2063_state *state = fe->tuner_priv;
2435 int err = 0;
2436
2437 err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
2438 if (err < 0)
2439 printk(KERN_ERR "%s: Invalid parameter\n", __func__);
2440
2441 return err;
2442}
2443EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits);
2444
2445
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002446MODULE_PARM_DESC(verbose, "Set Verbosity level");
2447
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002448MODULE_AUTHOR("Henry");
2449MODULE_DESCRIPTION("MT2063 Silicon tuner");
2450MODULE_LICENSE("GPL");