blob: 5154b9d08384622e841f6ac130c51f2efddf81ec [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 Chehab0e301442011-07-20 19:52:49 -03005
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03006#include "mt2063.h"
7
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03008static unsigned int verbose;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03009module_param(verbose, int, 0644);
10
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -030011/* positive error codes used internally */
Mauro Carvalho Chehab29a0a4f2011-07-20 23:44:10 -030012
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -030013/* Info: Unavoidable LO-related spur may be present in the output */
Mauro Carvalho Chehab29a0a4f2011-07-20 23:44:10 -030014#define MT2063_SPUR_PRESENT_ERR (0x00800000)
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030015
16/* Info: Mask of bits used for # of LO-related spurs that were avoided during tuning */
17#define MT2063_SPUR_CNT_MASK (0x001f0000)
18#define MT2063_SPUR_SHIFT (16)
19
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030020/* Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */
21#define MT2063_UPC_RANGE (0x04000000)
22
23/* Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */
24#define MT2063_DNC_RANGE (0x08000000)
25
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030026/*
27 * Constant defining the version of the following structure
28 * and therefore the API for this code.
29 *
30 * When compiling the tuner driver, the preprocessor will
31 * check against this version number to make sure that
32 * it matches the version that the tuner driver knows about.
33 */
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030034
35/* DECT Frequency Avoidance */
36#define MT2063_DECT_AVOID_US_FREQS 0x00000001
37
38#define MT2063_DECT_AVOID_EURO_FREQS 0x00000002
39
40#define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0)
41
42#define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0)
43
44enum MT2063_DECT_Avoid_Type {
45 MT2063_NO_DECT_AVOIDANCE = 0, /* Do not create DECT exclusion zones. */
46 MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS, /* Avoid US DECT frequencies. */
47 MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS, /* Avoid European DECT frequencies. */
48 MT2063_AVOID_BOTH /* Avoid both regions. Not typically used. */
49};
50
51#define MT2063_MAX_ZONES 48
52
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030053struct MT2063_ExclZone_t {
54 u32 min_;
55 u32 max_;
56 struct MT2063_ExclZone_t *next_;
57};
58
59/*
60 * Structure of data needed for Spur Avoidance
61 */
62struct MT2063_AvoidSpursData_t {
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030063 u32 f_ref;
64 u32 f_in;
65 u32 f_LO1;
66 u32 f_if1_Center;
67 u32 f_if1_Request;
68 u32 f_if1_bw;
69 u32 f_LO2;
70 u32 f_out;
71 u32 f_out_bw;
72 u32 f_LO1_Step;
73 u32 f_LO2_Step;
74 u32 f_LO1_FracN_Avoid;
75 u32 f_LO2_FracN_Avoid;
76 u32 f_zif_bw;
77 u32 f_min_LO_Separation;
78 u32 maxH1;
79 u32 maxH2;
80 enum MT2063_DECT_Avoid_Type avoidDECT;
81 u32 bSpurPresent;
82 u32 bSpurAvoided;
83 u32 nSpursFound;
84 u32 nZones;
85 struct MT2063_ExclZone_t *freeZones;
86 struct MT2063_ExclZone_t *usedZones;
87 struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES];
88};
89
90/*
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030091 * Parameter for function MT2063_SetPowerMask that specifies the power down
92 * of various sections of the MT2063.
93 */
94enum MT2063_Mask_Bits {
95 MT2063_REG_SD = 0x0040, /* Shutdown regulator */
96 MT2063_SRO_SD = 0x0020, /* Shutdown SRO */
97 MT2063_AFC_SD = 0x0010, /* Shutdown AFC A/D */
98 MT2063_PD_SD = 0x0002, /* Enable power detector shutdown */
99 MT2063_PDADC_SD = 0x0001, /* Enable power detector A/D shutdown */
100 MT2063_VCO_SD = 0x8000, /* Enable VCO shutdown */
101 MT2063_LTX_SD = 0x4000, /* Enable LTX shutdown */
102 MT2063_LT1_SD = 0x2000, /* Enable LT1 shutdown */
103 MT2063_LNA_SD = 0x1000, /* Enable LNA shutdown */
104 MT2063_UPC_SD = 0x0800, /* Enable upconverter shutdown */
105 MT2063_DNC_SD = 0x0400, /* Enable downconverter shutdown */
106 MT2063_VGA_SD = 0x0200, /* Enable VGA shutdown */
107 MT2063_AMP_SD = 0x0100, /* Enable AMP shutdown */
108 MT2063_ALL_SD = 0xFF73, /* All shutdown bits for this tuner */
109 MT2063_NONE_SD = 0x0000 /* No shutdown bits */
110};
111
112/*
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300113 * Parameter for selecting tuner mode
114 */
115enum MT2063_RCVR_MODES {
116 MT2063_CABLE_QAM = 0, /* Digital cable */
117 MT2063_CABLE_ANALOG, /* Analog cable */
118 MT2063_OFFAIR_COFDM, /* Digital offair */
119 MT2063_OFFAIR_COFDM_SAWLESS, /* Digital offair without SAW */
120 MT2063_OFFAIR_ANALOG, /* Analog offair */
121 MT2063_OFFAIR_8VSB, /* Analog offair */
122 MT2063_NUM_RCVR_MODES
123};
124
125/*
126 * Possible values for MT2063_DNC_OUTPUT
127 */
128enum MT2063_DNC_Output_Enable {
129 MT2063_DNC_NONE = 0,
130 MT2063_DNC_1,
131 MT2063_DNC_2,
132 MT2063_DNC_BOTH
133};
134
135/*
136** Two-wire serial bus subaddresses of the tuner registers.
137** Also known as the tuner's register addresses.
138*/
139enum MT2063_Register_Offsets {
140 MT2063_REG_PART_REV = 0, /* 0x00: Part/Rev Code */
141 MT2063_REG_LO1CQ_1, /* 0x01: LO1C Queued Byte 1 */
142 MT2063_REG_LO1CQ_2, /* 0x02: LO1C Queued Byte 2 */
143 MT2063_REG_LO2CQ_1, /* 0x03: LO2C Queued Byte 1 */
144 MT2063_REG_LO2CQ_2, /* 0x04: LO2C Queued Byte 2 */
145 MT2063_REG_LO2CQ_3, /* 0x05: LO2C Queued Byte 3 */
146 MT2063_REG_RSVD_06, /* 0x06: Reserved */
147 MT2063_REG_LO_STATUS, /* 0x07: LO Status */
148 MT2063_REG_FIFFC, /* 0x08: FIFF Center */
149 MT2063_REG_CLEARTUNE, /* 0x09: ClearTune Filter */
150 MT2063_REG_ADC_OUT, /* 0x0A: ADC_OUT */
151 MT2063_REG_LO1C_1, /* 0x0B: LO1C Byte 1 */
152 MT2063_REG_LO1C_2, /* 0x0C: LO1C Byte 2 */
153 MT2063_REG_LO2C_1, /* 0x0D: LO2C Byte 1 */
154 MT2063_REG_LO2C_2, /* 0x0E: LO2C Byte 2 */
155 MT2063_REG_LO2C_3, /* 0x0F: LO2C Byte 3 */
156 MT2063_REG_RSVD_10, /* 0x10: Reserved */
157 MT2063_REG_PWR_1, /* 0x11: PWR Byte 1 */
158 MT2063_REG_PWR_2, /* 0x12: PWR Byte 2 */
159 MT2063_REG_TEMP_STATUS, /* 0x13: Temp Status */
160 MT2063_REG_XO_STATUS, /* 0x14: Crystal Status */
161 MT2063_REG_RF_STATUS, /* 0x15: RF Attn Status */
162 MT2063_REG_FIF_STATUS, /* 0x16: FIF Attn Status */
163 MT2063_REG_LNA_OV, /* 0x17: LNA Attn Override */
164 MT2063_REG_RF_OV, /* 0x18: RF Attn Override */
165 MT2063_REG_FIF_OV, /* 0x19: FIF Attn Override */
166 MT2063_REG_LNA_TGT, /* 0x1A: Reserved */
167 MT2063_REG_PD1_TGT, /* 0x1B: Pwr Det 1 Target */
168 MT2063_REG_PD2_TGT, /* 0x1C: Pwr Det 2 Target */
169 MT2063_REG_RSVD_1D, /* 0x1D: Reserved */
170 MT2063_REG_RSVD_1E, /* 0x1E: Reserved */
171 MT2063_REG_RSVD_1F, /* 0x1F: Reserved */
172 MT2063_REG_RSVD_20, /* 0x20: Reserved */
173 MT2063_REG_BYP_CTRL, /* 0x21: Bypass Control */
174 MT2063_REG_RSVD_22, /* 0x22: Reserved */
175 MT2063_REG_RSVD_23, /* 0x23: Reserved */
176 MT2063_REG_RSVD_24, /* 0x24: Reserved */
177 MT2063_REG_RSVD_25, /* 0x25: Reserved */
178 MT2063_REG_RSVD_26, /* 0x26: Reserved */
179 MT2063_REG_RSVD_27, /* 0x27: Reserved */
180 MT2063_REG_FIFF_CTRL, /* 0x28: FIFF Control */
181 MT2063_REG_FIFF_OFFSET, /* 0x29: FIFF Offset */
182 MT2063_REG_CTUNE_CTRL, /* 0x2A: Reserved */
183 MT2063_REG_CTUNE_OV, /* 0x2B: Reserved */
184 MT2063_REG_CTRL_2C, /* 0x2C: Reserved */
185 MT2063_REG_FIFF_CTRL2, /* 0x2D: Fiff Control */
186 MT2063_REG_RSVD_2E, /* 0x2E: Reserved */
187 MT2063_REG_DNC_GAIN, /* 0x2F: DNC Control */
188 MT2063_REG_VGA_GAIN, /* 0x30: VGA Gain Ctrl */
189 MT2063_REG_RSVD_31, /* 0x31: Reserved */
190 MT2063_REG_TEMP_SEL, /* 0x32: Temperature Selection */
191 MT2063_REG_RSVD_33, /* 0x33: Reserved */
192 MT2063_REG_RSVD_34, /* 0x34: Reserved */
193 MT2063_REG_RSVD_35, /* 0x35: Reserved */
194 MT2063_REG_RSVD_36, /* 0x36: Reserved */
195 MT2063_REG_RSVD_37, /* 0x37: Reserved */
196 MT2063_REG_RSVD_38, /* 0x38: Reserved */
197 MT2063_REG_RSVD_39, /* 0x39: Reserved */
198 MT2063_REG_RSVD_3A, /* 0x3A: Reserved */
199 MT2063_REG_RSVD_3B, /* 0x3B: Reserved */
200 MT2063_REG_RSVD_3C, /* 0x3C: Reserved */
201 MT2063_REG_END_REGS
202};
203
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300204enum MTTune_atv_standard {
205 MTTUNEA_UNKNOWN = 0,
206 MTTUNEA_PAL_B,
207 MTTUNEA_PAL_G,
208 MTTUNEA_PAL_I,
209 MTTUNEA_PAL_L,
210 MTTUNEA_PAL_MN,
211 MTTUNEA_PAL_DK,
212 MTTUNEA_DIGITAL,
213 MTTUNEA_FMRADIO,
214 MTTUNEA_DVBC,
215 MTTUNEA_DVBT
216};
217
218
219struct mt2063_state {
220 struct i2c_adapter *i2c;
221
222 const struct mt2063_config *config;
223 struct dvb_tuner_ops ops;
224 struct dvb_frontend *frontend;
225 struct tuner_state status;
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300226
227 enum MTTune_atv_standard tv_type;
228 u32 frequency;
229 u32 srate;
230 u32 bandwidth;
231 u32 reference;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300232
233 u32 tuner_id;
234 struct MT2063_AvoidSpursData_t AS_Data;
235 u32 f_IF1_actual;
236 u32 rcvr_mode;
237 u32 ctfilt_sw;
238 u32 CTFiltMax[31];
239 u32 num_regs;
240 u8 reg[MT2063_REG_END_REGS];
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300241};
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300242
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300243/*
244 * mt2063_write - Write data into the I2C bus
245 */
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300246static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300247{
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300248 struct dvb_frontend *fe = state->frontend;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300249 int ret;
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300250 u8 buf[60];
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300251 struct i2c_msg msg = {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300252 .addr = state->config->tuner_address,
253 .flags = 0,
254 .buf = buf,
255 .len = len + 1
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300256 };
257
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300258 msg.buf[0] = reg;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300259 memcpy(msg.buf + 1, data, len);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300260
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300261 fe->ops.i2c_gate_ctrl(fe, 1);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300262 ret = i2c_transfer(state->i2c, &msg, 1);
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300263 fe->ops.i2c_gate_ctrl(fe, 0);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300264
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300265 if (ret < 0)
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -0300266 printk(KERN_ERR "%s error ret=%d\n", __func__, ret);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300267
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300268 return ret;
269}
270
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300271/*
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300272 * mt2063_write - Write register data into the I2C bus, caching the value
273 */
274static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val)
275{
276 u32 status;
277
278 if (reg >= MT2063_REG_END_REGS)
279 return -ERANGE;
280
281 status = mt2063_write(state, reg, &val, 1);
282 if (status < 0)
283 return status;
284
285 state->reg[reg] = val;
286
287 return 0;
288}
289
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300290/*
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300291 * mt2063_read - Read data from the I2C bus
292 */
293static u32 mt2063_read(struct mt2063_state *state,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300294 u8 subAddress, u8 *pData, u32 cnt)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300295{
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300296 u32 status = 0; /* Status to be returned */
297 struct dvb_frontend *fe = state->frontend;
298 u32 i = 0;
299
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300300 fe->ops.i2c_gate_ctrl(fe, 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300301
302 for (i = 0; i < cnt; i++) {
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300303 int ret;
304 u8 b0[] = { subAddress + i };
305 struct i2c_msg msg[] = {
306 {
307 .addr = state->config->tuner_address,
308 .flags = I2C_M_RD,
309 .buf = b0,
310 .len = 1
311 }, {
312 .addr = state->config->tuner_address,
313 .flags = I2C_M_RD,
314 .buf = pData + 1,
315 .len = 1
316 }
317 };
318
319 ret = i2c_transfer(state->i2c, msg, 2);
320 if (ret < 0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300321 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300322 }
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300323 fe->ops.i2c_gate_ctrl(fe, 0);
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -0300324 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300325}
326
Mauro Carvalho Chehabe930b3a2011-07-21 03:02:16 -0300327/*
328 * FIXME: Is this really needed?
329 */
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300330static int MT2063_Sleep(struct dvb_frontend *fe)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300331{
332 /*
333 ** ToDo: Add code here to implement a OS blocking
334 ** for a period of "nMinDelayTime" milliseconds.
335 */
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300336 msleep(10);
337
338 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300339}
340
Mauro Carvalho Chehabe930b3a2011-07-21 03:02:16 -0300341/*
342 * Microtune spur avoidance
343 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300344
345/* Implement ceiling, floor functions. */
346#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300347#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300348
349struct MT2063_FIFZone_t {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300350 s32 min_;
351 s32 max_;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300352};
353
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300354static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t
355 *pAS_Info,
356 struct MT2063_ExclZone_t *pPrevNode)
357{
358 struct MT2063_ExclZone_t *pNode;
359 /* Check for a node in the free list */
360 if (pAS_Info->freeZones != NULL) {
361 /* Use one from the free list */
362 pNode = pAS_Info->freeZones;
363 pAS_Info->freeZones = pNode->next_;
364 } else {
365 /* Grab a node from the array */
366 pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones];
367 }
368
369 if (pPrevNode != NULL) {
370 pNode->next_ = pPrevNode->next_;
371 pPrevNode->next_ = pNode;
372 } else { /* insert at the beginning of the list */
373
374 pNode->next_ = pAS_Info->usedZones;
375 pAS_Info->usedZones = pNode;
376 }
377
378 pAS_Info->nZones++;
379 return pNode;
380}
381
382static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t
383 *pAS_Info,
384 struct MT2063_ExclZone_t *pPrevNode,
385 struct MT2063_ExclZone_t
386 *pNodeToRemove)
387{
388 struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_;
389
390 /* Make previous node point to the subsequent node */
391 if (pPrevNode != NULL)
392 pPrevNode->next_ = pNext;
393
394 /* Add pNodeToRemove to the beginning of the freeZones */
395 pNodeToRemove->next_ = pAS_Info->freeZones;
396 pAS_Info->freeZones = pNodeToRemove;
397
398 /* Decrement node count */
399 pAS_Info->nZones--;
400
401 return pNext;
402}
403
404/*****************************************************************************
405**
406** Name: MT_AddExclZone
407**
408** Description: Add (and merge) an exclusion zone into the list.
409** If the range (f_min, f_max) is totally outside the
410** 1st IF BW, ignore the entry.
411** If the range (f_min, f_max) is negative, ignore the entry.
412**
413** Revision History:
414**
415** SCR Date Author Description
416** -------------------------------------------------------------------------
417** 103 01-31-2005 DAD Ver 1.14: In MT_AddExclZone(), if the range
418** (f_min, f_max) < 0, ignore the entry.
419**
420*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300421static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -0300422 u32 f_min, u32 f_max)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300423{
424 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
425 struct MT2063_ExclZone_t *pPrev = NULL;
426 struct MT2063_ExclZone_t *pNext = NULL;
427
428 /* Check to see if this overlaps the 1st IF filter */
429 if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2)))
430 && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2)))
431 && (f_min < f_max)) {
432 /*
433 ** 1 2 3 4 5 6
434 **
435 ** New entry: |---| |--| |--| |-| |---| |--|
436 ** or or or or or
437 ** Existing: |--| |--| |--| |---| |-| |--|
438 */
439
440 /* Check for our place in the list */
441 while ((pNode != NULL) && (pNode->max_ < f_min)) {
442 pPrev = pNode;
443 pNode = pNode->next_;
444 }
445
446 if ((pNode != NULL) && (pNode->min_ < f_max)) {
447 /* Combine me with pNode */
448 if (f_min < pNode->min_)
449 pNode->min_ = f_min;
450 if (f_max > pNode->max_)
451 pNode->max_ = f_max;
452 } else {
453 pNode = InsertNode(pAS_Info, pPrev);
454 pNode->min_ = f_min;
455 pNode->max_ = f_max;
456 }
457
458 /* Look for merging possibilities */
459 pNext = pNode->next_;
460 while ((pNext != NULL) && (pNext->min_ < pNode->max_)) {
461 if (pNext->max_ > pNode->max_)
462 pNode->max_ = pNext->max_;
463 pNext = RemoveNode(pAS_Info, pNode, pNext); /* Remove pNext, return ptr to pNext->next */
464 }
465 }
466}
467
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300468/*
469** Reset all exclusion zones.
470** Add zones to protect the PLL FracN regions near zero
471**
472** N/A I 06-17-2008 RSK Ver 1.19: Refactoring avoidance of DECT
473** frequencies into MT_ResetExclZones().
474*/
475static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info)
476{
477 u32 center;
478
479 pAS_Info->nZones = 0; /* this clears the used list */
480 pAS_Info->usedZones = NULL; /* reset ptr */
481 pAS_Info->freeZones = NULL; /* reset ptr */
482
483 center =
484 pAS_Info->f_ref *
485 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 +
486 pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in;
487 while (center <
488 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
489 pAS_Info->f_LO1_FracN_Avoid) {
490 /* Exclude LO1 FracN */
491 MT2063_AddExclZone(pAS_Info,
492 center - pAS_Info->f_LO1_FracN_Avoid,
493 center - 1);
494 MT2063_AddExclZone(pAS_Info, center + 1,
495 center + pAS_Info->f_LO1_FracN_Avoid);
496 center += pAS_Info->f_ref;
497 }
498
499 center =
500 pAS_Info->f_ref *
501 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 -
502 pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out;
503 while (center <
504 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
505 pAS_Info->f_LO2_FracN_Avoid) {
506 /* Exclude LO2 FracN */
507 MT2063_AddExclZone(pAS_Info,
508 center - pAS_Info->f_LO2_FracN_Avoid,
509 center - 1);
510 MT2063_AddExclZone(pAS_Info, center + 1,
511 center + pAS_Info->f_LO2_FracN_Avoid);
512 center += pAS_Info->f_ref;
513 }
514
515 if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
516 /* Exclude LO1 values that conflict with DECT channels */
517 MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */
518 MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */
519 MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */
520 MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */
521 MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */
522 }
523
524 if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
525 MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */
526 MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */
527 MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */
528 MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */
529 MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */
530 MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */
531 MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */
532 MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */
533 MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */
534 MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */
535 }
536}
537
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300538/*****************************************************************************
539**
540** Name: MT_ChooseFirstIF
541**
542** Description: Choose the best available 1st IF
543** If f_Desired is not excluded, choose that first.
544** Otherwise, return the value closest to f_Center that is
545** not excluded
546**
547** Revision History:
548**
549** SCR Date Author Description
550** -------------------------------------------------------------------------
551** 117 03-29-2007 RSK Ver 1.15: Re-wrote to match search order from
552** tuner DLL.
553** 147 07-27-2007 RSK Ver 1.17: Corrected calculation (-) to (+)
554** Added logic to force f_Center within 1/2 f_Step.
555**
556*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300557static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300558{
559 /*
560 ** Update "f_Desired" to be the nearest "combinational-multiple" of "f_LO1_Step".
561 ** The resulting number, F_LO1 must be a multiple of f_LO1_Step. And F_LO1 is the arithmetic sum
562 ** of f_in + f_Center. Neither f_in, nor f_Center must be a multiple of f_LO1_Step.
563 ** However, the sum must be.
564 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300565 const u32 f_Desired =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300566 pAS_Info->f_LO1_Step *
567 ((pAS_Info->f_if1_Request + pAS_Info->f_in +
568 pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) -
569 pAS_Info->f_in;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300570 const u32 f_Step =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300571 (pAS_Info->f_LO1_Step >
572 pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info->
573 f_LO2_Step;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300574 u32 f_Center;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300575
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300576 s32 i;
577 s32 j = 0;
578 u32 bDesiredExcluded = 0;
579 u32 bZeroExcluded = 0;
580 s32 tmpMin, tmpMax;
581 s32 bestDiff;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300582 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
583 struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES];
584
585 if (pAS_Info->nZones == 0)
586 return f_Desired;
587
588 /* f_Center needs to be an integer multiple of f_Step away from f_Desired */
589 if (pAS_Info->f_if1_Center > f_Desired)
590 f_Center =
591 f_Desired +
592 f_Step *
593 ((pAS_Info->f_if1_Center - f_Desired +
594 f_Step / 2) / f_Step);
595 else
596 f_Center =
597 f_Desired -
598 f_Step *
599 ((f_Desired - pAS_Info->f_if1_Center +
600 f_Step / 2) / f_Step);
601
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300602 /* Take MT_ExclZones, center around f_Center and change the resolution to f_Step */
603 while (pNode != NULL) {
604 /* floor function */
605 tmpMin =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300606 floor((s32) (pNode->min_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300607
608 /* ceil function */
609 tmpMax =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300610 ceil((s32) (pNode->max_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300611
612 if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired))
613 bDesiredExcluded = 1;
614
615 if ((tmpMin < 0) && (tmpMax > 0))
616 bZeroExcluded = 1;
617
618 /* See if this zone overlaps the previous */
619 if ((j > 0) && (tmpMin < zones[j - 1].max_))
620 zones[j - 1].max_ = tmpMax;
621 else {
622 /* Add new zone */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300623 zones[j].min_ = tmpMin;
624 zones[j].max_ = tmpMax;
625 j++;
626 }
627 pNode = pNode->next_;
628 }
629
630 /*
631 ** If the desired is okay, return with it
632 */
633 if (bDesiredExcluded == 0)
634 return f_Desired;
635
636 /*
637 ** If the desired is excluded and the center is okay, return with it
638 */
639 if (bZeroExcluded == 0)
640 return f_Center;
641
642 /* Find the value closest to 0 (f_Center) */
643 bestDiff = zones[0].min_;
644 for (i = 0; i < j; i++) {
645 if (abs(zones[i].min_) < abs(bestDiff))
646 bestDiff = zones[i].min_;
647 if (abs(zones[i].max_) < abs(bestDiff))
648 bestDiff = zones[i].max_;
649 }
650
651 if (bestDiff < 0)
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300652 return f_Center - ((u32) (-bestDiff) * f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300653
654 return f_Center + (bestDiff * f_Step);
655}
656
657/****************************************************************************
658**
659** Name: gcd
660**
661** Description: Uses Euclid's algorithm
662**
663** Parameters: u, v - unsigned values whose GCD is desired.
664**
665** Global: None
666**
667** Returns: greatest common divisor of u and v, if either value
668** is 0, the other value is returned as the result.
669**
670** Dependencies: None.
671**
672** Revision History:
673**
674** SCR Date Author Description
675** -------------------------------------------------------------------------
676** N/A 06-01-2004 JWS Original
677** N/A 08-03-2004 DAD Changed to Euclid's since it can handle
678** unsigned numbers.
679**
680****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300681static u32 MT2063_gcd(u32 u, u32 v)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300682{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300683 u32 r;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300684
685 while (v != 0) {
686 r = u % v;
687 u = v;
688 v = r;
689 }
690
691 return u;
692}
693
694/****************************************************************************
695**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300696** Name: IsSpurInBand
697**
698** Description: Checks to see if a spur will be present within the IF's
699** bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW)
700**
701** ma mb mc md
702** <--+-+-+-------------------+-------------------+-+-+-->
703** | ^ 0 ^ |
704** ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^
705** a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2
706**
707** Note that some equations are doubled to prevent round-off
708** problems when calculating fIFBW/2
709**
710** Parameters: pAS_Info - Avoid Spurs information block
711** fm - If spur, amount f_IF1 has to move negative
712** fp - If spur, amount f_IF1 has to move positive
713**
714** Global: None
715**
716** Returns: 1 if an LO spur would be present, otherwise 0.
717**
718** Dependencies: None.
719**
720** Revision History:
721**
722** SCR Date Author Description
723** -------------------------------------------------------------------------
724** N/A 11-28-2002 DAD Implemented algorithm from applied patent
725**
726****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300727static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -0300728 u32 *fm, u32 * fp)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300729{
730 /*
731 ** Calculate LO frequency settings.
732 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300733 u32 n, n0;
734 const u32 f_LO1 = pAS_Info->f_LO1;
735 const u32 f_LO2 = pAS_Info->f_LO2;
736 const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2;
737 const u32 c = d - pAS_Info->f_out_bw;
738 const u32 f = pAS_Info->f_zif_bw / 2;
Mauro Carvalho Chehabd0dcc2d2011-07-21 02:30:19 -0300739 const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300740 s32 f_nsLO1, f_nsLO2;
741 s32 f_Spur;
742 u32 ma, mb, mc, md, me, mf;
743 u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300744 *fm = 0;
745
746 /*
747 ** For each edge (d, c & f), calculate a scale, based on the gcd
748 ** of f_LO1, f_LO2 and the edge value. Use the larger of this
749 ** gcd-based scale factor or f_Scale.
750 */
751 lo_gcd = MT2063_gcd(f_LO1, f_LO2);
Mauro Carvalho Chehabfd1126c2011-07-21 03:30:57 -0300752 gd_Scale = max((u32) MT2063_gcd(lo_gcd, d), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300753 hgds = gd_Scale / 2;
Mauro Carvalho Chehabfd1126c2011-07-21 03:30:57 -0300754 gc_Scale = max((u32) MT2063_gcd(lo_gcd, c), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300755 hgcs = gc_Scale / 2;
Mauro Carvalho Chehabfd1126c2011-07-21 03:30:57 -0300756 gf_Scale = max((u32) MT2063_gcd(lo_gcd, f), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300757 hgfs = gf_Scale / 2;
758
Mauro Carvalho Chehabe930b3a2011-07-21 03:02:16 -0300759 n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300760
761 /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */
762 for (n = n0; n <= pAS_Info->maxH1; ++n) {
763 md = (n * ((f_LO1 + hgds) / gd_Scale) -
764 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
765
766 /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */
767 if (md >= pAS_Info->maxH1)
768 break;
769
770 ma = (n * ((f_LO1 + hgds) / gd_Scale) +
771 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
772
773 /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */
774 if (md == ma)
775 continue;
776
777 mc = (n * ((f_LO1 + hgcs) / gc_Scale) -
778 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
779 if (mc != md) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300780 f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale));
781 f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale));
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300782 f_Spur =
783 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
784 n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale);
785
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300786 *fp = ((f_Spur - (s32) c) / (mc - n)) + 1;
787 *fm = (((s32) d - f_Spur) / (mc - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300788 return 1;
789 }
790
791 /* Location of Zero-IF-spur to be checked */
792 me = (n * ((f_LO1 + hgfs) / gf_Scale) +
793 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
794 mf = (n * ((f_LO1 + hgfs) / gf_Scale) -
795 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
796 if (me != mf) {
797 f_nsLO1 = n * (f_LO1 / gf_Scale);
798 f_nsLO2 = me * (f_LO2 / gf_Scale);
799 f_Spur =
800 (gf_Scale * (f_nsLO1 - f_nsLO2)) +
801 n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale);
802
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300803 *fp = ((f_Spur + (s32) f) / (me - n)) + 1;
804 *fm = (((s32) f - f_Spur) / (me - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300805 return 1;
806 }
807
808 mb = (n * ((f_LO1 + hgcs) / gc_Scale) +
809 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
810 if (ma != mb) {
811 f_nsLO1 = n * (f_LO1 / gc_Scale);
812 f_nsLO2 = ma * (f_LO2 / gc_Scale);
813 f_Spur =
814 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
815 n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale);
816
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300817 *fp = (((s32) d + f_Spur) / (ma - n)) + 1;
818 *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300819 return 1;
820 }
821 }
822
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300823 /* No spurs found */
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300824 return 0;
825}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300826
827/*****************************************************************************
828**
829** Name: MT_AvoidSpurs
830**
831** Description: Main entry point to avoid spurs.
832** Checks for existing spurs in present LO1, LO2 freqs
833** and if present, chooses spur-free LO1, LO2 combination
834** that tunes the same input/output frequencies.
835**
836** Revision History:
837**
838** SCR Date Author Description
839** -------------------------------------------------------------------------
840** 096 04-06-2005 DAD Ver 1.11: Fix divide by 0 error if maxH==0.
841**
842*****************************************************************************/
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -0300843static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300844{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300845 u32 status = 0;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300846 u32 fm, fp; /* restricted range on LO's */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300847 pAS_Info->bSpurAvoided = 0;
848 pAS_Info->nSpursFound = 0;
849
850 if (pAS_Info->maxH1 == 0)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300851 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300852
853 /*
854 ** Avoid LO Generated Spurs
855 **
856 ** Make sure that have no LO-related spurs within the IF output
857 ** bandwidth.
858 **
859 ** If there is an LO spur in this band, start at the current IF1 frequency
860 ** and work out until we find a spur-free frequency or run up against the
861 ** 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they
862 ** will be unchanged if a spur-free setting is not found.
863 */
864 pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
865 if (pAS_Info->bSpurPresent) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300866 u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */
867 u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */
868 u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */
869 u32 delta_IF1;
870 u32 new_IF1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300871
872 /*
873 ** Spur was found, attempt to find a spur-free 1st IF
874 */
875 do {
876 pAS_Info->nSpursFound++;
877
878 /* Raise f_IF1_upper, if needed */
879 MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp);
880
881 /* Choose next IF1 that is closest to f_IF1_CENTER */
882 new_IF1 = MT2063_ChooseFirstIF(pAS_Info);
883
884 if (new_IF1 > zfIF1) {
885 pAS_Info->f_LO1 += (new_IF1 - zfIF1);
886 pAS_Info->f_LO2 += (new_IF1 - zfIF1);
887 } else {
888 pAS_Info->f_LO1 -= (zfIF1 - new_IF1);
889 pAS_Info->f_LO2 -= (zfIF1 - new_IF1);
890 }
891 zfIF1 = new_IF1;
892
893 if (zfIF1 > pAS_Info->f_if1_Center)
894 delta_IF1 = zfIF1 - pAS_Info->f_if1_Center;
895 else
896 delta_IF1 = pAS_Info->f_if1_Center - zfIF1;
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -0300897
898 pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300899 /*
900 ** Continue while the new 1st IF is still within the 1st IF bandwidth
901 ** and there is a spur in the band (again)
902 */
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -0300903 } 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 -0300904
905 /*
906 ** Use the LO-spur free values found. If the search went all the way to
907 ** the 1st IF band edge and always found spurs, just leave the original
908 ** choice. It's as "good" as any other.
909 */
910 if (pAS_Info->bSpurPresent == 1) {
911 status |= MT2063_SPUR_PRESENT_ERR;
912 pAS_Info->f_LO1 = zfLO1;
913 pAS_Info->f_LO2 = zfLO2;
914 } else
915 pAS_Info->bSpurAvoided = 1;
916 }
917
918 status |=
919 ((pAS_Info->
920 nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK);
921
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -0300922 return status;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300923}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300924
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300925
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300926/*
Mauro Carvalho Chehab66aea302011-07-21 03:57:10 -0300927 * Constants used by the tuning algorithm
928 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300929#define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */
930#define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */
931#define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */
932#define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */
933#define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */
934#define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */
935#define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */
936#define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */
937#define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */
938#define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */
939#define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */
940#define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */
941#define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */
942#define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */
943#define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */
944#define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */
945#define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */
946#define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */
947
948/*
949** Define the supported Part/Rev codes for the MT2063
950*/
951#define MT2063_B0 (0x9B)
952#define MT2063_B1 (0x9C)
953#define MT2063_B2 (0x9D)
954#define MT2063_B3 (0x9E)
955
956/*
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300957** Constants for setting receiver modes.
958** (6 modes defined at this time, enumerated by MT2063_RCVR_MODES)
959** (DNC1GC & DNC2GC are the values, which are used, when the specific
960** DNC Output is selected, the other is always off)
961**
962** If PAL-L or L' is received, set:
963** MT2063_SetParam(hMT2063,MT2063_TAGC,1);
964**
965** --------------+----------------------------------------------
966** Mode 0 : | MT2063_CABLE_QAM
967** Mode 1 : | MT2063_CABLE_ANALOG
968** Mode 2 : | MT2063_OFFAIR_COFDM
969** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
970** Mode 4 : | MT2063_OFFAIR_ANALOG
971** Mode 5 : | MT2063_OFFAIR_8VSB
972** --------------+----+----+----+----+-----+-----+--------------
973** Mode | 0 | 1 | 2 | 3 | 4 | 5 |
974** --------------+----+----+----+----+-----+-----+
975**
976**
977*/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300978static const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 };
979static const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 };
980static const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 };
981static const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 };
982static const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 };
983static const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 };
984static const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 };
985static const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 };
986static const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
987static const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 };
988static const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 };
989static const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
990static const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 };
991static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 };
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300992
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -0300993/**
994 * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked
995 *
996 * @state: struct mt2063_state pointer
997 *
998 * This function returns 0, if no lock, 1 if locked and a value < 1 if error
999 */
1000unsigned int mt2063_lockStatus(struct mt2063_state *state)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001001{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001002 const u32 nMaxWait = 100; /* wait a maximum of 100 msec */
1003 const u32 nPollRate = 2; /* poll status bits every 2 ms */
1004 const u32 nMaxLoops = nMaxWait / nPollRate;
1005 const u8 LO1LK = 0x80;
1006 u8 LO2LK = 0x08;
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001007 u32 status;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001008 u32 nDelays = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001009
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001010 /* LO2 Lock bit was in a different place for B0 version */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001011 if (state->tuner_id == MT2063_B0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001012 LO2LK = 0x40;
1013
1014 do {
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001015 status = mt2063_read(state, MT2063_REG_LO_STATUS,
1016 &state->reg[MT2063_REG_LO_STATUS], 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001017
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001018 if (status < 0)
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001019 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001020
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001021 if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) ==
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001022 (LO1LK | LO2LK)) {
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001023 return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001024 }
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001025 msleep(nPollRate); /* Wait between retries */
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001026 } while (++nDelays < nMaxLoops);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001027
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001028 /*
1029 * Got no lock or partial lock
1030 */
1031 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001032}
Mauro Carvalho Chehab3d497002011-07-21 11:00:59 -03001033EXPORT_SYMBOL_GPL(mt2063_lockStatus);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001034
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001035/*
1036 * mt2063_set_dnc_output_enable()
1037 */
1038static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state,
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001039 enum MT2063_DNC_Output_Enable *pValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001040{
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001041 if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */
1042 if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
1043 *pValue = MT2063_DNC_NONE;
1044 else
1045 *pValue = MT2063_DNC_2;
1046 } else { /* DNC1 is on */
1047 if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
1048 *pValue = MT2063_DNC_1;
1049 else
1050 *pValue = MT2063_DNC_BOTH;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001051 }
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001052 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001053}
1054
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001055/*
1056 * mt2063_set_dnc_output_enable()
1057 */
1058static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state,
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001059 enum MT2063_DNC_Output_Enable nValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001060{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001061 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001062 u8 val = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001063
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001064 /* selects, which DNC output is used */
1065 switch (nValue) {
1066 case MT2063_DNC_NONE:
1067 {
1068 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
1069 if (state->reg[MT2063_REG_DNC_GAIN] !=
1070 val)
1071 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001072 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001073 MT2063_REG_DNC_GAIN,
1074 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001075
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001076 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
1077 if (state->reg[MT2063_REG_VGA_GAIN] !=
1078 val)
1079 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001080 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001081 MT2063_REG_VGA_GAIN,
1082 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001083
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001084 val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
1085 if (state->reg[MT2063_REG_RSVD_20] !=
1086 val)
1087 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001088 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001089 MT2063_REG_RSVD_20,
1090 val);
1091
1092 break;
1093 }
1094 case MT2063_DNC_1:
1095 {
1096 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */
1097 if (state->reg[MT2063_REG_DNC_GAIN] !=
1098 val)
1099 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001100 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001101 MT2063_REG_DNC_GAIN,
1102 val);
1103
1104 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
1105 if (state->reg[MT2063_REG_VGA_GAIN] !=
1106 val)
1107 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001108 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001109 MT2063_REG_VGA_GAIN,
1110 val);
1111
1112 val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
1113 if (state->reg[MT2063_REG_RSVD_20] !=
1114 val)
1115 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001116 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001117 MT2063_REG_RSVD_20,
1118 val);
1119
1120 break;
1121 }
1122 case MT2063_DNC_2:
1123 {
1124 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
1125 if (state->reg[MT2063_REG_DNC_GAIN] !=
1126 val)
1127 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001128 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001129 MT2063_REG_DNC_GAIN,
1130 val);
1131
1132 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */
1133 if (state->reg[MT2063_REG_VGA_GAIN] !=
1134 val)
1135 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001136 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001137 MT2063_REG_VGA_GAIN,
1138 val);
1139
1140 val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
1141 if (state->reg[MT2063_REG_RSVD_20] !=
1142 val)
1143 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001144 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001145 MT2063_REG_RSVD_20,
1146 val);
1147
1148 break;
1149 }
1150 case MT2063_DNC_BOTH:
1151 {
1152 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */
1153 if (state->reg[MT2063_REG_DNC_GAIN] !=
1154 val)
1155 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001156 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001157 MT2063_REG_DNC_GAIN,
1158 val);
1159
1160 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */
1161 if (state->reg[MT2063_REG_VGA_GAIN] !=
1162 val)
1163 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001164 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001165 MT2063_REG_VGA_GAIN,
1166 val);
1167
1168 val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
1169 if (state->reg[MT2063_REG_RSVD_20] !=
1170 val)
1171 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001172 mt2063_setreg(state,
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001173 MT2063_REG_RSVD_20,
1174 val);
1175
1176 break;
1177 }
1178 default:
1179 break;
1180 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001181
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001182 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001183}
1184
1185/******************************************************************************
1186**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001187** Name: MT2063_SetReceiverMode
1188**
1189** Description: Set the MT2063 receiver mode
1190**
1191** --------------+----------------------------------------------
1192** Mode 0 : | MT2063_CABLE_QAM
1193** Mode 1 : | MT2063_CABLE_ANALOG
1194** Mode 2 : | MT2063_OFFAIR_COFDM
1195** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
1196** Mode 4 : | MT2063_OFFAIR_ANALOG
1197** Mode 5 : | MT2063_OFFAIR_8VSB
1198** --------------+----+----+----+----+-----+--------------------
1199** (DNC1GC & DNC2GC are the values, which are used, when the specific
1200** DNC Output is selected, the other is always off)
1201**
1202** |<---------- Mode -------------->|
1203** Reg Field | 0 | 1 | 2 | 3 | 4 | 5 |
1204** ------------+-----+-----+-----+-----+-----+-----+
1205** RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF
1206** LNARin | 0 | 0 | 3 | 3 | 3 | 3
1207** FIFFQen | 1 | 1 | 1 | 1 | 1 | 1
1208** FIFFq | 0 | 0 | 0 | 0 | 0 | 0
1209** DNC1gc | 0 | 0 | 0 | 0 | 0 | 0
1210** DNC2gc | 0 | 0 | 0 | 0 | 0 | 0
1211** GCU Auto | 1 | 1 | 1 | 1 | 1 | 1
1212** LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31
1213** LNA Target | 44 | 43 | 43 | 43 | 43 | 43
1214** ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0
1215** RF max Atn | 31 | 31 | 31 | 31 | 31 | 31
1216** PD1 Target | 36 | 36 | 38 | 38 | 36 | 38
1217** ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0
1218** FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5
1219** PD2 Target | 40 | 33 | 42 | 42 | 33 | 42
1220**
1221**
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001222** Parameters: state - ptr to mt2063_state structure
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001223** Mode - desired reciever mode
1224**
1225** Usage: status = MT2063_SetReceiverMode(hMT2063, Mode);
1226**
1227** Returns: status:
1228** MT_OK - No errors
1229** MT_COMM_ERR - Serial bus communications error
1230**
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001231** Dependencies: mt2063_setreg - Write a byte of data to a HW register.
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001232** Assumes that the tuner cache is valid.
1233**
1234** Revision History:
1235**
1236** SCR Date Author Description
1237** -------------------------------------------------------------------------
1238** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1239** N/A 01-10-2007 PINZ Added additional GCU Settings, FIFF Calib will be triggered
1240** 155 10-01-2007 DAD Ver 1.06: Add receiver mode for SECAM positive
1241** modulation
1242** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
1243** N/A 10-22-2007 PINZ Ver 1.07: Changed some Registers at init to have
1244** the same settings as with MT Launcher
1245** N/A 10-30-2007 PINZ Add SetParam VGAGC & VGAOI
1246** Add SetParam DNC_OUTPUT_ENABLE
1247** Removed VGAGC from receiver mode,
1248** default now 1
1249** N/A 10-31-2007 PINZ Ver 1.08: Add SetParam TAGC, removed from rcvr-mode
1250** Add SetParam AMPGC, removed from rcvr-mode
1251** Corrected names of GCU values
1252** reorganized receiver modes, removed,
1253** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
1254** Actualized Receiver-Mode values
1255** N/A 11-12-2007 PINZ Ver 1.09: Actualized Receiver-Mode values
1256** N/A 11-27-2007 PINZ Improved buffered writing
1257** 01-03-2008 PINZ Ver 1.10: Added a trigger of BYPATNUP for
1258** correct wakeup of the LNA after shutdown
1259** Set AFCsd = 1 as default
1260** Changed CAP1sel default
1261** 01-14-2008 PINZ Ver 1.11: Updated gain settings
1262** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
1263** Split SetParam up to ACLNA / ACLNA_MAX
1264** removed ACLNA_INRC/DECR (+RF & FIF)
1265** removed GCUAUTO / BYPATNDN/UP
1266**
1267******************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001268static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001269 enum MT2063_RCVR_MODES Mode)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001270{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001271 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001272 u8 val;
1273 u32 longval;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001274
1275 if (Mode >= MT2063_NUM_RCVR_MODES)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001276 status = -ERANGE;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001277
1278 /* RFAGCen */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001279 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001280 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001281 (state->
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001282 reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001283 ? 0x40 :
1284 0x00);
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001285 if (state->reg[MT2063_REG_PD1_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001286 status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001287 }
1288
1289 /* LNARin */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001290 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001291 u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001292 (LNARIN[Mode] & 0x03);
1293 if (state->reg[MT2063_REG_CTRL_2C] != val)
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001294 status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001295 }
1296
1297 /* FIFFQEN and FIFFQ */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001298 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001299 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001300 (state->
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001301 reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001302 (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001303 if (state->reg[MT2063_REG_FIFF_CTRL2] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001304 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001305 mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001306 /* trigger FIFF calibration, needed after changing FIFFQ */
1307 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001308 (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001309 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001310 mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001311 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001312 (state->
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001313 reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001314 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001315 mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001316 }
1317 }
1318
1319 /* DNC1GC & DNC2GC */
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001320 status |= mt2063_get_dnc_output_enable(state, &longval);
1321 status |= mt2063_set_dnc_output_enable(state, longval);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001322
1323 /* acLNAmax */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001324 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001325 u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001326 (ACLNAMAX[Mode] & 0x1F);
1327 if (state->reg[MT2063_REG_LNA_OV] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001328 status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001329 }
1330
1331 /* LNATGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001332 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001333 u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001334 (LNATGT[Mode] & 0x3F);
1335 if (state->reg[MT2063_REG_LNA_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001336 status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001337 }
1338
1339 /* ACRF */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001340 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001341 u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) |
1342 (ACRFMAX[Mode] & 0x1F);
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001343 if (state->reg[MT2063_REG_RF_OV] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001344 status |= mt2063_setreg(state, MT2063_REG_RF_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001345 }
1346
1347 /* PD1TGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001348 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001349 u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001350 (PD1TGT[Mode] & 0x3F);
1351 if (state->reg[MT2063_REG_PD1_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001352 status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001353 }
1354
1355 /* FIFATN */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001356 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001357 u8 val = ACFIFMAX[Mode];
1358 if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5)
1359 val = 5;
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001360 val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001361 (val & 0x1F);
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001362 if (state->reg[MT2063_REG_FIF_OV] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001363 status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001364 }
1365
1366 /* PD2TGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001367 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001368 u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001369 (PD2TGT[Mode] & 0x3F);
1370 if (state->reg[MT2063_REG_PD2_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001371 status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001372 }
1373
1374 /* Ignore ATN Overload */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001375 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001376 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) |
1377 (RFOVDIS[Mode] ? 0x80 : 0x00);
1378 if (state->reg[MT2063_REG_LNA_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001379 status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001380 }
1381
1382 /* Ignore FIF Overload */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001383 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001384 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) |
1385 (FIFOVDIS[Mode] ? 0x80 : 0x00);
1386 if (state->reg[MT2063_REG_PD1_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001387 status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001388 }
1389
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001390 if (status >= 0)
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001391 state->rcvr_mode = Mode;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001392
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001393 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001394}
1395
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001396/****************************************************************************
1397**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001398** Name: MT2063_ClearPowerMaskBits
1399**
1400** Description: Clears the power-down mask bits for various sections of
1401** the MT2063
1402**
1403** Parameters: h - Tuner handle (returned by MT2063_Open)
1404** Bits - Mask bits to be cleared.
1405**
1406** See definition of MT2063_Mask_Bits type for description
1407** of each of the power bits.
1408**
1409** Returns: status:
1410** MT_OK - No errors
1411** MT_INV_HANDLE - Invalid tuner handle
1412** MT_COMM_ERR - Serial bus communications error
1413**
1414** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
1415**
1416** Revision History:
1417**
1418** SCR Date Author Description
1419** -------------------------------------------------------------------------
1420** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1421**
1422****************************************************************************/
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001423static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state,
1424 enum MT2063_Mask_Bits Bits)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001425{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001426 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001427
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001428 Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */
1429 if ((Bits & 0xFF00) != 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001430 state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001431 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001432 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001433 MT2063_REG_PWR_2,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001434 &state->reg[MT2063_REG_PWR_2], 1);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001435 }
1436 if ((Bits & 0xFF) != 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001437 state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001438 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001439 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001440 MT2063_REG_PWR_1,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001441 &state->reg[MT2063_REG_PWR_1], 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001442 }
1443
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001444 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001445}
1446
1447/****************************************************************************
1448**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001449** Name: MT2063_SoftwareShutdown
1450**
1451** Description: Enables or disables software shutdown function. When
1452** Shutdown==1, any section whose power mask is set will be
1453** shutdown.
1454**
1455** Parameters: h - Tuner handle (returned by MT2063_Open)
1456** Shutdown - 1 = shutdown the masked sections, otherwise
1457** power all sections on
1458**
1459** Returns: status:
1460** MT_OK - No errors
1461** MT_INV_HANDLE - Invalid tuner handle
1462** MT_COMM_ERR - Serial bus communications error
1463**
1464** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
1465**
1466** Revision History:
1467**
1468** SCR Date Author Description
1469** -------------------------------------------------------------------------
1470** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1471** 01-03-2008 PINZ Ver 1.xx: Added a trigger of BYPATNUP for
1472** correct wakeup of the LNA
1473**
1474****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001475static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001476{
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001477 u32 status; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001478
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001479 if (Shutdown == 1)
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001480 state->reg[MT2063_REG_PWR_1] |= 0x04; /* Turn the bit on */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001481 else
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001482 state->reg[MT2063_REG_PWR_1] &= ~0x04; /* Turn off the bit */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001483
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001484 status = mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001485 MT2063_REG_PWR_1,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001486 &state->reg[MT2063_REG_PWR_1], 1);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001487
1488 if (Shutdown != 1) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001489 state->reg[MT2063_REG_BYP_CTRL] =
1490 (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001491 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001492 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001493 MT2063_REG_BYP_CTRL,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001494 &state->reg[MT2063_REG_BYP_CTRL],
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001495 1);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001496 state->reg[MT2063_REG_BYP_CTRL] =
1497 (state->reg[MT2063_REG_BYP_CTRL] & 0x9F);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001498 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001499 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001500 MT2063_REG_BYP_CTRL,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001501 &state->reg[MT2063_REG_BYP_CTRL],
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001502 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001503 }
1504
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001505 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001506}
1507
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001508static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001509{
1510 return f_ref * (f_LO / f_ref)
1511 + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step);
1512}
1513
1514/****************************************************************************
1515**
1516** Name: fLO_FractionalTerm
1517**
1518** Description: Calculates the portion contributed by FracN / denom.
1519**
1520** This function preserves maximum precision without
1521** risk of overflow. It accurately calculates
1522** f_ref * num / denom to within 1 HZ with fixed math.
1523**
1524** Parameters: num - Fractional portion of the multiplier
1525** denom - denominator portion of the ratio
1526** This routine successfully handles denom values
1527** up to and including 2^18.
1528** f_Ref - SRO frequency. This calculation handles
1529** f_ref as two separate 14-bit fields.
1530** Therefore, a maximum value of 2^28-1
1531** may safely be used for f_ref. This is
1532** the genesis of the magic number "14" and the
1533** magic mask value of 0x03FFF.
1534**
1535** Returns: f_ref * num / denom
1536**
1537** Revision History:
1538**
1539** SCR Date Author Description
1540** -------------------------------------------------------------------------
1541** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1542**
1543****************************************************************************/
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001544static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001545{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001546 u32 t1 = (f_ref >> 14) * num;
1547 u32 term1 = t1 / denom;
1548 u32 loss = t1 % denom;
1549 u32 term2 =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001550 (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom;
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001551 return (term1 << 14) + term2;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001552}
1553
1554/****************************************************************************
1555**
1556** Name: CalcLO1Mult
1557**
1558** Description: Calculates Integer divider value and the numerator
1559** value for a FracN PLL.
1560**
1561** This function assumes that the f_LO and f_Ref are
1562** evenly divisible by f_LO_Step.
1563**
1564** Parameters: Div - OUTPUT: Whole number portion of the multiplier
1565** FracN - OUTPUT: Fractional portion of the multiplier
1566** f_LO - desired LO frequency.
1567** f_LO_Step - Minimum step size for the LO (in Hz).
1568** f_Ref - SRO frequency.
1569** f_Avoid - Range of PLL frequencies to avoid near
1570** integer multiples of f_Ref (in Hz).
1571**
1572** Returns: Recalculated LO frequency.
1573**
1574** Revision History:
1575**
1576** SCR Date Author Description
1577** -------------------------------------------------------------------------
1578** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1579**
1580****************************************************************************/
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001581static u32 MT2063_CalcLO1Mult(u32 *Div,
1582 u32 *FracN,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001583 u32 f_LO,
1584 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001585{
1586 /* Calculate the whole number portion of the divider */
1587 *Div = f_LO / f_Ref;
1588
1589 /* Calculate the numerator value (round to nearest f_LO_Step) */
1590 *FracN =
1591 (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
1592 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
1593
1594 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64);
1595}
1596
1597/****************************************************************************
1598**
1599** Name: CalcLO2Mult
1600**
1601** Description: Calculates Integer divider value and the numerator
1602** value for a FracN PLL.
1603**
1604** This function assumes that the f_LO and f_Ref are
1605** evenly divisible by f_LO_Step.
1606**
1607** Parameters: Div - OUTPUT: Whole number portion of the multiplier
1608** FracN - OUTPUT: Fractional portion of the multiplier
1609** f_LO - desired LO frequency.
1610** f_LO_Step - Minimum step size for the LO (in Hz).
1611** f_Ref - SRO frequency.
1612** f_Avoid - Range of PLL frequencies to avoid near
1613** integer multiples of f_Ref (in Hz).
1614**
1615** Returns: Recalculated LO frequency.
1616**
1617** Revision History:
1618**
1619** SCR Date Author Description
1620** -------------------------------------------------------------------------
1621** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1622**
1623****************************************************************************/
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001624static u32 MT2063_CalcLO2Mult(u32 *Div,
1625 u32 *FracN,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001626 u32 f_LO,
1627 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001628{
1629 /* Calculate the whole number portion of the divider */
1630 *Div = f_LO / f_Ref;
1631
1632 /* Calculate the numerator value (round to nearest f_LO_Step) */
1633 *FracN =
1634 (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
1635 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
1636
1637 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN,
1638 8191);
1639}
1640
1641/****************************************************************************
1642**
1643** Name: FindClearTuneFilter
1644**
1645** Description: Calculate the corrrect ClearTune filter to be used for
1646** a given input frequency.
1647**
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001648** Parameters: state - ptr to tuner data structure
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001649** f_in - RF input center frequency (in Hz).
1650**
1651** Returns: ClearTune filter number (0-31)
1652**
1653** Dependencies: MUST CALL MT2064_Open BEFORE FindClearTuneFilter!
1654**
1655** Revision History:
1656**
1657** SCR Date Author Description
1658** -------------------------------------------------------------------------
1659** 04-10-2008 PINZ Ver 1.14: Use software-controlled ClearTune
1660** cross-over frequency values.
1661**
1662****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001663static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001664{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001665 u32 RFBand;
1666 u32 idx; /* index loop */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001667
1668 /*
1669 ** Find RF Band setting
1670 */
1671 RFBand = 31; /* def when f_in > all */
1672 for (idx = 0; idx < 31; ++idx) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001673 if (state->CTFiltMax[idx] >= f_in) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001674 RFBand = idx;
1675 break;
1676 }
1677 }
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001678 return RFBand;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001679}
1680
1681/****************************************************************************
1682**
1683** Name: MT2063_Tune
1684**
1685** Description: Change the tuner's tuned frequency to RFin.
1686**
1687** Parameters: h - Open handle to the tuner (from MT2063_Open).
1688** f_in - RF input center frequency (in Hz).
1689**
1690** Returns: status:
1691** MT_OK - No errors
1692** MT_INV_HANDLE - Invalid tuner handle
1693** MT_UPC_UNLOCK - Upconverter PLL unlocked
1694** MT_DNC_UNLOCK - Downconverter PLL unlocked
1695** MT_COMM_ERR - Serial bus communications error
1696** MT_SPUR_CNT_MASK - Count of avoided LO spurs
1697** MT_SPUR_PRESENT - LO spur possible in output
1698** MT_FIN_RANGE - Input freq out of range
1699** MT_FOUT_RANGE - Output freq out of range
1700** MT_UPC_RANGE - Upconverter freq out of range
1701** MT_DNC_RANGE - Downconverter freq out of range
1702**
1703** Dependencies: MUST CALL MT2063_Open BEFORE MT2063_Tune!
1704**
1705** MT_ReadSub - Read data from the two-wire serial bus
1706** MT_WriteSub - Write data to the two-wire serial bus
1707** MT_Sleep - Delay execution for x milliseconds
1708** MT2063_GetLocked - Checks to see if LO1 and LO2 are locked
1709**
1710** Revision History:
1711**
1712** SCR Date Author Description
1713** -------------------------------------------------------------------------
1714** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1715** 04-10-2008 PINZ Ver 1.05: Use software-controlled ClearTune
1716** cross-over frequency values.
1717** 175 I 16-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
1718** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
1719** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
1720**
1721****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001722static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001723{ /* RF input center frequency */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001724
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001725 u32 status = 0; /* status of operation */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001726 u32 LO1; /* 1st LO register value */
1727 u32 Num1; /* Numerator for LO1 reg. value */
1728 u32 f_IF1; /* 1st IF requested */
1729 u32 LO2; /* 2nd LO register value */
1730 u32 Num2; /* Numerator for LO2 reg. value */
1731 u32 ofLO1, ofLO2; /* last time's LO frequencies */
1732 u32 ofin, ofout; /* last time's I/O frequencies */
1733 u8 fiffc = 0x80; /* FIFF center freq from tuner */
1734 u32 fiffof; /* Offset from FIFF center freq */
1735 const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */
1736 u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */
1737 u8 val;
1738 u32 RFBand;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001739
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001740 /* Check the input and output frequency ranges */
1741 if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ))
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001742 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001743
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001744 if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ)
1745 || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ))
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001746 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001747
1748 /*
1749 ** Save original LO1 and LO2 register values
1750 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001751 ofLO1 = state->AS_Data.f_LO1;
1752 ofLO2 = state->AS_Data.f_LO2;
1753 ofin = state->AS_Data.f_in;
1754 ofout = state->AS_Data.f_out;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001755
1756 /*
1757 ** Find and set RF Band setting
1758 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001759 if (state->ctfilt_sw == 1) {
1760 val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08);
1761 if (state->reg[MT2063_REG_CTUNE_CTRL] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001762 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001763 mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001764 }
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001765 val = state->reg[MT2063_REG_CTUNE_OV];
1766 RFBand = FindClearTuneFilter(state, f_in);
1767 state->reg[MT2063_REG_CTUNE_OV] =
1768 (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001769 | RFBand);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001770 if (state->reg[MT2063_REG_CTUNE_OV] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001771 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001772 mt2063_setreg(state, MT2063_REG_CTUNE_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001773 }
1774 }
1775
1776 /*
1777 ** Read the FIFF Center Frequency from the tuner
1778 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001779 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001780 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001781 mt2063_read(state,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001782 MT2063_REG_FIFFC,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001783 &state->reg[MT2063_REG_FIFFC], 1);
1784 fiffc = state->reg[MT2063_REG_FIFFC];
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001785 }
1786 /*
1787 ** Assign in the requested values
1788 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001789 state->AS_Data.f_in = f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001790 /* Request a 1st IF such that LO1 is on a step size */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001791 state->AS_Data.f_if1_Request =
1792 MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in,
1793 state->AS_Data.f_LO1_Step,
1794 state->AS_Data.f_ref) - f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001795
1796 /*
1797 ** Calculate frequency settings. f_IF1_FREQ + f_in is the
1798 ** desired LO1 frequency
1799 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001800 MT2063_ResetExclZones(&state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001801
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001802 f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001803
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001804 state->AS_Data.f_LO1 =
1805 MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step,
1806 state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001807
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001808 state->AS_Data.f_LO2 =
1809 MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
1810 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001811
1812 /*
1813 ** Check for any LO spurs in the output bandwidth and adjust
1814 ** the LO settings to avoid them if needed
1815 */
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001816 status |= MT2063_AvoidSpurs(&state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001817 /*
1818 ** MT_AvoidSpurs spurs may have changed the LO1 & LO2 values.
1819 ** Recalculate the LO frequencies and the values to be placed
1820 ** in the tuning registers.
1821 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001822 state->AS_Data.f_LO1 =
1823 MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1,
1824 state->AS_Data.f_LO1_Step, state->AS_Data.f_ref);
1825 state->AS_Data.f_LO2 =
1826 MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
1827 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
1828 state->AS_Data.f_LO2 =
1829 MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2,
1830 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001831
1832 /*
1833 ** Check the upconverter and downconverter frequency ranges
1834 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001835 if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ)
1836 || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001837 status |= MT2063_UPC_RANGE;
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001838 if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ)
1839 || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001840 status |= MT2063_DNC_RANGE;
1841 /* LO2 Lock bit was in a different place for B0 version */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001842 if (state->tuner_id == MT2063_B0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001843 LO2LK = 0x40;
1844
1845 /*
1846 ** If we have the same LO frequencies and we're already locked,
1847 ** then skip re-programming the LO registers.
1848 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001849 if ((ofLO1 != state->AS_Data.f_LO1)
1850 || (ofLO2 != state->AS_Data.f_LO2)
1851 || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) !=
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001852 (LO1LK | LO2LK))) {
1853 /*
1854 ** Calculate the FIFFOF register value
1855 **
1856 ** IF1_Actual
1857 ** FIFFOF = ------------ - 8 * FIFFC - 4992
1858 ** f_ref/64
1859 */
1860 fiffof =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001861 (state->AS_Data.f_LO1 -
1862 f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc -
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001863 4992;
1864 if (fiffof > 0xFF)
1865 fiffof = 0xFF;
1866
1867 /*
1868 ** Place all of the calculated values into the local tuner
1869 ** register fields.
1870 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001871 if (status >= 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001872 state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */
1873 state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */
1874 state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001875 |(Num2 >> 12)); /* NUM2q (hi) */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001876 state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */
1877 state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001878
1879 /*
1880 ** Now write out the computed register values
1881 ** IMPORTANT: There is a required order for writing
1882 ** (0x05 must follow all the others).
1883 */
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001884 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 -03001885 if (state->tuner_id == MT2063_B0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001886 /* Re-write the one-shot bits to trigger the tune operation */
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001887 status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001888 }
1889 /* Write out the FIFF offset only if it's changing */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001890 if (state->reg[MT2063_REG_FIFF_OFFSET] !=
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001891 (u8) fiffof) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001892 state->reg[MT2063_REG_FIFF_OFFSET] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001893 (u8) fiffof;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001894 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001895 mt2063_write(state,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001896 MT2063_REG_FIFF_OFFSET,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001897 &state->
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001898 reg[MT2063_REG_FIFF_OFFSET],
1899 1);
1900 }
1901 }
1902
1903 /*
1904 ** Check for LO's locking
1905 */
1906
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001907 if (status < 0)
1908 return status;
1909
1910 status = mt2063_lockStatus(state);
1911 if (status < 0)
1912 return status;
1913 if (!status)
1914 return -EINVAL; /* Couldn't lock */
1915
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001916 /*
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001917 * If we locked OK, assign calculated data to mt2063_state structure
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001918 */
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001919 state->f_IF1_actual = state->AS_Data.f_LO1 - f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001920 }
1921
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001922 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001923}
1924
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001925int mt2063_setTune(struct dvb_frontend *fe, u32 f_in, u32 bw_in,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001926 enum MTTune_atv_standard tv_type)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001927{
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001928 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001929 u32 status = 0;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001930 s32 pict_car = 0;
1931 s32 pict2chanb_vsb = 0;
1932 s32 pict2chanb_snd = 0;
1933 s32 pict2snd1 = 0;
1934 s32 pict2snd2 = 0;
1935 s32 ch_bw = 0;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001936 s32 if_mid = 0;
1937 s32 rcvr_mode = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001938
1939 switch (tv_type) {
1940 case MTTUNEA_PAL_B:{
1941 pict_car = 38900000;
1942 ch_bw = 8000000;
1943 pict2chanb_vsb = -1250000;
1944 pict2snd1 = 5500000;
1945 pict2snd2 = 5742000;
1946 rcvr_mode = 1;
1947 break;
1948 }
1949 case MTTUNEA_PAL_G:{
1950 pict_car = 38900000;
1951 ch_bw = 7000000;
1952 pict2chanb_vsb = -1250000;
1953 pict2snd1 = 5500000;
1954 pict2snd2 = 0;
1955 rcvr_mode = 1;
1956 break;
1957 }
1958 case MTTUNEA_PAL_I:{
1959 pict_car = 38900000;
1960 ch_bw = 8000000;
1961 pict2chanb_vsb = -1250000;
1962 pict2snd1 = 6000000;
1963 pict2snd2 = 0;
1964 rcvr_mode = 1;
1965 break;
1966 }
1967 case MTTUNEA_PAL_L:{
1968 pict_car = 38900000;
1969 ch_bw = 8000000;
1970 pict2chanb_vsb = -1250000;
1971 pict2snd1 = 6500000;
1972 pict2snd2 = 0;
1973 rcvr_mode = 1;
1974 break;
1975 }
1976 case MTTUNEA_PAL_MN:{
1977 pict_car = 38900000;
1978 ch_bw = 6000000;
1979 pict2chanb_vsb = -1250000;
1980 pict2snd1 = 4500000;
1981 pict2snd2 = 0;
1982 rcvr_mode = 1;
1983 break;
1984 }
1985 case MTTUNEA_PAL_DK:{
1986 pict_car = 38900000;
1987 ch_bw = 8000000;
1988 pict2chanb_vsb = -1250000;
1989 pict2snd1 = 6500000;
1990 pict2snd2 = 0;
1991 rcvr_mode = 1;
1992 break;
1993 }
1994 case MTTUNEA_DIGITAL:{
1995 pict_car = 36125000;
1996 ch_bw = 8000000;
1997 pict2chanb_vsb = -(ch_bw / 2);
1998 pict2snd1 = 0;
1999 pict2snd2 = 0;
2000 rcvr_mode = 2;
2001 break;
2002 }
2003 case MTTUNEA_FMRADIO:{
2004 pict_car = 38900000;
2005 ch_bw = 8000000;
2006 pict2chanb_vsb = -(ch_bw / 2);
2007 pict2snd1 = 0;
2008 pict2snd2 = 0;
2009 rcvr_mode = 4;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002010 break;
2011 }
2012 case MTTUNEA_DVBC:{
2013 pict_car = 36125000;
2014 ch_bw = 8000000;
2015 pict2chanb_vsb = -(ch_bw / 2);
2016 pict2snd1 = 0;
2017 pict2snd2 = 0;
2018 rcvr_mode = MT2063_CABLE_QAM;
2019 break;
2020 }
2021 case MTTUNEA_DVBT:{
2022 pict_car = 36125000;
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03002023 ch_bw = bw_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002024 pict2chanb_vsb = -(ch_bw / 2);
2025 pict2snd1 = 0;
2026 pict2snd2 = 0;
2027 rcvr_mode = MT2063_OFFAIR_COFDM;
2028 break;
2029 }
2030 case MTTUNEA_UNKNOWN:
2031 break;
2032 default:
2033 break;
2034 }
2035
2036 pict2chanb_snd = pict2chanb_vsb - ch_bw;
2037 if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
2038
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03002039 state->AS_Data.f_LO2_Step = 125000;
2040 state->AS_Data.f_out = if_mid;
2041 state->AS_Data.f_out_bw = ch_bw + 750000;
2042 status = MT2063_SetReceiverMode(state, rcvr_mode);
2043 if (status < 0)
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03002044 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002045
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03002046 status = MT2063_Tune(state, (f_in + (pict2chanb_vsb + (ch_bw / 2))));
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002047
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03002048 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002049}
2050
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002051static const u8 MT2063B0_defaults[] = {
2052 /* Reg, Value */
2053 0x19, 0x05,
2054 0x1B, 0x1D,
2055 0x1C, 0x1F,
2056 0x1D, 0x0F,
2057 0x1E, 0x3F,
2058 0x1F, 0x0F,
2059 0x20, 0x3F,
2060 0x22, 0x21,
2061 0x23, 0x3F,
2062 0x24, 0x20,
2063 0x25, 0x3F,
2064 0x27, 0xEE,
2065 0x2C, 0x27, /* bit at 0x20 is cleared below */
2066 0x30, 0x03,
2067 0x2C, 0x07, /* bit at 0x20 is cleared here */
2068 0x2D, 0x87,
2069 0x2E, 0xAA,
2070 0x28, 0xE1, /* Set the FIFCrst bit here */
2071 0x28, 0xE0, /* Clear the FIFCrst bit here */
2072 0x00
2073};
2074
2075/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
2076static const u8 MT2063B1_defaults[] = {
2077 /* Reg, Value */
2078 0x05, 0xF0,
2079 0x11, 0x10, /* New Enable AFCsd */
2080 0x19, 0x05,
2081 0x1A, 0x6C,
2082 0x1B, 0x24,
2083 0x1C, 0x28,
2084 0x1D, 0x8F,
2085 0x1E, 0x14,
2086 0x1F, 0x8F,
2087 0x20, 0x57,
2088 0x22, 0x21, /* New - ver 1.03 */
2089 0x23, 0x3C, /* New - ver 1.10 */
2090 0x24, 0x20, /* New - ver 1.03 */
2091 0x2C, 0x24, /* bit at 0x20 is cleared below */
2092 0x2D, 0x87, /* FIFFQ=0 */
2093 0x2F, 0xF3,
2094 0x30, 0x0C, /* New - ver 1.11 */
2095 0x31, 0x1B, /* New - ver 1.11 */
2096 0x2C, 0x04, /* bit at 0x20 is cleared here */
2097 0x28, 0xE1, /* Set the FIFCrst bit here */
2098 0x28, 0xE0, /* Clear the FIFCrst bit here */
2099 0x00
2100};
2101
2102/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
2103static const u8 MT2063B3_defaults[] = {
2104 /* Reg, Value */
2105 0x05, 0xF0,
2106 0x19, 0x3D,
2107 0x2C, 0x24, /* bit at 0x20 is cleared below */
2108 0x2C, 0x04, /* bit at 0x20 is cleared here */
2109 0x28, 0xE1, /* Set the FIFCrst bit here */
2110 0x28, 0xE0, /* Clear the FIFCrst bit here */
2111 0x00
2112};
2113
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002114static int mt2063_init(struct dvb_frontend *fe)
2115{
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002116 u32 status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002117 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002118 u8 all_resets = 0xF0; /* reset/load bits */
2119 const u8 *def = NULL;
2120 u32 FCRUN;
2121 s32 maxReads;
2122 u32 fcu_osc;
2123 u32 i;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002124
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002125 state->rcvr_mode = MT2063_CABLE_QAM;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002126
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002127 /* Read the Part/Rev code from the tuner */
2128 status = mt2063_read(state, MT2063_REG_PART_REV, state->reg, 1);
2129 if (status < 0)
2130 return status;
2131
2132 /* Check the part/rev code */
2133 if (((state->reg[MT2063_REG_PART_REV] != MT2063_B0) /* MT2063 B0 */
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03002134 && (state->reg[MT2063_REG_PART_REV] != MT2063_B1) /* MT2063 B1 */
2135 && (state->reg[MT2063_REG_PART_REV] != MT2063_B3))) /* MT2063 B3 */
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002136 return -ENODEV; /* Wrong tuner Part/Rev code */
2137
2138 /* Check the 2nd byte of the Part/Rev code from the tuner */
2139 status = mt2063_read(state, MT2063_REG_RSVD_3B,
2140 &state->reg[MT2063_REG_RSVD_3B], 1);
2141
2142 /* b7 != 0 ==> NOT MT2063 */
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03002143 if (status < 0 || ((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00))
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002144 return -ENODEV; /* Wrong tuner Part/Rev code */
2145
2146 /* Reset the tuner */
2147 status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1);
2148 if (status < 0)
2149 return status;
2150
2151 /* change all of the default values that vary from the HW reset values */
2152 /* def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */
2153 switch (state->reg[MT2063_REG_PART_REV]) {
2154 case MT2063_B3:
2155 def = MT2063B3_defaults;
2156 break;
2157
2158 case MT2063_B1:
2159 def = MT2063B1_defaults;
2160 break;
2161
2162 case MT2063_B0:
2163 def = MT2063B0_defaults;
2164 break;
2165
2166 default:
2167 return -ENODEV;
2168 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002169 }
2170
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002171 while (status >= 0 && *def) {
2172 u8 reg = *def++;
2173 u8 val = *def++;
2174 status = mt2063_write(state, reg, &val, 1);
2175 }
2176 if (status < 0)
2177 return status;
2178
2179 /* Wait for FIFF location to complete. */
2180 FCRUN = 1;
2181 maxReads = 10;
2182 while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) {
2183 msleep(2);
2184 status = mt2063_read(state,
2185 MT2063_REG_XO_STATUS,
2186 &state->
2187 reg[MT2063_REG_XO_STATUS], 1);
2188 FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6;
2189 }
2190
2191 if (FCRUN != 0 || status < 0)
2192 return -ENODEV;
2193
2194 status = mt2063_read(state,
2195 MT2063_REG_FIFFC,
2196 &state->reg[MT2063_REG_FIFFC], 1);
2197 if (status < 0)
2198 return status;
2199
2200 /* Read back all the registers from the tuner */
2201 status = mt2063_read(state,
2202 MT2063_REG_PART_REV,
2203 state->reg, MT2063_REG_END_REGS);
2204 if (status < 0)
2205 return status;
2206
2207 /* Initialize the tuner state. */
2208 state->tuner_id = state->reg[MT2063_REG_PART_REV];
2209 state->AS_Data.f_ref = MT2063_REF_FREQ;
2210 state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) *
2211 ((u32) state->reg[MT2063_REG_FIFFC] + 640);
2212 state->AS_Data.f_if1_bw = MT2063_IF1_BW;
2213 state->AS_Data.f_out = 43750000UL;
2214 state->AS_Data.f_out_bw = 6750000UL;
2215 state->AS_Data.f_zif_bw = MT2063_ZIF_BW;
2216 state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64;
2217 state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE;
2218 state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1;
2219 state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2;
2220 state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP;
2221 state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center;
2222 state->AS_Data.f_LO1 = 2181000000UL;
2223 state->AS_Data.f_LO2 = 1486249786UL;
2224 state->f_IF1_actual = state->AS_Data.f_if1_Center;
2225 state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual;
2226 state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID;
2227 state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID;
2228 state->num_regs = MT2063_REG_END_REGS;
2229 state->AS_Data.avoidDECT = MT2063_AVOID_BOTH;
2230 state->ctfilt_sw = 0;
2231
2232 state->CTFiltMax[0] = 69230000;
2233 state->CTFiltMax[1] = 105770000;
2234 state->CTFiltMax[2] = 140350000;
2235 state->CTFiltMax[3] = 177110000;
2236 state->CTFiltMax[4] = 212860000;
2237 state->CTFiltMax[5] = 241130000;
2238 state->CTFiltMax[6] = 274370000;
2239 state->CTFiltMax[7] = 309820000;
2240 state->CTFiltMax[8] = 342450000;
2241 state->CTFiltMax[9] = 378870000;
2242 state->CTFiltMax[10] = 416210000;
2243 state->CTFiltMax[11] = 456500000;
2244 state->CTFiltMax[12] = 495790000;
2245 state->CTFiltMax[13] = 534530000;
2246 state->CTFiltMax[14] = 572610000;
2247 state->CTFiltMax[15] = 598970000;
2248 state->CTFiltMax[16] = 635910000;
2249 state->CTFiltMax[17] = 672130000;
2250 state->CTFiltMax[18] = 714840000;
2251 state->CTFiltMax[19] = 739660000;
2252 state->CTFiltMax[20] = 770410000;
2253 state->CTFiltMax[21] = 814660000;
2254 state->CTFiltMax[22] = 846950000;
2255 state->CTFiltMax[23] = 867820000;
2256 state->CTFiltMax[24] = 915980000;
2257 state->CTFiltMax[25] = 947450000;
2258 state->CTFiltMax[26] = 983110000;
2259 state->CTFiltMax[27] = 1021630000;
2260 state->CTFiltMax[28] = 1061870000;
2261 state->CTFiltMax[29] = 1098330000;
2262 state->CTFiltMax[30] = 1138990000;
2263
2264 /*
2265 ** Fetch the FCU osc value and use it and the fRef value to
2266 ** scale all of the Band Max values
2267 */
2268
2269 state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A;
2270 status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
2271 &state->reg[MT2063_REG_CTUNE_CTRL], 1);
2272 if (status < 0)
2273 return status;
2274
2275 /* Read the ClearTune filter calibration value */
2276 status = mt2063_read(state, MT2063_REG_FIFFC,
2277 &state->reg[MT2063_REG_FIFFC], 1);
2278 if (status < 0)
2279 return status;
2280
2281 fcu_osc = state->reg[MT2063_REG_FIFFC];
2282
2283 state->reg[MT2063_REG_CTUNE_CTRL] = 0x00;
2284 status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
2285 &state->reg[MT2063_REG_CTUNE_CTRL], 1);
2286 if (status < 0)
2287 return status;
2288
2289 /* Adjust each of the values in the ClearTune filter cross-over table */
2290 for (i = 0; i < 31; i++)
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03002291 state->CTFiltMax[i] = (state->CTFiltMax[i] / 768) * (fcu_osc + 640);
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002292
2293 status = MT2063_SoftwareShutdown(state, 1);
2294 if (status < 0)
2295 return status;
2296 status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
2297 if (status < 0)
2298 return status;
2299
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002300 return 0;
2301}
2302
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002303static int mt2063_get_status(struct dvb_frontend *fe, u32 * status)
2304{
2305 int rc = 0;
2306
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03002307 /* FIXME: add get tuner lock status */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002308
2309 return rc;
2310}
2311
2312static int mt2063_get_state(struct dvb_frontend *fe,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002313 enum tuner_param param, struct tuner_state *tunstate)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002314{
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002315 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002316
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002317 switch (param) {
2318 case DVBFE_TUNER_FREQUENCY:
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03002319 /* get frequency */
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002320 break;
2321 case DVBFE_TUNER_TUNERSTEP:
2322 break;
2323 case DVBFE_TUNER_IFFREQ:
2324 break;
2325 case DVBFE_TUNER_BANDWIDTH:
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03002326 /* get bandwidth */
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002327 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002328 case DVBFE_TUNER_REFCLOCK:
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03002329 tunstate->refclock = mt2063_lockStatus(state);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002330 break;
2331 default:
2332 break;
2333 }
2334
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002335 return (int)tunstate->refclock;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002336}
2337
2338static int mt2063_set_state(struct dvb_frontend *fe,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002339 enum tuner_param param, struct tuner_state *tunstate)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002340{
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002341 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002342 u32 status = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002343
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002344 switch (param) {
2345 case DVBFE_TUNER_FREQUENCY:
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03002346 /* set frequency */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002347
2348 status =
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03002349 mt2063_setTune(fe,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002350 tunstate->frequency, tunstate->bandwidth,
2351 state->tv_type);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002352
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002353 state->frequency = tunstate->frequency;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002354 break;
2355 case DVBFE_TUNER_TUNERSTEP:
2356 break;
2357 case DVBFE_TUNER_IFFREQ:
2358 break;
2359 case DVBFE_TUNER_BANDWIDTH:
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03002360 /* set bandwidth */
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03002361 state->bandwidth = tunstate->bandwidth;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002362 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002363 case DVBFE_TUNER_REFCLOCK:
2364
2365 break;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002366 default:
2367 break;
2368 }
2369
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002370 return (int)status;
2371}
2372
2373static int mt2063_release(struct dvb_frontend *fe)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002374{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002375 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002376
2377 fe->tuner_priv = NULL;
2378 kfree(state);
2379
2380 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002381}
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002382
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002383static struct dvb_tuner_ops mt2063_ops = {
2384 .info = {
2385 .name = "MT2063 Silicon Tuner",
2386 .frequency_min = 45000000,
2387 .frequency_max = 850000000,
2388 .frequency_step = 0,
2389 },
2390
2391 .init = mt2063_init,
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002392 .sleep = MT2063_Sleep,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002393 .get_status = mt2063_get_status,
2394 .get_state = mt2063_get_state,
2395 .set_state = mt2063_set_state,
2396 .release = mt2063_release
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002397};
2398
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002399struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
2400 struct mt2063_config *config,
2401 struct i2c_adapter *i2c)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002402{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002403 struct mt2063_state *state = NULL;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002404
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002405 state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002406 if (state == NULL)
2407 goto error;
2408
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002409 state->config = config;
2410 state->i2c = i2c;
2411 state->frontend = fe;
2412 state->reference = config->refclock / 1000; /* kHz */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002413 fe->tuner_priv = state;
2414 fe->ops.tuner_ops = mt2063_ops;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002415
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03002416 printk(KERN_INFO "%s: Attaching MT2063\n", __func__);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002417 return fe;
2418
2419error:
2420 kfree(state);
2421 return NULL;
2422}
Mauro Carvalho Chehab3d497002011-07-21 11:00:59 -03002423EXPORT_SYMBOL_GPL(mt2063_attach);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002424
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03002425/*
2426 * Ancillary routines visible outside mt2063
2427 * FIXME: Remove them in favor of using standard tuner callbacks
2428 */
2429unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe)
2430{
2431 struct mt2063_state *state = fe->tuner_priv;
2432 int err = 0;
2433
2434 err = MT2063_SoftwareShutdown(state, 1);
2435 if (err < 0)
2436 printk(KERN_ERR "%s: Couldn't shutdown\n", __func__);
2437
2438 return err;
2439}
2440EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown);
2441
2442unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe)
2443{
2444 struct mt2063_state *state = fe->tuner_priv;
2445 int err = 0;
2446
2447 err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
2448 if (err < 0)
2449 printk(KERN_ERR "%s: Invalid parameter\n", __func__);
2450
2451 return err;
2452}
2453EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits);
2454
2455
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002456MODULE_PARM_DESC(verbose, "Set Verbosity level");
2457
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002458MODULE_AUTHOR("Henry");
2459MODULE_DESCRIPTION("MT2063 Silicon tuner");
2460MODULE_LICENSE("GPL");