blob: 3c0b3f1ec24876aff6fc1bc5b66cc2ab5cb6cb6f [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 Chehab29a0a4fe2011-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 Chehab29a0a4fe2011-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/*
113 * Parameter for function MT2063_GetParam & MT2063_SetParam that
114 * specifies the tuning algorithm parameter to be read/written.
115 */
116enum MT2063_Param {
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300117 /* min tuning step size (default: 50000 Hz) */
118 MT2063_STEPSIZE,
119
120 /* input center frequency set by MT2063_Tune() */
121 MT2063_INPUT_FREQ,
122
123 /* LO1 Frequency set by MT2063_Tune() */
124 MT2063_LO1_FREQ,
125
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300126 /* LO2 Frequency set by MT2063_Tune() */
127 MT2063_LO2_FREQ,
128
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300129 /* output center frequency set by MT2063_Tune() */
130 MT2063_OUTPUT_FREQ,
131
132 /* output bandwidth set by MT2063_Tune() */
133 MT2063_OUTPUT_BW,
134
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300135 /* Receiver Mode for some parameters. 1 is DVB-T */
136 MT2063_RCVR_MODE,
137
138 /* directly set LNA attenuation, parameter is value to set */
139 MT2063_ACLNA,
140
141 /* maximum LNA attenuation, parameter is value to set */
142 MT2063_ACLNA_MAX,
143
144 /* directly set ATN attenuation. Paremeter is value to set. */
145 MT2063_ACRF,
146
147 /* maxium ATN attenuation. Paremeter is value to set. */
148 MT2063_ACRF_MAX,
149
150 /* directly set FIF attenuation. Paremeter is value to set. */
151 MT2063_ACFIF,
152
153 /* maxium FIF attenuation. Paremeter is value to set. */
154 MT2063_ACFIF_MAX,
155
156 /* LNA Rin */
157 MT2063_LNA_RIN,
158
159 /* Power Detector LNA level target */
160 MT2063_LNA_TGT,
161
162 /* Power Detector 1 level */
163 MT2063_PD1,
164
165 /* Power Detector 1 level target */
166 MT2063_PD1_TGT,
167
168 /* Power Detector 2 level */
169 MT2063_PD2,
170
171 /* Power Detector 2 level target */
172 MT2063_PD2_TGT,
173
174 /* Selects, which DNC is activ */
175 MT2063_DNC_OUTPUT_ENABLE,
176
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300177 MT2063_EOP /* last entry in enumerated list */
178};
179
180/*
181 * Parameter for selecting tuner mode
182 */
183enum MT2063_RCVR_MODES {
184 MT2063_CABLE_QAM = 0, /* Digital cable */
185 MT2063_CABLE_ANALOG, /* Analog cable */
186 MT2063_OFFAIR_COFDM, /* Digital offair */
187 MT2063_OFFAIR_COFDM_SAWLESS, /* Digital offair without SAW */
188 MT2063_OFFAIR_ANALOG, /* Analog offair */
189 MT2063_OFFAIR_8VSB, /* Analog offair */
190 MT2063_NUM_RCVR_MODES
191};
192
193/*
194 * Possible values for MT2063_DNC_OUTPUT
195 */
196enum MT2063_DNC_Output_Enable {
197 MT2063_DNC_NONE = 0,
198 MT2063_DNC_1,
199 MT2063_DNC_2,
200 MT2063_DNC_BOTH
201};
202
203/*
204** Two-wire serial bus subaddresses of the tuner registers.
205** Also known as the tuner's register addresses.
206*/
207enum MT2063_Register_Offsets {
208 MT2063_REG_PART_REV = 0, /* 0x00: Part/Rev Code */
209 MT2063_REG_LO1CQ_1, /* 0x01: LO1C Queued Byte 1 */
210 MT2063_REG_LO1CQ_2, /* 0x02: LO1C Queued Byte 2 */
211 MT2063_REG_LO2CQ_1, /* 0x03: LO2C Queued Byte 1 */
212 MT2063_REG_LO2CQ_2, /* 0x04: LO2C Queued Byte 2 */
213 MT2063_REG_LO2CQ_3, /* 0x05: LO2C Queued Byte 3 */
214 MT2063_REG_RSVD_06, /* 0x06: Reserved */
215 MT2063_REG_LO_STATUS, /* 0x07: LO Status */
216 MT2063_REG_FIFFC, /* 0x08: FIFF Center */
217 MT2063_REG_CLEARTUNE, /* 0x09: ClearTune Filter */
218 MT2063_REG_ADC_OUT, /* 0x0A: ADC_OUT */
219 MT2063_REG_LO1C_1, /* 0x0B: LO1C Byte 1 */
220 MT2063_REG_LO1C_2, /* 0x0C: LO1C Byte 2 */
221 MT2063_REG_LO2C_1, /* 0x0D: LO2C Byte 1 */
222 MT2063_REG_LO2C_2, /* 0x0E: LO2C Byte 2 */
223 MT2063_REG_LO2C_3, /* 0x0F: LO2C Byte 3 */
224 MT2063_REG_RSVD_10, /* 0x10: Reserved */
225 MT2063_REG_PWR_1, /* 0x11: PWR Byte 1 */
226 MT2063_REG_PWR_2, /* 0x12: PWR Byte 2 */
227 MT2063_REG_TEMP_STATUS, /* 0x13: Temp Status */
228 MT2063_REG_XO_STATUS, /* 0x14: Crystal Status */
229 MT2063_REG_RF_STATUS, /* 0x15: RF Attn Status */
230 MT2063_REG_FIF_STATUS, /* 0x16: FIF Attn Status */
231 MT2063_REG_LNA_OV, /* 0x17: LNA Attn Override */
232 MT2063_REG_RF_OV, /* 0x18: RF Attn Override */
233 MT2063_REG_FIF_OV, /* 0x19: FIF Attn Override */
234 MT2063_REG_LNA_TGT, /* 0x1A: Reserved */
235 MT2063_REG_PD1_TGT, /* 0x1B: Pwr Det 1 Target */
236 MT2063_REG_PD2_TGT, /* 0x1C: Pwr Det 2 Target */
237 MT2063_REG_RSVD_1D, /* 0x1D: Reserved */
238 MT2063_REG_RSVD_1E, /* 0x1E: Reserved */
239 MT2063_REG_RSVD_1F, /* 0x1F: Reserved */
240 MT2063_REG_RSVD_20, /* 0x20: Reserved */
241 MT2063_REG_BYP_CTRL, /* 0x21: Bypass Control */
242 MT2063_REG_RSVD_22, /* 0x22: Reserved */
243 MT2063_REG_RSVD_23, /* 0x23: Reserved */
244 MT2063_REG_RSVD_24, /* 0x24: Reserved */
245 MT2063_REG_RSVD_25, /* 0x25: Reserved */
246 MT2063_REG_RSVD_26, /* 0x26: Reserved */
247 MT2063_REG_RSVD_27, /* 0x27: Reserved */
248 MT2063_REG_FIFF_CTRL, /* 0x28: FIFF Control */
249 MT2063_REG_FIFF_OFFSET, /* 0x29: FIFF Offset */
250 MT2063_REG_CTUNE_CTRL, /* 0x2A: Reserved */
251 MT2063_REG_CTUNE_OV, /* 0x2B: Reserved */
252 MT2063_REG_CTRL_2C, /* 0x2C: Reserved */
253 MT2063_REG_FIFF_CTRL2, /* 0x2D: Fiff Control */
254 MT2063_REG_RSVD_2E, /* 0x2E: Reserved */
255 MT2063_REG_DNC_GAIN, /* 0x2F: DNC Control */
256 MT2063_REG_VGA_GAIN, /* 0x30: VGA Gain Ctrl */
257 MT2063_REG_RSVD_31, /* 0x31: Reserved */
258 MT2063_REG_TEMP_SEL, /* 0x32: Temperature Selection */
259 MT2063_REG_RSVD_33, /* 0x33: Reserved */
260 MT2063_REG_RSVD_34, /* 0x34: Reserved */
261 MT2063_REG_RSVD_35, /* 0x35: Reserved */
262 MT2063_REG_RSVD_36, /* 0x36: Reserved */
263 MT2063_REG_RSVD_37, /* 0x37: Reserved */
264 MT2063_REG_RSVD_38, /* 0x38: Reserved */
265 MT2063_REG_RSVD_39, /* 0x39: Reserved */
266 MT2063_REG_RSVD_3A, /* 0x3A: Reserved */
267 MT2063_REG_RSVD_3B, /* 0x3B: Reserved */
268 MT2063_REG_RSVD_3C, /* 0x3C: Reserved */
269 MT2063_REG_END_REGS
270};
271
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300272enum MTTune_atv_standard {
273 MTTUNEA_UNKNOWN = 0,
274 MTTUNEA_PAL_B,
275 MTTUNEA_PAL_G,
276 MTTUNEA_PAL_I,
277 MTTUNEA_PAL_L,
278 MTTUNEA_PAL_MN,
279 MTTUNEA_PAL_DK,
280 MTTUNEA_DIGITAL,
281 MTTUNEA_FMRADIO,
282 MTTUNEA_DVBC,
283 MTTUNEA_DVBT
284};
285
286
287struct mt2063_state {
288 struct i2c_adapter *i2c;
289
290 const struct mt2063_config *config;
291 struct dvb_tuner_ops ops;
292 struct dvb_frontend *frontend;
293 struct tuner_state status;
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300294
295 enum MTTune_atv_standard tv_type;
296 u32 frequency;
297 u32 srate;
298 u32 bandwidth;
299 u32 reference;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300300
301 u32 tuner_id;
302 struct MT2063_AvoidSpursData_t AS_Data;
303 u32 f_IF1_actual;
304 u32 rcvr_mode;
305 u32 ctfilt_sw;
306 u32 CTFiltMax[31];
307 u32 num_regs;
308 u8 reg[MT2063_REG_END_REGS];
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300309};
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300310
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300311/* Prototypes */
312static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
313 u32 f_min, u32 f_max);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -0300314static u32 MT2063_GetReg(struct mt2063_state *state, u8 reg, u8 * val);
315static u32 MT2063_GetParam(struct mt2063_state *state, enum MT2063_Param param, u32 * pValue);
316static u32 MT2063_SetReg(struct mt2063_state *state, u8 reg, u8 val);
317static u32 MT2063_SetParam(struct mt2063_state *state, enum MT2063_Param param,
Mauro Carvalho Chehab29a0a4fe2011-07-20 23:44:10 -0300318 enum MT2063_DNC_Output_Enable nValue);
Mauro Carvalho Chehab8c64f9322011-07-21 03:29:06 -0300319static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown);
320static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, enum MT2063_Mask_Bits Bits);
321
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300322
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300323/*****************/
324/* From drivers/media/common/tuners/mt2063_cfg.h */
325
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300326unsigned int mt2063_setTune(struct dvb_frontend *fe, u32 f_in,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300327 u32 bw_in,
328 enum MTTune_atv_standard tv_type)
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300329{
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300330 struct dvb_frontend_ops *frontend_ops = NULL;
331 struct dvb_tuner_ops *tuner_ops = NULL;
332 struct tuner_state t_state;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300333 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300334 int err = 0;
335
336 t_state.frequency = f_in;
337 t_state.bandwidth = bw_in;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300338 state->tv_type = tv_type;
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300339 if (&fe->ops)
340 frontend_ops = &fe->ops;
341 if (&frontend_ops->tuner_ops)
342 tuner_ops = &frontend_ops->tuner_ops;
343 if (tuner_ops->set_state) {
344 if ((err =
345 tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY,
346 &t_state)) < 0) {
347 printk("%s: Invalid parameter\n", __func__);
348 return err;
349 }
350 }
351
352 return err;
353}
354
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300355unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe)
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300356{
Mauro Carvalho Chehab8c64f9322011-07-21 03:29:06 -0300357 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300358 struct dvb_frontend_ops *frontend_ops = &fe->ops;
359 struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300360 int err = 0;
361
362 if (&fe->ops)
363 frontend_ops = &fe->ops;
364 if (&frontend_ops->tuner_ops)
365 tuner_ops = &frontend_ops->tuner_ops;
366 if (tuner_ops->set_state) {
Mauro Carvalho Chehab8c64f9322011-07-21 03:29:06 -0300367 err = MT2063_SoftwareShutdown(state, 1);
368 if (err < 0) {
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300369 printk("%s: Invalid parameter\n", __func__);
370 return err;
371 }
372 }
373
374 return err;
375}
376
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300377unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe)
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300378{
Mauro Carvalho Chehab8c64f9322011-07-21 03:29:06 -0300379 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300380 struct dvb_frontend_ops *frontend_ops = &fe->ops;
381 struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300382 int err = 0;
383
384 if (&fe->ops)
385 frontend_ops = &fe->ops;
386 if (&frontend_ops->tuner_ops)
387 tuner_ops = &frontend_ops->tuner_ops;
388 if (tuner_ops->set_state) {
Mauro Carvalho Chehab8c64f9322011-07-21 03:29:06 -0300389 err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
390 if (err < 0) {
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300391 printk("%s: Invalid parameter\n", __func__);
392 return err;
393 }
394 }
395
396 return err;
397}
398
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300399/*
400 * mt2063_write - Write data into the I2C bus
401 */
402static u32 mt2063_write(struct mt2063_state *state,
403 u8 reg, u8 *data, u32 len)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300404{
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300405 struct dvb_frontend *fe = state->frontend;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300406 int ret;
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300407 u8 buf[60];
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300408 struct i2c_msg msg = {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300409 .addr = state->config->tuner_address,
410 .flags = 0,
411 .buf = buf,
412 .len = len + 1
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300413 };
414
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300415 msg.buf[0] = reg;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300416 memcpy(msg.buf + 1, data, len);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300417
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300418 fe->ops.i2c_gate_ctrl(fe, 1);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300419 ret = i2c_transfer(state->i2c, &msg, 1);
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300420 fe->ops.i2c_gate_ctrl(fe, 0);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300421
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300422 if (ret < 0)
423 printk("mt2063_writeregs error ret=%d\n", ret);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300424
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300425 return ret;
426}
427
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300428/*
429 * mt2063_read - Read data from the I2C bus
430 */
431static u32 mt2063_read(struct mt2063_state *state,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300432 u8 subAddress, u8 *pData, u32 cnt)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300433{
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300434 u32 status = 0; /* Status to be returned */
435 struct dvb_frontend *fe = state->frontend;
436 u32 i = 0;
437
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300438 fe->ops.i2c_gate_ctrl(fe, 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300439
440 for (i = 0; i < cnt; i++) {
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300441 int ret;
442 u8 b0[] = { subAddress + i };
443 struct i2c_msg msg[] = {
444 {
445 .addr = state->config->tuner_address,
446 .flags = I2C_M_RD,
447 .buf = b0,
448 .len = 1
449 }, {
450 .addr = state->config->tuner_address,
451 .flags = I2C_M_RD,
452 .buf = pData + 1,
453 .len = 1
454 }
455 };
456
457 ret = i2c_transfer(state->i2c, msg, 2);
458 if (ret < 0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300459 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300460 }
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300461 fe->ops.i2c_gate_ctrl(fe, 0);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300462 return (status);
463}
464
Mauro Carvalho Chehabe930b3a2011-07-21 03:02:16 -0300465/*
466 * FIXME: Is this really needed?
467 */
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300468static int MT2063_Sleep(struct dvb_frontend *fe)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300469{
470 /*
471 ** ToDo: Add code here to implement a OS blocking
472 ** for a period of "nMinDelayTime" milliseconds.
473 */
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300474 msleep(10);
475
476 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300477}
478
Mauro Carvalho Chehabe930b3a2011-07-21 03:02:16 -0300479/*
480 * Microtune spur avoidance
481 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300482
483/* Implement ceiling, floor functions. */
484#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300485#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300486
487struct MT2063_FIFZone_t {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300488 s32 min_;
489 s32 max_;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300490};
491
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300492/*
493** Reset all exclusion zones.
494** Add zones to protect the PLL FracN regions near zero
495**
496** N/A I 06-17-2008 RSK Ver 1.19: Refactoring avoidance of DECT
497** frequencies into MT_ResetExclZones().
498*/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300499static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300500{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300501 u32 center;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300502
503 pAS_Info->nZones = 0; /* this clears the used list */
504 pAS_Info->usedZones = NULL; /* reset ptr */
505 pAS_Info->freeZones = NULL; /* reset ptr */
506
507 center =
508 pAS_Info->f_ref *
509 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 +
510 pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in;
511 while (center <
512 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
513 pAS_Info->f_LO1_FracN_Avoid) {
514 /* Exclude LO1 FracN */
515 MT2063_AddExclZone(pAS_Info,
516 center - pAS_Info->f_LO1_FracN_Avoid,
517 center - 1);
518 MT2063_AddExclZone(pAS_Info, center + 1,
519 center + pAS_Info->f_LO1_FracN_Avoid);
520 center += pAS_Info->f_ref;
521 }
522
523 center =
524 pAS_Info->f_ref *
525 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 -
526 pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out;
527 while (center <
528 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
529 pAS_Info->f_LO2_FracN_Avoid) {
530 /* Exclude LO2 FracN */
531 MT2063_AddExclZone(pAS_Info,
532 center - pAS_Info->f_LO2_FracN_Avoid,
533 center - 1);
534 MT2063_AddExclZone(pAS_Info, center + 1,
535 center + pAS_Info->f_LO2_FracN_Avoid);
536 center += pAS_Info->f_ref;
537 }
538
539 if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
540 /* Exclude LO1 values that conflict with DECT channels */
541 MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */
542 MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */
543 MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */
544 MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */
545 MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */
546 }
547
548 if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
549 MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */
550 MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */
551 MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */
552 MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */
553 MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */
554 MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */
555 MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */
556 MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */
557 MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */
558 MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */
559 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300560}
561
562static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t
563 *pAS_Info,
564 struct MT2063_ExclZone_t *pPrevNode)
565{
566 struct MT2063_ExclZone_t *pNode;
567 /* Check for a node in the free list */
568 if (pAS_Info->freeZones != NULL) {
569 /* Use one from the free list */
570 pNode = pAS_Info->freeZones;
571 pAS_Info->freeZones = pNode->next_;
572 } else {
573 /* Grab a node from the array */
574 pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones];
575 }
576
577 if (pPrevNode != NULL) {
578 pNode->next_ = pPrevNode->next_;
579 pPrevNode->next_ = pNode;
580 } else { /* insert at the beginning of the list */
581
582 pNode->next_ = pAS_Info->usedZones;
583 pAS_Info->usedZones = pNode;
584 }
585
586 pAS_Info->nZones++;
587 return pNode;
588}
589
590static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t
591 *pAS_Info,
592 struct MT2063_ExclZone_t *pPrevNode,
593 struct MT2063_ExclZone_t
594 *pNodeToRemove)
595{
596 struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_;
597
598 /* Make previous node point to the subsequent node */
599 if (pPrevNode != NULL)
600 pPrevNode->next_ = pNext;
601
602 /* Add pNodeToRemove to the beginning of the freeZones */
603 pNodeToRemove->next_ = pAS_Info->freeZones;
604 pAS_Info->freeZones = pNodeToRemove;
605
606 /* Decrement node count */
607 pAS_Info->nZones--;
608
609 return pNext;
610}
611
612/*****************************************************************************
613**
614** Name: MT_AddExclZone
615**
616** Description: Add (and merge) an exclusion zone into the list.
617** If the range (f_min, f_max) is totally outside the
618** 1st IF BW, ignore the entry.
619** If the range (f_min, f_max) is negative, ignore the entry.
620**
621** Revision History:
622**
623** SCR Date Author Description
624** -------------------------------------------------------------------------
625** 103 01-31-2005 DAD Ver 1.14: In MT_AddExclZone(), if the range
626** (f_min, f_max) < 0, ignore the entry.
627**
628*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300629static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300630 u32 f_min, u32 f_max)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300631{
632 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
633 struct MT2063_ExclZone_t *pPrev = NULL;
634 struct MT2063_ExclZone_t *pNext = NULL;
635
636 /* Check to see if this overlaps the 1st IF filter */
637 if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2)))
638 && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2)))
639 && (f_min < f_max)) {
640 /*
641 ** 1 2 3 4 5 6
642 **
643 ** New entry: |---| |--| |--| |-| |---| |--|
644 ** or or or or or
645 ** Existing: |--| |--| |--| |---| |-| |--|
646 */
647
648 /* Check for our place in the list */
649 while ((pNode != NULL) && (pNode->max_ < f_min)) {
650 pPrev = pNode;
651 pNode = pNode->next_;
652 }
653
654 if ((pNode != NULL) && (pNode->min_ < f_max)) {
655 /* Combine me with pNode */
656 if (f_min < pNode->min_)
657 pNode->min_ = f_min;
658 if (f_max > pNode->max_)
659 pNode->max_ = f_max;
660 } else {
661 pNode = InsertNode(pAS_Info, pPrev);
662 pNode->min_ = f_min;
663 pNode->max_ = f_max;
664 }
665
666 /* Look for merging possibilities */
667 pNext = pNode->next_;
668 while ((pNext != NULL) && (pNext->min_ < pNode->max_)) {
669 if (pNext->max_ > pNode->max_)
670 pNode->max_ = pNext->max_;
671 pNext = RemoveNode(pAS_Info, pNode, pNext); /* Remove pNext, return ptr to pNext->next */
672 }
673 }
674}
675
676/*****************************************************************************
677**
678** Name: MT_ChooseFirstIF
679**
680** Description: Choose the best available 1st IF
681** If f_Desired is not excluded, choose that first.
682** Otherwise, return the value closest to f_Center that is
683** not excluded
684**
685** Revision History:
686**
687** SCR Date Author Description
688** -------------------------------------------------------------------------
689** 117 03-29-2007 RSK Ver 1.15: Re-wrote to match search order from
690** tuner DLL.
691** 147 07-27-2007 RSK Ver 1.17: Corrected calculation (-) to (+)
692** Added logic to force f_Center within 1/2 f_Step.
693**
694*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300695static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300696{
697 /*
698 ** Update "f_Desired" to be the nearest "combinational-multiple" of "f_LO1_Step".
699 ** The resulting number, F_LO1 must be a multiple of f_LO1_Step. And F_LO1 is the arithmetic sum
700 ** of f_in + f_Center. Neither f_in, nor f_Center must be a multiple of f_LO1_Step.
701 ** However, the sum must be.
702 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300703 const u32 f_Desired =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300704 pAS_Info->f_LO1_Step *
705 ((pAS_Info->f_if1_Request + pAS_Info->f_in +
706 pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) -
707 pAS_Info->f_in;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300708 const u32 f_Step =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300709 (pAS_Info->f_LO1_Step >
710 pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info->
711 f_LO2_Step;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300712 u32 f_Center;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300713
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300714 s32 i;
715 s32 j = 0;
716 u32 bDesiredExcluded = 0;
717 u32 bZeroExcluded = 0;
718 s32 tmpMin, tmpMax;
719 s32 bestDiff;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300720 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
721 struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES];
722
723 if (pAS_Info->nZones == 0)
724 return f_Desired;
725
726 /* f_Center needs to be an integer multiple of f_Step away from f_Desired */
727 if (pAS_Info->f_if1_Center > f_Desired)
728 f_Center =
729 f_Desired +
730 f_Step *
731 ((pAS_Info->f_if1_Center - f_Desired +
732 f_Step / 2) / f_Step);
733 else
734 f_Center =
735 f_Desired -
736 f_Step *
737 ((f_Desired - pAS_Info->f_if1_Center +
738 f_Step / 2) / f_Step);
739
740 //assert;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300741 //if (!abs((s32) f_Center - (s32) pAS_Info->f_if1_Center) <= (s32) (f_Step/2))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300742 // return 0;
743
744 /* Take MT_ExclZones, center around f_Center and change the resolution to f_Step */
745 while (pNode != NULL) {
746 /* floor function */
747 tmpMin =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300748 floor((s32) (pNode->min_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300749
750 /* ceil function */
751 tmpMax =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300752 ceil((s32) (pNode->max_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300753
754 if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired))
755 bDesiredExcluded = 1;
756
757 if ((tmpMin < 0) && (tmpMax > 0))
758 bZeroExcluded = 1;
759
760 /* See if this zone overlaps the previous */
761 if ((j > 0) && (tmpMin < zones[j - 1].max_))
762 zones[j - 1].max_ = tmpMax;
763 else {
764 /* Add new zone */
765 //assert(j<MT2063_MAX_ZONES);
766 //if (j>=MT2063_MAX_ZONES)
767 //break;
768
769 zones[j].min_ = tmpMin;
770 zones[j].max_ = tmpMax;
771 j++;
772 }
773 pNode = pNode->next_;
774 }
775
776 /*
777 ** If the desired is okay, return with it
778 */
779 if (bDesiredExcluded == 0)
780 return f_Desired;
781
782 /*
783 ** If the desired is excluded and the center is okay, return with it
784 */
785 if (bZeroExcluded == 0)
786 return f_Center;
787
788 /* Find the value closest to 0 (f_Center) */
789 bestDiff = zones[0].min_;
790 for (i = 0; i < j; i++) {
791 if (abs(zones[i].min_) < abs(bestDiff))
792 bestDiff = zones[i].min_;
793 if (abs(zones[i].max_) < abs(bestDiff))
794 bestDiff = zones[i].max_;
795 }
796
797 if (bestDiff < 0)
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300798 return f_Center - ((u32) (-bestDiff) * f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300799
800 return f_Center + (bestDiff * f_Step);
801}
802
803/****************************************************************************
804**
805** Name: gcd
806**
807** Description: Uses Euclid's algorithm
808**
809** Parameters: u, v - unsigned values whose GCD is desired.
810**
811** Global: None
812**
813** Returns: greatest common divisor of u and v, if either value
814** is 0, the other value is returned as the result.
815**
816** Dependencies: None.
817**
818** Revision History:
819**
820** SCR Date Author Description
821** -------------------------------------------------------------------------
822** N/A 06-01-2004 JWS Original
823** N/A 08-03-2004 DAD Changed to Euclid's since it can handle
824** unsigned numbers.
825**
826****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300827static u32 MT2063_gcd(u32 u, u32 v)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300828{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300829 u32 r;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300830
831 while (v != 0) {
832 r = u % v;
833 u = v;
834 v = r;
835 }
836
837 return u;
838}
839
840/****************************************************************************
841**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300842** Name: IsSpurInBand
843**
844** Description: Checks to see if a spur will be present within the IF's
845** bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW)
846**
847** ma mb mc md
848** <--+-+-+-------------------+-------------------+-+-+-->
849** | ^ 0 ^ |
850** ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^
851** a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2
852**
853** Note that some equations are doubled to prevent round-off
854** problems when calculating fIFBW/2
855**
856** Parameters: pAS_Info - Avoid Spurs information block
857** fm - If spur, amount f_IF1 has to move negative
858** fp - If spur, amount f_IF1 has to move positive
859**
860** Global: None
861**
862** Returns: 1 if an LO spur would be present, otherwise 0.
863**
864** Dependencies: None.
865**
866** Revision History:
867**
868** SCR Date Author Description
869** -------------------------------------------------------------------------
870** N/A 11-28-2002 DAD Implemented algorithm from applied patent
871**
872****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300873static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info,
874 u32 * fm, u32 * fp)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300875{
876 /*
877 ** Calculate LO frequency settings.
878 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300879 u32 n, n0;
880 const u32 f_LO1 = pAS_Info->f_LO1;
881 const u32 f_LO2 = pAS_Info->f_LO2;
882 const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2;
883 const u32 c = d - pAS_Info->f_out_bw;
884 const u32 f = pAS_Info->f_zif_bw / 2;
Mauro Carvalho Chehabd0dcc2d2011-07-21 02:30:19 -0300885 const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300886 s32 f_nsLO1, f_nsLO2;
887 s32 f_Spur;
888 u32 ma, mb, mc, md, me, mf;
889 u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300890 *fm = 0;
891
892 /*
893 ** For each edge (d, c & f), calculate a scale, based on the gcd
894 ** of f_LO1, f_LO2 and the edge value. Use the larger of this
895 ** gcd-based scale factor or f_Scale.
896 */
897 lo_gcd = MT2063_gcd(f_LO1, f_LO2);
Mauro Carvalho Chehabfd1126c2011-07-21 03:30:57 -0300898 gd_Scale = max((u32) MT2063_gcd(lo_gcd, d), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300899 hgds = gd_Scale / 2;
Mauro Carvalho Chehabfd1126c2011-07-21 03:30:57 -0300900 gc_Scale = max((u32) MT2063_gcd(lo_gcd, c), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300901 hgcs = gc_Scale / 2;
Mauro Carvalho Chehabfd1126c2011-07-21 03:30:57 -0300902 gf_Scale = max((u32) MT2063_gcd(lo_gcd, f), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300903 hgfs = gf_Scale / 2;
904
Mauro Carvalho Chehabe930b3a2011-07-21 03:02:16 -0300905 n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300906
907 /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */
908 for (n = n0; n <= pAS_Info->maxH1; ++n) {
909 md = (n * ((f_LO1 + hgds) / gd_Scale) -
910 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
911
912 /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */
913 if (md >= pAS_Info->maxH1)
914 break;
915
916 ma = (n * ((f_LO1 + hgds) / gd_Scale) +
917 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
918
919 /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */
920 if (md == ma)
921 continue;
922
923 mc = (n * ((f_LO1 + hgcs) / gc_Scale) -
924 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
925 if (mc != md) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300926 f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale));
927 f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale));
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300928 f_Spur =
929 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
930 n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale);
931
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300932 *fp = ((f_Spur - (s32) c) / (mc - n)) + 1;
933 *fm = (((s32) d - f_Spur) / (mc - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300934 return 1;
935 }
936
937 /* Location of Zero-IF-spur to be checked */
938 me = (n * ((f_LO1 + hgfs) / gf_Scale) +
939 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
940 mf = (n * ((f_LO1 + hgfs) / gf_Scale) -
941 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
942 if (me != mf) {
943 f_nsLO1 = n * (f_LO1 / gf_Scale);
944 f_nsLO2 = me * (f_LO2 / gf_Scale);
945 f_Spur =
946 (gf_Scale * (f_nsLO1 - f_nsLO2)) +
947 n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale);
948
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300949 *fp = ((f_Spur + (s32) f) / (me - n)) + 1;
950 *fm = (((s32) f - f_Spur) / (me - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300951 return 1;
952 }
953
954 mb = (n * ((f_LO1 + hgcs) / gc_Scale) +
955 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
956 if (ma != mb) {
957 f_nsLO1 = n * (f_LO1 / gc_Scale);
958 f_nsLO2 = ma * (f_LO2 / gc_Scale);
959 f_Spur =
960 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
961 n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale);
962
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300963 *fp = (((s32) d + f_Spur) / (ma - n)) + 1;
964 *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300965 return 1;
966 }
967 }
968
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300969 /* No spurs found */
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300970 return 0;
971}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300972
973/*****************************************************************************
974**
975** Name: MT_AvoidSpurs
976**
977** Description: Main entry point to avoid spurs.
978** Checks for existing spurs in present LO1, LO2 freqs
979** and if present, chooses spur-free LO1, LO2 combination
980** that tunes the same input/output frequencies.
981**
982** Revision History:
983**
984** SCR Date Author Description
985** -------------------------------------------------------------------------
986** 096 04-06-2005 DAD Ver 1.11: Fix divide by 0 error if maxH==0.
987**
988*****************************************************************************/
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300989static u32 MT2063_AvoidSpurs(void *h, struct MT2063_AvoidSpursData_t * pAS_Info)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300990{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300991 u32 status = 0;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300992 u32 fm, fp; /* restricted range on LO's */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300993 pAS_Info->bSpurAvoided = 0;
994 pAS_Info->nSpursFound = 0;
995
996 if (pAS_Info->maxH1 == 0)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300997 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300998
999 /*
1000 ** Avoid LO Generated Spurs
1001 **
1002 ** Make sure that have no LO-related spurs within the IF output
1003 ** bandwidth.
1004 **
1005 ** If there is an LO spur in this band, start at the current IF1 frequency
1006 ** and work out until we find a spur-free frequency or run up against the
1007 ** 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they
1008 ** will be unchanged if a spur-free setting is not found.
1009 */
1010 pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
1011 if (pAS_Info->bSpurPresent) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001012 u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */
1013 u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */
1014 u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */
1015 u32 delta_IF1;
1016 u32 new_IF1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001017
1018 /*
1019 ** Spur was found, attempt to find a spur-free 1st IF
1020 */
1021 do {
1022 pAS_Info->nSpursFound++;
1023
1024 /* Raise f_IF1_upper, if needed */
1025 MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp);
1026
1027 /* Choose next IF1 that is closest to f_IF1_CENTER */
1028 new_IF1 = MT2063_ChooseFirstIF(pAS_Info);
1029
1030 if (new_IF1 > zfIF1) {
1031 pAS_Info->f_LO1 += (new_IF1 - zfIF1);
1032 pAS_Info->f_LO2 += (new_IF1 - zfIF1);
1033 } else {
1034 pAS_Info->f_LO1 -= (zfIF1 - new_IF1);
1035 pAS_Info->f_LO2 -= (zfIF1 - new_IF1);
1036 }
1037 zfIF1 = new_IF1;
1038
1039 if (zfIF1 > pAS_Info->f_if1_Center)
1040 delta_IF1 = zfIF1 - pAS_Info->f_if1_Center;
1041 else
1042 delta_IF1 = pAS_Info->f_if1_Center - zfIF1;
1043 }
1044 /*
1045 ** Continue while the new 1st IF is still within the 1st IF bandwidth
1046 ** and there is a spur in the band (again)
1047 */
1048 while ((2 * delta_IF1 + pAS_Info->f_out_bw <=
1049 pAS_Info->f_if1_bw)
1050 && (pAS_Info->bSpurPresent =
1051 IsSpurInBand(pAS_Info, &fm, &fp)));
1052
1053 /*
1054 ** Use the LO-spur free values found. If the search went all the way to
1055 ** the 1st IF band edge and always found spurs, just leave the original
1056 ** choice. It's as "good" as any other.
1057 */
1058 if (pAS_Info->bSpurPresent == 1) {
1059 status |= MT2063_SPUR_PRESENT_ERR;
1060 pAS_Info->f_LO1 = zfLO1;
1061 pAS_Info->f_LO2 = zfLO2;
1062 } else
1063 pAS_Info->bSpurAvoided = 1;
1064 }
1065
1066 status |=
1067 ((pAS_Info->
1068 nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK);
1069
1070 return (status);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001071}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001072
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001073/*
1074** The expected version of MT_AvoidSpursData_t
1075** If the version is different, an updated file is needed from Microtune
1076*/
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001077
1078typedef enum {
1079 MT2063_SET_ATTEN,
1080 MT2063_INCR_ATTEN,
1081 MT2063_DECR_ATTEN
1082} MT2063_ATTEN_CNTL_MODE;
1083
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001084/*
Mauro Carvalho Chehab66aea302011-07-21 03:57:10 -03001085 * Constants used by the tuning algorithm
1086 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001087#define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */
1088#define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */
1089#define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */
1090#define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */
1091#define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */
1092#define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */
1093#define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */
1094#define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */
1095#define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */
1096#define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */
1097#define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */
1098#define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */
1099#define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */
1100#define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */
1101#define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */
1102#define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */
1103#define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */
1104#define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */
1105
1106/*
1107** Define the supported Part/Rev codes for the MT2063
1108*/
1109#define MT2063_B0 (0x9B)
1110#define MT2063_B1 (0x9C)
1111#define MT2063_B2 (0x9D)
1112#define MT2063_B3 (0x9E)
1113
1114/*
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001115** Constants for setting receiver modes.
1116** (6 modes defined at this time, enumerated by MT2063_RCVR_MODES)
1117** (DNC1GC & DNC2GC are the values, which are used, when the specific
1118** DNC Output is selected, the other is always off)
1119**
1120** If PAL-L or L' is received, set:
1121** MT2063_SetParam(hMT2063,MT2063_TAGC,1);
1122**
1123** --------------+----------------------------------------------
1124** Mode 0 : | MT2063_CABLE_QAM
1125** Mode 1 : | MT2063_CABLE_ANALOG
1126** Mode 2 : | MT2063_OFFAIR_COFDM
1127** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
1128** Mode 4 : | MT2063_OFFAIR_ANALOG
1129** Mode 5 : | MT2063_OFFAIR_8VSB
1130** --------------+----+----+----+----+-----+-----+--------------
1131** Mode | 0 | 1 | 2 | 3 | 4 | 5 |
1132** --------------+----+----+----+----+-----+-----+
1133**
1134**
1135*/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001136static const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 };
1137static const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 };
1138static const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 };
1139static const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 };
1140static const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 };
1141static const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 };
1142static const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 };
1143static const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 };
1144static const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
1145static const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 };
1146static const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 };
1147static const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
1148static const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 };
1149static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 };
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001150
1151/*
1152** Local Function Prototypes - not available for external access.
1153*/
1154
1155/* Forward declaration(s): */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001156static u32 MT2063_CalcLO1Mult(u32 * Div, u32 * FracN, u32 f_LO,
1157 u32 f_LO_Step, u32 f_Ref);
1158static u32 MT2063_CalcLO2Mult(u32 * Div, u32 * FracN, u32 f_LO,
1159 u32 f_LO_Step, u32 f_Ref);
1160static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num,
1161 u32 denom);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001162
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001163/**
1164 * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked
1165 *
1166 * @state: struct mt2063_state pointer
1167 *
1168 * This function returns 0, if no lock, 1 if locked and a value < 1 if error
1169 */
1170unsigned int mt2063_lockStatus(struct mt2063_state *state)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001171{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001172 const u32 nMaxWait = 100; /* wait a maximum of 100 msec */
1173 const u32 nPollRate = 2; /* poll status bits every 2 ms */
1174 const u32 nMaxLoops = nMaxWait / nPollRate;
1175 const u8 LO1LK = 0x80;
1176 u8 LO2LK = 0x08;
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001177 u32 status;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001178 u32 nDelays = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001179
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001180 /* LO2 Lock bit was in a different place for B0 version */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001181 if (state->tuner_id == MT2063_B0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001182 LO2LK = 0x40;
1183
1184 do {
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001185 status = mt2063_read(state, MT2063_REG_LO_STATUS,
1186 &state->reg[MT2063_REG_LO_STATUS], 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001187
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001188 if (status < 0)
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001189 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001190
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001191 if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) ==
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001192 (LO1LK | LO2LK)) {
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001193 return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001194 }
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03001195 msleep(nPollRate); /* Wait between retries */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001196 }
1197 while (++nDelays < nMaxLoops);
1198
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001199 /*
1200 * Got no lock or partial lock
1201 */
1202 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001203}
1204
1205/****************************************************************************
1206**
1207** Name: MT2063_GetParam
1208**
1209** Description: Gets a tuning algorithm parameter.
1210**
1211** This function provides access to the internals of the
1212** tuning algorithm - mostly for testing purposes.
1213**
1214** Parameters: h - Tuner handle (returned by MT2063_Open)
1215** param - Tuning algorithm parameter
1216** (see enum MT2063_Param)
1217** pValue - ptr to returned value
1218**
1219** param Description
1220** ---------------------- --------------------------------
1221** MT2063_IC_ADDR Serial Bus address of this tuner
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001222** MT2063_SRO_FREQ crystal frequency
1223** MT2063_STEPSIZE minimum tuning step size
1224** MT2063_INPUT_FREQ input center frequency
1225** MT2063_LO1_FREQ LO1 Frequency
1226** MT2063_LO1_STEPSIZE LO1 minimum step size
1227** MT2063_LO1_FRACN_AVOID LO1 FracN keep-out region
1228** MT2063_IF1_ACTUAL Current 1st IF in use
1229** MT2063_IF1_REQUEST Requested 1st IF
1230** MT2063_IF1_CENTER Center of 1st IF SAW filter
1231** MT2063_IF1_BW Bandwidth of 1st IF SAW filter
1232** MT2063_ZIF_BW zero-IF bandwidth
1233** MT2063_LO2_FREQ LO2 Frequency
1234** MT2063_LO2_STEPSIZE LO2 minimum step size
1235** MT2063_LO2_FRACN_AVOID LO2 FracN keep-out region
1236** MT2063_OUTPUT_FREQ output center frequency
1237** MT2063_OUTPUT_BW output bandwidth
1238** MT2063_LO_SEPARATION min inter-tuner LO separation
1239** MT2063_AS_ALG ID of avoid-spurs algorithm in use
1240** MT2063_MAX_HARM1 max # of intra-tuner harmonics
1241** MT2063_MAX_HARM2 max # of inter-tuner harmonics
1242** MT2063_EXCL_ZONES # of 1st IF exclusion zones
1243** MT2063_NUM_SPURS # of spurs found/avoided
1244** MT2063_SPUR_AVOIDED >0 spurs avoided
1245** MT2063_SPUR_PRESENT >0 spurs in output (mathematically)
1246** MT2063_RCVR_MODE Predefined modes.
1247** MT2063_ACLNA LNA attenuator gain code
1248** MT2063_ACRF RF attenuator gain code
1249** MT2063_ACFIF FIF attenuator gain code
1250** MT2063_ACLNA_MAX LNA attenuator limit
1251** MT2063_ACRF_MAX RF attenuator limit
1252** MT2063_ACFIF_MAX FIF attenuator limit
1253** MT2063_PD1 Actual value of PD1
1254** MT2063_PD2 Actual value of PD2
1255** MT2063_DNC_OUTPUT_ENABLE DNC output selection
1256** MT2063_VGAGC VGA gain code
1257** MT2063_VGAOI VGA output current
1258** MT2063_TAGC TAGC setting
1259** MT2063_AMPGC AMP gain code
1260** MT2063_AVOID_DECT Avoid DECT Frequencies
1261** MT2063_CTFILT_SW Cleartune filter selection
1262**
1263** Usage: status |= MT2063_GetParam(hMT2063,
1264** MT2063_IF1_ACTUAL,
1265** &f_IF1_Actual);
1266**
1267** Returns: status:
1268** MT_OK - No errors
1269** MT_INV_HANDLE - Invalid tuner handle
1270** MT_ARG_NULL - Null pointer argument passed
1271** MT_ARG_RANGE - Invalid parameter requested
1272**
1273** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
1274**
1275** See Also: MT2063_SetParam, MT2063_Open
1276**
1277** Revision History:
1278**
1279** SCR Date Author Description
1280** -------------------------------------------------------------------------
1281** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1282** 154 09-13-2007 RSK Ver 1.05: Get/SetParam changes for LOx_FREQ
1283** 10-31-2007 PINZ Ver 1.08: Get/SetParam add VGAGC, VGAOI, AMPGC, TAGC
1284** 173 M 01-23-2008 RSK Ver 1.12: Read LO1C and LO2C registers from HW
1285** in GetParam.
1286** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
1287** Split SetParam up to ACLNA / ACLNA_MAX
1288** removed ACLNA_INRC/DECR (+RF & FIF)
1289** removed GCUAUTO / BYPATNDN/UP
1290** 175 I 16-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
1291** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
1292** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
1293**
1294****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001295static u32 MT2063_GetParam(struct mt2063_state *state, enum MT2063_Param param, u32 *pValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001296{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001297 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001298 u32 Div;
1299 u32 Num;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001300
1301 if (pValue == NULL)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001302 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001303
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001304 switch (param) {
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001305 /* input center frequency */
1306 case MT2063_INPUT_FREQ:
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001307 *pValue = state->AS_Data.f_in;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001308 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001309
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001310 /* LO1 Frequency */
1311 case MT2063_LO1_FREQ:
1312 {
1313 /* read the actual tuner register values for LO1C_1 and LO1C_2 */
1314 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001315 mt2063_read(state,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001316 MT2063_REG_LO1C_1,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001317 &state->
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001318 reg[MT2063_REG_LO1C_1], 2);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001319 Div = state->reg[MT2063_REG_LO1C_1];
1320 Num = state->reg[MT2063_REG_LO1C_2] & 0x3F;
1321 state->AS_Data.f_LO1 =
1322 (state->AS_Data.f_ref * Div) +
1323 MT2063_fLO_FractionalTerm(state->AS_Data.
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001324 f_ref, Num, 64);
1325 }
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001326 *pValue = state->AS_Data.f_LO1;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001327 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001328
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001329 /* Bandwidth of 1st IF SAW filter */
1330 case MT2063_IF1_BW:
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001331 *pValue = state->AS_Data.f_if1_bw;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001332 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001333
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001334 /* zero-IF bandwidth */
1335 case MT2063_ZIF_BW:
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001336 *pValue = state->AS_Data.f_zif_bw;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001337 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001338
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001339 /* LO2 Frequency */
1340 case MT2063_LO2_FREQ:
1341 {
1342 /* Read the actual tuner register values for LO2C_1, LO2C_2 and LO2C_3 */
1343 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001344 mt2063_read(state,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001345 MT2063_REG_LO2C_1,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001346 &state->
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001347 reg[MT2063_REG_LO2C_1], 3);
1348 Div =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001349 (state->reg[MT2063_REG_LO2C_1] & 0xFE) >> 1;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001350 Num =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001351 ((state->
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001352 reg[MT2063_REG_LO2C_1] & 0x01) << 12) |
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001353 (state->
1354 reg[MT2063_REG_LO2C_2] << 4) | (state->
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001355 reg
1356 [MT2063_REG_LO2C_3]
1357 & 0x00F);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001358 state->AS_Data.f_LO2 =
1359 (state->AS_Data.f_ref * Div) +
1360 MT2063_fLO_FractionalTerm(state->AS_Data.
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001361 f_ref, Num, 8191);
1362 }
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001363 *pValue = state->AS_Data.f_LO2;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001364 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001365
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001366 /* LO2 FracN keep-out region */
1367 case MT2063_LO2_FRACN_AVOID:
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001368 *pValue = state->AS_Data.f_LO2_FracN_Avoid;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001369 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001370
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001371 /* output center frequency */
1372 case MT2063_OUTPUT_FREQ:
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001373 *pValue = state->AS_Data.f_out;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001374 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001375
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001376 /* output bandwidth */
1377 case MT2063_OUTPUT_BW:
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001378 *pValue = state->AS_Data.f_out_bw - 750000;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001379 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001380
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001381 /* Predefined receiver setup combination */
1382 case MT2063_RCVR_MODE:
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001383 *pValue = state->rcvr_mode;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001384 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001385
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001386 case MT2063_PD1:
1387 case MT2063_PD2: {
1388 u8 mask = (param == MT2063_PD1 ? 0x01 : 0x03); /* PD1 vs PD2 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001389 u8 orig = (state->reg[MT2063_REG_BYP_CTRL]);
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001390 u8 reg = (orig & 0xF1) | mask; /* Only set 3 bits (not 5) */
1391 int i;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001392
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001393 *pValue = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001394
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001395 /* Initiate ADC output to reg 0x0A */
1396 if (reg != orig)
1397 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001398 mt2063_write(state,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001399 MT2063_REG_BYP_CTRL,
1400 &reg, 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001401
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001402 if (status < 0)
1403 return (status);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001404
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001405 for (i = 0; i < 8; i++) {
1406 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001407 mt2063_read(state,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001408 MT2063_REG_ADC_OUT,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001409 &state->
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001410 reg
1411 [MT2063_REG_ADC_OUT],
1412 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001413
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001414 if (status >= 0)
1415 *pValue +=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001416 state->
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001417 reg[MT2063_REG_ADC_OUT];
1418 else {
1419 if (i)
1420 *pValue /= i;
1421 return (status);
1422 }
1423 }
1424 *pValue /= 8; /* divide by number of reads */
1425 *pValue >>= 2; /* only want 6 MSB's out of 8 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001426
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001427 /* Restore value of Register BYP_CTRL */
1428 if (reg != orig)
1429 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001430 mt2063_write(state,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001431 MT2063_REG_BYP_CTRL,
1432 &orig, 1);
1433 }
1434 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001435
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001436 /* Get LNA attenuator code */
1437 case MT2063_ACLNA:
1438 {
1439 u8 val;
1440 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001441 MT2063_GetReg(state, MT2063_REG_XO_STATUS,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001442 &val);
1443 *pValue = val & 0x1f;
1444 }
1445 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001446
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001447 /* Get RF attenuator code */
1448 case MT2063_ACRF:
1449 {
1450 u8 val;
1451 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001452 MT2063_GetReg(state, MT2063_REG_RF_STATUS,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001453 &val);
1454 *pValue = val & 0x1f;
1455 }
1456 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001457
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001458 /* Get FIF attenuator code */
1459 case MT2063_ACFIF:
1460 {
1461 u8 val;
1462 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001463 MT2063_GetReg(state, MT2063_REG_FIF_STATUS,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001464 &val);
1465 *pValue = val & 0x1f;
1466 }
1467 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001468
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001469 /* Get LNA attenuator limit */
1470 case MT2063_ACLNA_MAX:
1471 {
1472 u8 val;
1473 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001474 MT2063_GetReg(state, MT2063_REG_LNA_OV,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001475 &val);
1476 *pValue = val & 0x1f;
1477 }
1478 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001479
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001480 /* Get RF attenuator limit */
1481 case MT2063_ACRF_MAX:
1482 {
1483 u8 val;
1484 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001485 MT2063_GetReg(state, MT2063_REG_RF_OV,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001486 &val);
1487 *pValue = val & 0x1f;
1488 }
1489 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001490
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001491 /* Get FIF attenuator limit */
1492 case MT2063_ACFIF_MAX:
1493 {
1494 u8 val;
1495 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001496 MT2063_GetReg(state, MT2063_REG_FIF_OV,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001497 &val);
1498 *pValue = val & 0x1f;
1499 }
1500 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001501
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001502 /* Get current used DNC output */
1503 case MT2063_DNC_OUTPUT_ENABLE:
1504 {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001505 if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */
1506 if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001507 *pValue =
1508 (u32) MT2063_DNC_NONE;
1509 else
1510 *pValue =
1511 (u32) MT2063_DNC_2;
1512 } else { /* DNC1 is on */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001513
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001514 if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001515 *pValue =
1516 (u32) MT2063_DNC_1;
1517 else
1518 *pValue =
1519 (u32) MT2063_DNC_BOTH;
1520 }
1521 }
1522 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001523
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001524 default:
1525 status |= -ERANGE;
1526 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001527 return (status);
1528}
1529
1530/****************************************************************************
1531**
1532** Name: MT2063_GetReg
1533**
1534** Description: Gets an MT2063 register.
1535**
1536** Parameters: h - Tuner handle (returned by MT2063_Open)
1537** reg - MT2063 register/subaddress location
1538** *val - MT2063 register/subaddress value
1539**
1540** Returns: status:
1541** MT_OK - No errors
1542** MT_COMM_ERR - Serial bus communications error
1543** MT_INV_HANDLE - Invalid tuner handle
1544** MT_ARG_NULL - Null pointer argument passed
1545** MT_ARG_RANGE - Argument out of range
1546**
1547** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
1548**
1549** Use this function if you need to read a register from
1550** the MT2063.
1551**
1552** Revision History:
1553**
1554** SCR Date Author Description
1555** -------------------------------------------------------------------------
1556** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1557**
1558****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001559static u32 MT2063_GetReg(struct mt2063_state *state, u8 reg, u8 * val)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001560{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001561 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001562
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001563 if (val == NULL)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001564 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001565
1566 if (reg >= MT2063_REG_END_REGS)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001567 return -ERANGE;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001568
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001569 status = mt2063_read(state, reg, &state->reg[reg], 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001570
1571 return (status);
1572}
1573
1574/******************************************************************************
1575**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001576** Name: MT2063_SetReceiverMode
1577**
1578** Description: Set the MT2063 receiver mode
1579**
1580** --------------+----------------------------------------------
1581** Mode 0 : | MT2063_CABLE_QAM
1582** Mode 1 : | MT2063_CABLE_ANALOG
1583** Mode 2 : | MT2063_OFFAIR_COFDM
1584** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
1585** Mode 4 : | MT2063_OFFAIR_ANALOG
1586** Mode 5 : | MT2063_OFFAIR_8VSB
1587** --------------+----+----+----+----+-----+--------------------
1588** (DNC1GC & DNC2GC are the values, which are used, when the specific
1589** DNC Output is selected, the other is always off)
1590**
1591** |<---------- Mode -------------->|
1592** Reg Field | 0 | 1 | 2 | 3 | 4 | 5 |
1593** ------------+-----+-----+-----+-----+-----+-----+
1594** RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF
1595** LNARin | 0 | 0 | 3 | 3 | 3 | 3
1596** FIFFQen | 1 | 1 | 1 | 1 | 1 | 1
1597** FIFFq | 0 | 0 | 0 | 0 | 0 | 0
1598** DNC1gc | 0 | 0 | 0 | 0 | 0 | 0
1599** DNC2gc | 0 | 0 | 0 | 0 | 0 | 0
1600** GCU Auto | 1 | 1 | 1 | 1 | 1 | 1
1601** LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31
1602** LNA Target | 44 | 43 | 43 | 43 | 43 | 43
1603** ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0
1604** RF max Atn | 31 | 31 | 31 | 31 | 31 | 31
1605** PD1 Target | 36 | 36 | 38 | 38 | 36 | 38
1606** ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0
1607** FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5
1608** PD2 Target | 40 | 33 | 42 | 42 | 33 | 42
1609**
1610**
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001611** Parameters: state - ptr to mt2063_state structure
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001612** Mode - desired reciever mode
1613**
1614** Usage: status = MT2063_SetReceiverMode(hMT2063, Mode);
1615**
1616** Returns: status:
1617** MT_OK - No errors
1618** MT_COMM_ERR - Serial bus communications error
1619**
1620** Dependencies: MT2063_SetReg - Write a byte of data to a HW register.
1621** Assumes that the tuner cache is valid.
1622**
1623** Revision History:
1624**
1625** SCR Date Author Description
1626** -------------------------------------------------------------------------
1627** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1628** N/A 01-10-2007 PINZ Added additional GCU Settings, FIFF Calib will be triggered
1629** 155 10-01-2007 DAD Ver 1.06: Add receiver mode for SECAM positive
1630** modulation
1631** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
1632** N/A 10-22-2007 PINZ Ver 1.07: Changed some Registers at init to have
1633** the same settings as with MT Launcher
1634** N/A 10-30-2007 PINZ Add SetParam VGAGC & VGAOI
1635** Add SetParam DNC_OUTPUT_ENABLE
1636** Removed VGAGC from receiver mode,
1637** default now 1
1638** N/A 10-31-2007 PINZ Ver 1.08: Add SetParam TAGC, removed from rcvr-mode
1639** Add SetParam AMPGC, removed from rcvr-mode
1640** Corrected names of GCU values
1641** reorganized receiver modes, removed,
1642** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE)
1643** Actualized Receiver-Mode values
1644** N/A 11-12-2007 PINZ Ver 1.09: Actualized Receiver-Mode values
1645** N/A 11-27-2007 PINZ Improved buffered writing
1646** 01-03-2008 PINZ Ver 1.10: Added a trigger of BYPATNUP for
1647** correct wakeup of the LNA after shutdown
1648** Set AFCsd = 1 as default
1649** Changed CAP1sel default
1650** 01-14-2008 PINZ Ver 1.11: Updated gain settings
1651** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
1652** Split SetParam up to ACLNA / ACLNA_MAX
1653** removed ACLNA_INRC/DECR (+RF & FIF)
1654** removed GCUAUTO / BYPATNDN/UP
1655**
1656******************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001657static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001658 enum MT2063_RCVR_MODES Mode)
1659{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001660 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001661 u8 val;
1662 u32 longval;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001663
1664 if (Mode >= MT2063_NUM_RCVR_MODES)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001665 status = -ERANGE;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001666
1667 /* RFAGCen */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001668 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001669 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001670 (state->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001671 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x40) | (RFAGCEN[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001672 ? 0x40 :
1673 0x00);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001674 if (state->reg[MT2063_REG_PD1_TGT] != val) {
1675 status |= MT2063_SetReg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001676 }
1677 }
1678
1679 /* LNARin */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001680 if (status >= 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001681 status |= MT2063_SetParam(state, MT2063_LNA_RIN, LNARIN[Mode]);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001682 }
1683
1684 /* FIFFQEN and FIFFQ */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001685 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001686 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001687 (state->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001688 reg[MT2063_REG_FIFF_CTRL2] & (u8) ~ 0xF0) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001689 (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001690 if (state->reg[MT2063_REG_FIFF_CTRL2] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001691 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001692 MT2063_SetReg(state, MT2063_REG_FIFF_CTRL2, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001693 /* trigger FIFF calibration, needed after changing FIFFQ */
1694 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001695 (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001696 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001697 MT2063_SetReg(state, MT2063_REG_FIFF_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001698 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001699 (state->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001700 reg[MT2063_REG_FIFF_CTRL] & (u8) ~ 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001701 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001702 MT2063_SetReg(state, MT2063_REG_FIFF_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001703 }
1704 }
1705
1706 /* DNC1GC & DNC2GC */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001707 status |= MT2063_GetParam(state, MT2063_DNC_OUTPUT_ENABLE, &longval);
1708 status |= MT2063_SetParam(state, MT2063_DNC_OUTPUT_ENABLE, longval);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001709
1710 /* acLNAmax */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001711 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001712 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001713 MT2063_SetParam(state, MT2063_ACLNA_MAX, ACLNAMAX[Mode]);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001714 }
1715
1716 /* LNATGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001717 if (status >= 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001718 status |= MT2063_SetParam(state, MT2063_LNA_TGT, LNATGT[Mode]);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001719 }
1720
1721 /* ACRF */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001722 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001723 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001724 MT2063_SetParam(state, MT2063_ACRF_MAX, ACRFMAX[Mode]);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001725 }
1726
1727 /* PD1TGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001728 if (status >= 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001729 status |= MT2063_SetParam(state, MT2063_PD1_TGT, PD1TGT[Mode]);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001730 }
1731
1732 /* FIFATN */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001733 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001734 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001735 MT2063_SetParam(state, MT2063_ACFIF_MAX, ACFIFMAX[Mode]);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001736 }
1737
1738 /* PD2TGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001739 if (status >= 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001740 status |= MT2063_SetParam(state, MT2063_PD2_TGT, PD2TGT[Mode]);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001741 }
1742
1743 /* Ignore ATN Overload */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001744 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001745 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001746 (state->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001747 reg[MT2063_REG_LNA_TGT] & (u8) ~ 0x80) | (RFOVDIS[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001748 ? 0x80 :
1749 0x00);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001750 if (state->reg[MT2063_REG_LNA_TGT] != val) {
1751 status |= MT2063_SetReg(state, MT2063_REG_LNA_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001752 }
1753 }
1754
1755 /* Ignore FIF Overload */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001756 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001757 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001758 (state->
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001759 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x80) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001760 (FIFOVDIS[Mode] ? 0x80 : 0x00);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001761 if (state->reg[MT2063_REG_PD1_TGT] != val) {
1762 status |= MT2063_SetReg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001763 }
1764 }
1765
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001766 if (status >= 0)
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001767 state->rcvr_mode = Mode;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001768
1769 return (status);
1770}
1771
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001772/****************************************************************************
1773**
1774** Name: MT2063_SetParam
1775**
1776** Description: Sets a tuning algorithm parameter.
1777**
1778** This function provides access to the internals of the
1779** tuning algorithm. You can override many of the tuning
1780** algorithm defaults using this function.
1781**
1782** Parameters: h - Tuner handle (returned by MT2063_Open)
1783** param - Tuning algorithm parameter
1784** (see enum MT2063_Param)
1785** nValue - value to be set
1786**
1787** param Description
1788** ---------------------- --------------------------------
1789** MT2063_SRO_FREQ crystal frequency
1790** MT2063_STEPSIZE minimum tuning step size
1791** MT2063_LO1_FREQ LO1 frequency
1792** MT2063_LO1_STEPSIZE LO1 minimum step size
1793** MT2063_LO1_FRACN_AVOID LO1 FracN keep-out region
1794** MT2063_IF1_REQUEST Requested 1st IF
1795** MT2063_ZIF_BW zero-IF bandwidth
1796** MT2063_LO2_FREQ LO2 frequency
1797** MT2063_LO2_STEPSIZE LO2 minimum step size
1798** MT2063_LO2_FRACN_AVOID LO2 FracN keep-out region
1799** MT2063_OUTPUT_FREQ output center frequency
1800** MT2063_OUTPUT_BW output bandwidth
1801** MT2063_LO_SEPARATION min inter-tuner LO separation
1802** MT2063_MAX_HARM1 max # of intra-tuner harmonics
1803** MT2063_MAX_HARM2 max # of inter-tuner harmonics
1804** MT2063_RCVR_MODE Predefined modes
1805** MT2063_LNA_RIN Set LNA Rin (*)
1806** MT2063_LNA_TGT Set target power level at LNA (*)
1807** MT2063_PD1_TGT Set target power level at PD1 (*)
1808** MT2063_PD2_TGT Set target power level at PD2 (*)
1809** MT2063_ACLNA_MAX LNA attenuator limit (*)
1810** MT2063_ACRF_MAX RF attenuator limit (*)
1811** MT2063_ACFIF_MAX FIF attenuator limit (*)
1812** MT2063_DNC_OUTPUT_ENABLE DNC output selection
1813** MT2063_VGAGC VGA gain code
1814** MT2063_VGAOI VGA output current
1815** MT2063_TAGC TAGC setting
1816** MT2063_AMPGC AMP gain code
1817** MT2063_AVOID_DECT Avoid DECT Frequencies
1818** MT2063_CTFILT_SW Cleartune filter selection
1819**
1820** (*) This parameter is set by MT2063_RCVR_MODE, do not call
1821** additionally.
1822**
1823** Usage: status |= MT2063_SetParam(hMT2063,
1824** MT2063_STEPSIZE,
1825** 50000);
1826**
1827** Returns: status:
1828** MT_OK - No errors
1829** MT_INV_HANDLE - Invalid tuner handle
1830** MT_ARG_NULL - Null pointer argument passed
1831** MT_ARG_RANGE - Invalid parameter requested
1832** or set value out of range
1833** or non-writable parameter
1834**
1835** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
1836**
1837** See Also: MT2063_GetParam, MT2063_Open
1838**
1839** Revision History:
1840**
1841** SCR Date Author Description
1842** -------------------------------------------------------------------------
1843** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
1844** 154 09-13-2007 RSK Ver 1.05: Get/SetParam changes for LOx_FREQ
1845** 10-31-2007 PINZ Ver 1.08: Get/SetParam add VGAGC, VGAOI, AMPGC, TAGC
1846** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT
1847** Split SetParam up to ACLNA / ACLNA_MAX
1848** removed ACLNA_INRC/DECR (+RF & FIF)
1849** removed GCUAUTO / BYPATNDN/UP
1850** 175 I 06-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
1851** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
1852** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
1853**
1854****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001855static u32 MT2063_SetParam(struct mt2063_state *state,
Mauro Carvalho Chehab29a0a4fe2011-07-20 23:44:10 -03001856 enum MT2063_Param param,
1857 enum MT2063_DNC_Output_Enable nValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001858{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001859 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001860 u8 val = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001861
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001862 switch (param) {
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001863 /* LO1 frequency */
1864 case MT2063_LO1_FREQ:
1865 {
1866 /* Note: LO1 and LO2 are BOTH written at toggle of LDLOos */
1867 /* Capture the Divider and Numerator portions of other LO */
1868 u8 tempLO2CQ[3];
1869 u8 tempLO2C[3];
1870 u8 tmpOneShot;
1871 u32 Div, FracN;
1872 u8 restore = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001873
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001874 /* Buffer the queue for restoration later and get actual LO2 values. */
1875 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001876 mt2063_read(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001877 MT2063_REG_LO2CQ_1,
1878 &(tempLO2CQ[0]), 3);
1879 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001880 mt2063_read(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001881 MT2063_REG_LO2C_1,
1882 &(tempLO2C[0]), 3);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001883
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001884 /* clear the one-shot bits */
1885 tempLO2CQ[2] = tempLO2CQ[2] & 0x0F;
1886 tempLO2C[2] = tempLO2C[2] & 0x0F;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001887
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001888 /* only write the queue values if they are different from the actual. */
1889 if ((tempLO2CQ[0] != tempLO2C[0]) ||
1890 (tempLO2CQ[1] != tempLO2C[1]) ||
1891 (tempLO2CQ[2] != tempLO2C[2])) {
1892 /* put actual LO2 value into queue (with 0 in one-shot bits) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001893 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001894 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001895 MT2063_REG_LO2CQ_1,
1896 &(tempLO2C[0]), 3);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001897
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001898 if (status == 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001899 /* cache the bytes just written. */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001900 state->reg[MT2063_REG_LO2CQ_1] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001901 tempLO2C[0];
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001902 state->reg[MT2063_REG_LO2CQ_2] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001903 tempLO2C[1];
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001904 state->reg[MT2063_REG_LO2CQ_3] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001905 tempLO2C[2];
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001906 }
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001907 restore = 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001908 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001909
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001910 /* Calculate the Divider and Numberator components of LO1 */
1911 status =
1912 MT2063_CalcLO1Mult(&Div, &FracN, nValue,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001913 state->AS_Data.f_ref /
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001914 64,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001915 state->AS_Data.f_ref);
1916 state->reg[MT2063_REG_LO1CQ_1] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001917 (u8) (Div & 0x00FF);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001918 state->reg[MT2063_REG_LO1CQ_2] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001919 (u8) (FracN);
1920 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001921 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001922 MT2063_REG_LO1CQ_1,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001923 &state->
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001924 reg[MT2063_REG_LO1CQ_1], 2);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001925
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001926 /* set the one-shot bit to load the pair of LO values */
1927 tmpOneShot = tempLO2CQ[2] | 0xE0;
1928 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001929 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001930 MT2063_REG_LO2CQ_3,
1931 &tmpOneShot, 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001932
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001933 /* only restore the queue values if they were different from the actual. */
1934 if (restore) {
1935 /* put actual LO2 value into queue (0 in one-shot bits) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001936 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001937 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001938 MT2063_REG_LO2CQ_1,
1939 &(tempLO2CQ[0]), 3);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001940
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001941 /* cache the bytes just written. */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001942 state->reg[MT2063_REG_LO2CQ_1] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001943 tempLO2CQ[0];
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001944 state->reg[MT2063_REG_LO2CQ_2] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001945 tempLO2CQ[1];
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001946 state->reg[MT2063_REG_LO2CQ_3] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001947 tempLO2CQ[2];
1948 }
1949
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001950 MT2063_GetParam(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001951 MT2063_LO1_FREQ,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001952 &state->AS_Data.f_LO1);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001953 }
1954 break;
1955
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001956 /* zero-IF bandwidth */
1957 case MT2063_ZIF_BW:
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001958 state->AS_Data.f_zif_bw = nValue;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001959 break;
1960
1961 /* LO2 frequency */
1962 case MT2063_LO2_FREQ:
1963 {
1964 /* Note: LO1 and LO2 are BOTH written at toggle of LDLOos */
1965 /* Capture the Divider and Numerator portions of other LO */
1966 u8 tempLO1CQ[2];
1967 u8 tempLO1C[2];
1968 u32 Div2;
1969 u32 FracN2;
1970 u8 tmpOneShot;
1971 u8 restore = 0;
1972
1973 /* Buffer the queue for restoration later and get actual LO2 values. */
1974 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001975 mt2063_read(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001976 MT2063_REG_LO1CQ_1,
1977 &(tempLO1CQ[0]), 2);
1978 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001979 mt2063_read(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001980 MT2063_REG_LO1C_1,
1981 &(tempLO1C[0]), 2);
1982
1983 /* only write the queue values if they are different from the actual. */
1984 if ((tempLO1CQ[0] != tempLO1C[0])
1985 || (tempLO1CQ[1] != tempLO1C[1])) {
1986 /* put actual LO1 value into queue */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001987 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001988 mt2063_write(state,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001989 MT2063_REG_LO1CQ_1,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001990 &(tempLO1C[0]), 2);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001991
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001992 /* cache the bytes just written. */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001993 state->reg[MT2063_REG_LO1CQ_1] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001994 tempLO1C[0];
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001995 state->reg[MT2063_REG_LO1CQ_2] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001996 tempLO1C[1];
1997 restore = 1;
1998 }
1999
2000 /* Calculate the Divider and Numberator components of LO2 */
2001 status =
2002 MT2063_CalcLO2Mult(&Div2, &FracN2, nValue,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002003 state->AS_Data.f_ref /
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002004 8191,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002005 state->AS_Data.f_ref);
2006 state->reg[MT2063_REG_LO2CQ_1] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002007 (u8) ((Div2 << 1) |
2008 ((FracN2 >> 12) & 0x01)) & 0xFF;
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002009 state->reg[MT2063_REG_LO2CQ_2] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002010 (u8) ((FracN2 >> 4) & 0xFF);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002011 state->reg[MT2063_REG_LO2CQ_3] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002012 (u8) ((FracN2 & 0x0F));
2013 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03002014 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002015 MT2063_REG_LO1CQ_1,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002016 &state->
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002017 reg[MT2063_REG_LO1CQ_1], 3);
2018
2019 /* set the one-shot bit to load the LO values */
2020 tmpOneShot =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002021 state->reg[MT2063_REG_LO2CQ_3] | 0xE0;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002022 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03002023 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002024 MT2063_REG_LO2CQ_3,
2025 &tmpOneShot, 1);
2026
2027 /* only restore LO1 queue value if they were different from the actual. */
2028 if (restore) {
2029 /* put previous LO1 queue value back into queue */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002030 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03002031 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002032 MT2063_REG_LO1CQ_1,
2033 &(tempLO1CQ[0]), 2);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002034
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002035 /* cache the bytes just written. */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002036 state->reg[MT2063_REG_LO1CQ_1] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002037 tempLO1CQ[0];
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002038 state->reg[MT2063_REG_LO1CQ_2] =
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002039 tempLO1CQ[1];
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002040 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002041
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002042 MT2063_GetParam(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002043 MT2063_LO2_FREQ,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002044 &state->AS_Data.f_LO2);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002045 }
2046 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002047
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002048 /* LO2 FracN keep-out region */
2049 case MT2063_LO2_FRACN_AVOID:
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002050 state->AS_Data.f_LO2_FracN_Avoid = nValue;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002051 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002052
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002053 /* output center frequency */
2054 case MT2063_OUTPUT_FREQ:
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002055 state->AS_Data.f_out = nValue;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002056 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002057
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002058 /* output bandwidth */
2059 case MT2063_OUTPUT_BW:
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002060 state->AS_Data.f_out_bw = nValue + 750000;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002061 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002062
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002063 case MT2063_RCVR_MODE:
2064 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002065 MT2063_SetReceiverMode(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002066 (enum MT2063_RCVR_MODES)
2067 nValue);
2068 break;
2069
2070 /* Set LNA Rin -- nValue is desired value */
2071 case MT2063_LNA_RIN:
2072 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002073 (state->
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002074 reg[MT2063_REG_CTRL_2C] & (u8) ~ 0x03) |
2075 (nValue & 0x03);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002076 if (state->reg[MT2063_REG_CTRL_2C] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002077 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002078 MT2063_SetReg(state, MT2063_REG_CTRL_2C,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002079 val);
2080 }
2081 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002082
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002083 /* Set target power level at LNA -- nValue is desired value */
2084 case MT2063_LNA_TGT:
2085 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002086 (state->
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002087 reg[MT2063_REG_LNA_TGT] & (u8) ~ 0x3F) |
2088 (nValue & 0x3F);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002089 if (state->reg[MT2063_REG_LNA_TGT] != val) {
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002090 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002091 MT2063_SetReg(state, MT2063_REG_LNA_TGT,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002092 val);
2093 }
2094 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002095
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002096 /* Set target power level at PD1 -- nValue is desired value */
2097 case MT2063_PD1_TGT:
2098 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002099 (state->
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002100 reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x3F) |
2101 (nValue & 0x3F);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002102 if (state->reg[MT2063_REG_PD1_TGT] != val) {
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002103 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002104 MT2063_SetReg(state, MT2063_REG_PD1_TGT,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002105 val);
2106 }
2107 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002108
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002109 /* Set target power level at PD2 -- nValue is desired value */
2110 case MT2063_PD2_TGT:
2111 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002112 (state->
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002113 reg[MT2063_REG_PD2_TGT] & (u8) ~ 0x3F) |
2114 (nValue & 0x3F);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002115 if (state->reg[MT2063_REG_PD2_TGT] != val) {
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002116 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002117 MT2063_SetReg(state, MT2063_REG_PD2_TGT,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002118 val);
2119 }
2120 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002121
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002122 /* Set LNA atten limit -- nValue is desired value */
2123 case MT2063_ACLNA_MAX:
2124 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002125 (state->
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002126 reg[MT2063_REG_LNA_OV] & (u8) ~ 0x1F) | (nValue
2127 &
2128 0x1F);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002129 if (state->reg[MT2063_REG_LNA_OV] != val) {
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002130 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002131 MT2063_SetReg(state, MT2063_REG_LNA_OV,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002132 val);
2133 }
2134 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002135
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002136 /* Set RF atten limit -- nValue is desired value */
2137 case MT2063_ACRF_MAX:
2138 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002139 (state->
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002140 reg[MT2063_REG_RF_OV] & (u8) ~ 0x1F) | (nValue
2141 &
2142 0x1F);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002143 if (state->reg[MT2063_REG_RF_OV] != val) {
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002144 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002145 MT2063_SetReg(state, MT2063_REG_RF_OV, val);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002146 }
2147 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002148
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002149 /* Set FIF atten limit -- nValue is desired value, max. 5 if no B3 */
2150 case MT2063_ACFIF_MAX:
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002151 if (state->reg[MT2063_REG_PART_REV] != MT2063_B3
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002152 && nValue > 5)
2153 nValue = 5;
2154 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002155 (state->
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002156 reg[MT2063_REG_FIF_OV] & (u8) ~ 0x1F) | (nValue
2157 &
2158 0x1F);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002159 if (state->reg[MT2063_REG_FIF_OV] != val) {
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002160 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002161 MT2063_SetReg(state, MT2063_REG_FIF_OV,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002162 val);
2163 }
2164 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002165
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002166 case MT2063_DNC_OUTPUT_ENABLE:
2167 /* selects, which DNC output is used */
Mauro Carvalho Chehab29a0a4fe2011-07-20 23:44:10 -03002168 switch (nValue) {
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002169 case MT2063_DNC_NONE:
2170 {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002171 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
2172 if (state->reg[MT2063_REG_DNC_GAIN] !=
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002173 val)
2174 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002175 MT2063_SetReg(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002176 MT2063_REG_DNC_GAIN,
2177 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002178
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002179 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
2180 if (state->reg[MT2063_REG_VGA_GAIN] !=
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002181 val)
2182 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002183 MT2063_SetReg(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002184 MT2063_REG_VGA_GAIN,
2185 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002186
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002187 val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
2188 if (state->reg[MT2063_REG_RSVD_20] !=
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002189 val)
2190 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002191 MT2063_SetReg(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002192 MT2063_REG_RSVD_20,
2193 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002194
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002195 break;
2196 }
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002197 case MT2063_DNC_1:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002198 {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002199 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */
2200 if (state->reg[MT2063_REG_DNC_GAIN] !=
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002201 val)
2202 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002203 MT2063_SetReg(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002204 MT2063_REG_DNC_GAIN,
2205 val);
2206
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002207 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
2208 if (state->reg[MT2063_REG_VGA_GAIN] !=
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002209 val)
2210 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002211 MT2063_SetReg(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002212 MT2063_REG_VGA_GAIN,
2213 val);
2214
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002215 val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
2216 if (state->reg[MT2063_REG_RSVD_20] !=
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002217 val)
2218 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002219 MT2063_SetReg(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002220 MT2063_REG_RSVD_20,
2221 val);
2222
2223 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002224 }
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002225 case MT2063_DNC_2:
2226 {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002227 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
2228 if (state->reg[MT2063_REG_DNC_GAIN] !=
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002229 val)
2230 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002231 MT2063_SetReg(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002232 MT2063_REG_DNC_GAIN,
2233 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002234
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002235 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */
2236 if (state->reg[MT2063_REG_VGA_GAIN] !=
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002237 val)
2238 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002239 MT2063_SetReg(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002240 MT2063_REG_VGA_GAIN,
2241 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002242
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002243 val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
2244 if (state->reg[MT2063_REG_RSVD_20] !=
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002245 val)
2246 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002247 MT2063_SetReg(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002248 MT2063_REG_RSVD_20,
2249 val);
2250
2251 break;
2252 }
2253 case MT2063_DNC_BOTH:
2254 {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002255 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */
2256 if (state->reg[MT2063_REG_DNC_GAIN] !=
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002257 val)
2258 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002259 MT2063_SetReg(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002260 MT2063_REG_DNC_GAIN,
2261 val);
2262
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002263 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */
2264 if (state->reg[MT2063_REG_VGA_GAIN] !=
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002265 val)
2266 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002267 MT2063_SetReg(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002268 MT2063_REG_VGA_GAIN,
2269 val);
2270
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002271 val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
2272 if (state->reg[MT2063_REG_RSVD_20] !=
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002273 val)
2274 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002275 MT2063_SetReg(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002276 MT2063_REG_RSVD_20,
2277 val);
2278
2279 break;
2280 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002281 default:
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002282 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002283 }
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002284 break;
2285
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002286 default:
2287 status |= -ERANGE;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002288 }
2289 return (status);
2290}
2291
2292/****************************************************************************
2293**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002294** Name: MT2063_ClearPowerMaskBits
2295**
2296** Description: Clears the power-down mask bits for various sections of
2297** the MT2063
2298**
2299** Parameters: h - Tuner handle (returned by MT2063_Open)
2300** Bits - Mask bits to be cleared.
2301**
2302** See definition of MT2063_Mask_Bits type for description
2303** of each of the power bits.
2304**
2305** Returns: status:
2306** MT_OK - No errors
2307** MT_INV_HANDLE - Invalid tuner handle
2308** MT_COMM_ERR - Serial bus communications error
2309**
2310** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
2311**
2312** Revision History:
2313**
2314** SCR Date Author Description
2315** -------------------------------------------------------------------------
2316** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2317**
2318****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002319static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, enum MT2063_Mask_Bits Bits)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002320{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002321 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002322
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002323 Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */
2324 if ((Bits & 0xFF00) != 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002325 state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002326 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03002327 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002328 MT2063_REG_PWR_2,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002329 &state->reg[MT2063_REG_PWR_2], 1);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002330 }
2331 if ((Bits & 0xFF) != 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002332 state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002333 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03002334 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002335 MT2063_REG_PWR_1,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002336 &state->reg[MT2063_REG_PWR_1], 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002337 }
2338
2339 return (status);
2340}
2341
2342/****************************************************************************
2343**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002344** Name: MT2063_SoftwareShutdown
2345**
2346** Description: Enables or disables software shutdown function. When
2347** Shutdown==1, any section whose power mask is set will be
2348** shutdown.
2349**
2350** Parameters: h - Tuner handle (returned by MT2063_Open)
2351** Shutdown - 1 = shutdown the masked sections, otherwise
2352** power all sections on
2353**
2354** Returns: status:
2355** MT_OK - No errors
2356** MT_INV_HANDLE - Invalid tuner handle
2357** MT_COMM_ERR - Serial bus communications error
2358**
2359** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
2360**
2361** Revision History:
2362**
2363** SCR Date Author Description
2364** -------------------------------------------------------------------------
2365** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2366** 01-03-2008 PINZ Ver 1.xx: Added a trigger of BYPATNUP for
2367** correct wakeup of the LNA
2368**
2369****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002370static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002371{
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03002372 u32 status; /* Status to be returned */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002373
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002374 if (Shutdown == 1)
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002375 state->reg[MT2063_REG_PWR_1] |= 0x04; /* Turn the bit on */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002376 else
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002377 state->reg[MT2063_REG_PWR_1] &= ~0x04; /* Turn off the bit */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002378
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03002379 status = mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002380 MT2063_REG_PWR_1,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002381 &state->reg[MT2063_REG_PWR_1], 1);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002382
2383 if (Shutdown != 1) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002384 state->reg[MT2063_REG_BYP_CTRL] =
2385 (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002386 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03002387 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002388 MT2063_REG_BYP_CTRL,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002389 &state->reg[MT2063_REG_BYP_CTRL],
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002390 1);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002391 state->reg[MT2063_REG_BYP_CTRL] =
2392 (state->reg[MT2063_REG_BYP_CTRL] & 0x9F);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002393 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03002394 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002395 MT2063_REG_BYP_CTRL,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002396 &state->reg[MT2063_REG_BYP_CTRL],
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002397 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002398 }
2399
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03002400 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002401}
2402
2403/****************************************************************************
2404**
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002405** Name: MT2063_SetReg
2406**
2407** Description: Sets an MT2063 register.
2408**
2409** Parameters: h - Tuner handle (returned by MT2063_Open)
2410** reg - MT2063 register/subaddress location
2411** val - MT2063 register/subaddress value
2412**
2413** Returns: status:
2414** MT_OK - No errors
2415** MT_COMM_ERR - Serial bus communications error
2416** MT_INV_HANDLE - Invalid tuner handle
2417** MT_ARG_RANGE - Argument out of range
2418**
2419** Dependencies: USERS MUST CALL MT2063_Open() FIRST!
2420**
2421** Use this function if you need to override a default
2422** register value
2423**
2424** Revision History:
2425**
2426** SCR Date Author Description
2427** -------------------------------------------------------------------------
2428** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2429**
2430****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002431static u32 MT2063_SetReg(struct mt2063_state *state, u8 reg, u8 val)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002432{
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03002433 u32 status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002434
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002435 if (reg >= MT2063_REG_END_REGS)
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03002436 return -ERANGE;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002437
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03002438 status = mt2063_write(state, reg, &val, 1);
2439 if (status < 0)
2440 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002441
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03002442 state->reg[reg] = val;
2443
2444 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002445}
2446
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002447static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002448{
2449 return f_ref * (f_LO / f_ref)
2450 + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step);
2451}
2452
2453/****************************************************************************
2454**
2455** Name: fLO_FractionalTerm
2456**
2457** Description: Calculates the portion contributed by FracN / denom.
2458**
2459** This function preserves maximum precision without
2460** risk of overflow. It accurately calculates
2461** f_ref * num / denom to within 1 HZ with fixed math.
2462**
2463** Parameters: num - Fractional portion of the multiplier
2464** denom - denominator portion of the ratio
2465** This routine successfully handles denom values
2466** up to and including 2^18.
2467** f_Ref - SRO frequency. This calculation handles
2468** f_ref as two separate 14-bit fields.
2469** Therefore, a maximum value of 2^28-1
2470** may safely be used for f_ref. This is
2471** the genesis of the magic number "14" and the
2472** magic mask value of 0x03FFF.
2473**
2474** Returns: f_ref * num / denom
2475**
2476** Revision History:
2477**
2478** SCR Date Author Description
2479** -------------------------------------------------------------------------
2480** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2481**
2482****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002483static u32 MT2063_fLO_FractionalTerm(u32 f_ref,
2484 u32 num, u32 denom)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002485{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002486 u32 t1 = (f_ref >> 14) * num;
2487 u32 term1 = t1 / denom;
2488 u32 loss = t1 % denom;
2489 u32 term2 =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002490 (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom;
2491 return ((term1 << 14) + term2);
2492}
2493
2494/****************************************************************************
2495**
2496** Name: CalcLO1Mult
2497**
2498** Description: Calculates Integer divider value and the numerator
2499** value for a FracN PLL.
2500**
2501** This function assumes that the f_LO and f_Ref are
2502** evenly divisible by f_LO_Step.
2503**
2504** Parameters: Div - OUTPUT: Whole number portion of the multiplier
2505** FracN - OUTPUT: Fractional portion of the multiplier
2506** f_LO - desired LO frequency.
2507** f_LO_Step - Minimum step size for the LO (in Hz).
2508** f_Ref - SRO frequency.
2509** f_Avoid - Range of PLL frequencies to avoid near
2510** integer multiples of f_Ref (in Hz).
2511**
2512** Returns: Recalculated LO frequency.
2513**
2514** Revision History:
2515**
2516** SCR Date Author Description
2517** -------------------------------------------------------------------------
2518** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2519**
2520****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002521static u32 MT2063_CalcLO1Mult(u32 * Div,
2522 u32 * FracN,
2523 u32 f_LO,
2524 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002525{
2526 /* Calculate the whole number portion of the divider */
2527 *Div = f_LO / f_Ref;
2528
2529 /* Calculate the numerator value (round to nearest f_LO_Step) */
2530 *FracN =
2531 (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
2532 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
2533
2534 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64);
2535}
2536
2537/****************************************************************************
2538**
2539** Name: CalcLO2Mult
2540**
2541** Description: Calculates Integer divider value and the numerator
2542** value for a FracN PLL.
2543**
2544** This function assumes that the f_LO and f_Ref are
2545** evenly divisible by f_LO_Step.
2546**
2547** Parameters: Div - OUTPUT: Whole number portion of the multiplier
2548** FracN - OUTPUT: Fractional portion of the multiplier
2549** f_LO - desired LO frequency.
2550** f_LO_Step - Minimum step size for the LO (in Hz).
2551** f_Ref - SRO frequency.
2552** f_Avoid - Range of PLL frequencies to avoid near
2553** integer multiples of f_Ref (in Hz).
2554**
2555** Returns: Recalculated LO frequency.
2556**
2557** Revision History:
2558**
2559** SCR Date Author Description
2560** -------------------------------------------------------------------------
2561** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2562**
2563****************************************************************************/
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002564static u32 MT2063_CalcLO2Mult(u32 * Div,
2565 u32 * FracN,
2566 u32 f_LO,
2567 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002568{
2569 /* Calculate the whole number portion of the divider */
2570 *Div = f_LO / f_Ref;
2571
2572 /* Calculate the numerator value (round to nearest f_LO_Step) */
2573 *FracN =
2574 (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
2575 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
2576
2577 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN,
2578 8191);
2579}
2580
2581/****************************************************************************
2582**
2583** Name: FindClearTuneFilter
2584**
2585** Description: Calculate the corrrect ClearTune filter to be used for
2586** a given input frequency.
2587**
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002588** Parameters: state - ptr to tuner data structure
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002589** f_in - RF input center frequency (in Hz).
2590**
2591** Returns: ClearTune filter number (0-31)
2592**
2593** Dependencies: MUST CALL MT2064_Open BEFORE FindClearTuneFilter!
2594**
2595** Revision History:
2596**
2597** SCR Date Author Description
2598** -------------------------------------------------------------------------
2599** 04-10-2008 PINZ Ver 1.14: Use software-controlled ClearTune
2600** cross-over frequency values.
2601**
2602****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002603static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002604{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002605 u32 RFBand;
2606 u32 idx; /* index loop */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002607
2608 /*
2609 ** Find RF Band setting
2610 */
2611 RFBand = 31; /* def when f_in > all */
2612 for (idx = 0; idx < 31; ++idx) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002613 if (state->CTFiltMax[idx] >= f_in) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002614 RFBand = idx;
2615 break;
2616 }
2617 }
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03002618 return RFBand;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002619}
2620
2621/****************************************************************************
2622**
2623** Name: MT2063_Tune
2624**
2625** Description: Change the tuner's tuned frequency to RFin.
2626**
2627** Parameters: h - Open handle to the tuner (from MT2063_Open).
2628** f_in - RF input center frequency (in Hz).
2629**
2630** Returns: status:
2631** MT_OK - No errors
2632** MT_INV_HANDLE - Invalid tuner handle
2633** MT_UPC_UNLOCK - Upconverter PLL unlocked
2634** MT_DNC_UNLOCK - Downconverter PLL unlocked
2635** MT_COMM_ERR - Serial bus communications error
2636** MT_SPUR_CNT_MASK - Count of avoided LO spurs
2637** MT_SPUR_PRESENT - LO spur possible in output
2638** MT_FIN_RANGE - Input freq out of range
2639** MT_FOUT_RANGE - Output freq out of range
2640** MT_UPC_RANGE - Upconverter freq out of range
2641** MT_DNC_RANGE - Downconverter freq out of range
2642**
2643** Dependencies: MUST CALL MT2063_Open BEFORE MT2063_Tune!
2644**
2645** MT_ReadSub - Read data from the two-wire serial bus
2646** MT_WriteSub - Write data to the two-wire serial bus
2647** MT_Sleep - Delay execution for x milliseconds
2648** MT2063_GetLocked - Checks to see if LO1 and LO2 are locked
2649**
2650** Revision History:
2651**
2652** SCR Date Author Description
2653** -------------------------------------------------------------------------
2654** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b.
2655** 04-10-2008 PINZ Ver 1.05: Use software-controlled ClearTune
2656** cross-over frequency values.
2657** 175 I 16-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs.
2658** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid.
2659** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW
2660**
2661****************************************************************************/
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002662static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002663{ /* RF input center frequency */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002664
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002665 u32 status = 0; /* status of operation */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002666 u32 LO1; /* 1st LO register value */
2667 u32 Num1; /* Numerator for LO1 reg. value */
2668 u32 f_IF1; /* 1st IF requested */
2669 u32 LO2; /* 2nd LO register value */
2670 u32 Num2; /* Numerator for LO2 reg. value */
2671 u32 ofLO1, ofLO2; /* last time's LO frequencies */
2672 u32 ofin, ofout; /* last time's I/O frequencies */
2673 u8 fiffc = 0x80; /* FIFF center freq from tuner */
2674 u32 fiffof; /* Offset from FIFF center freq */
2675 const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */
2676 u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */
2677 u8 val;
2678 u32 RFBand;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002679
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002680 /* Check the input and output frequency ranges */
2681 if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ))
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002682 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002683
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002684 if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ)
2685 || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ))
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002686 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002687
2688 /*
2689 ** Save original LO1 and LO2 register values
2690 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002691 ofLO1 = state->AS_Data.f_LO1;
2692 ofLO2 = state->AS_Data.f_LO2;
2693 ofin = state->AS_Data.f_in;
2694 ofout = state->AS_Data.f_out;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002695
2696 /*
2697 ** Find and set RF Band setting
2698 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002699 if (state->ctfilt_sw == 1) {
2700 val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08);
2701 if (state->reg[MT2063_REG_CTUNE_CTRL] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002702 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002703 MT2063_SetReg(state, MT2063_REG_CTUNE_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002704 }
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002705 val = state->reg[MT2063_REG_CTUNE_OV];
2706 RFBand = FindClearTuneFilter(state, f_in);
2707 state->reg[MT2063_REG_CTUNE_OV] =
2708 (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002709 | RFBand);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002710 if (state->reg[MT2063_REG_CTUNE_OV] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002711 status |=
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002712 MT2063_SetReg(state, MT2063_REG_CTUNE_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002713 }
2714 }
2715
2716 /*
2717 ** Read the FIFF Center Frequency from the tuner
2718 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002719 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002720 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03002721 mt2063_read(state,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002722 MT2063_REG_FIFFC,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002723 &state->reg[MT2063_REG_FIFFC], 1);
2724 fiffc = state->reg[MT2063_REG_FIFFC];
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002725 }
2726 /*
2727 ** Assign in the requested values
2728 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002729 state->AS_Data.f_in = f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002730 /* Request a 1st IF such that LO1 is on a step size */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002731 state->AS_Data.f_if1_Request =
2732 MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in,
2733 state->AS_Data.f_LO1_Step,
2734 state->AS_Data.f_ref) - f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002735
2736 /*
2737 ** Calculate frequency settings. f_IF1_FREQ + f_in is the
2738 ** desired LO1 frequency
2739 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002740 MT2063_ResetExclZones(&state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002741
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002742 f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002743
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002744 state->AS_Data.f_LO1 =
2745 MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step,
2746 state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002747
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002748 state->AS_Data.f_LO2 =
2749 MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
2750 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002751
2752 /*
2753 ** Check for any LO spurs in the output bandwidth and adjust
2754 ** the LO settings to avoid them if needed
2755 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002756 status |= MT2063_AvoidSpurs(state, &state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002757 /*
2758 ** MT_AvoidSpurs spurs may have changed the LO1 & LO2 values.
2759 ** Recalculate the LO frequencies and the values to be placed
2760 ** in the tuning registers.
2761 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002762 state->AS_Data.f_LO1 =
2763 MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1,
2764 state->AS_Data.f_LO1_Step, state->AS_Data.f_ref);
2765 state->AS_Data.f_LO2 =
2766 MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
2767 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
2768 state->AS_Data.f_LO2 =
2769 MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2,
2770 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002771
2772 /*
2773 ** Check the upconverter and downconverter frequency ranges
2774 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002775 if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ)
2776 || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002777 status |= MT2063_UPC_RANGE;
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002778 if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ)
2779 || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002780 status |= MT2063_DNC_RANGE;
2781 /* LO2 Lock bit was in a different place for B0 version */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002782 if (state->tuner_id == MT2063_B0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002783 LO2LK = 0x40;
2784
2785 /*
2786 ** If we have the same LO frequencies and we're already locked,
2787 ** then skip re-programming the LO registers.
2788 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002789 if ((ofLO1 != state->AS_Data.f_LO1)
2790 || (ofLO2 != state->AS_Data.f_LO2)
2791 || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) !=
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002792 (LO1LK | LO2LK))) {
2793 /*
2794 ** Calculate the FIFFOF register value
2795 **
2796 ** IF1_Actual
2797 ** FIFFOF = ------------ - 8 * FIFFC - 4992
2798 ** f_ref/64
2799 */
2800 fiffof =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002801 (state->AS_Data.f_LO1 -
2802 f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc -
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002803 4992;
2804 if (fiffof > 0xFF)
2805 fiffof = 0xFF;
2806
2807 /*
2808 ** Place all of the calculated values into the local tuner
2809 ** register fields.
2810 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002811 if (status >= 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002812 state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */
2813 state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */
2814 state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002815 |(Num2 >> 12)); /* NUM2q (hi) */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002816 state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */
2817 state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002818
2819 /*
2820 ** Now write out the computed register values
2821 ** IMPORTANT: There is a required order for writing
2822 ** (0x05 must follow all the others).
2823 */
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03002824 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 -03002825 if (state->tuner_id == MT2063_B0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002826 /* Re-write the one-shot bits to trigger the tune operation */
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03002827 status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002828 }
2829 /* Write out the FIFF offset only if it's changing */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002830 if (state->reg[MT2063_REG_FIFF_OFFSET] !=
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002831 (u8) fiffof) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002832 state->reg[MT2063_REG_FIFF_OFFSET] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002833 (u8) fiffof;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002834 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03002835 mt2063_write(state,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002836 MT2063_REG_FIFF_OFFSET,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03002837 &state->
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002838 reg[MT2063_REG_FIFF_OFFSET],
2839 1);
2840 }
2841 }
2842
2843 /*
2844 ** Check for LO's locking
2845 */
2846
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03002847 if (status < 0)
2848 return status;
2849
2850 status = mt2063_lockStatus(state);
2851 if (status < 0)
2852 return status;
2853 if (!status)
2854 return -EINVAL; /* Couldn't lock */
2855
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002856 /*
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03002857 * If we locked OK, assign calculated data to mt2063_state structure
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002858 */
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03002859 state->f_IF1_actual = state->AS_Data.f_LO1 - f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002860 }
2861
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03002862 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002863}
2864
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002865static u32 MT_Tune_atv(void *h, u32 f_in, u32 bw_in,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002866 enum MTTune_atv_standard tv_type)
2867{
2868
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03002869 u32 status = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002870
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002871 s32 pict_car = 0;
2872 s32 pict2chanb_vsb = 0;
2873 s32 pict2chanb_snd = 0;
2874 s32 pict2snd1 = 0;
2875 s32 pict2snd2 = 0;
2876 s32 ch_bw = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002877
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002878 s32 if_mid = 0;
2879 s32 rcvr_mode = 0;
2880 u32 mode_get = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002881
2882 switch (tv_type) {
2883 case MTTUNEA_PAL_B:{
2884 pict_car = 38900000;
2885 ch_bw = 8000000;
2886 pict2chanb_vsb = -1250000;
2887 pict2snd1 = 5500000;
2888 pict2snd2 = 5742000;
2889 rcvr_mode = 1;
2890 break;
2891 }
2892 case MTTUNEA_PAL_G:{
2893 pict_car = 38900000;
2894 ch_bw = 7000000;
2895 pict2chanb_vsb = -1250000;
2896 pict2snd1 = 5500000;
2897 pict2snd2 = 0;
2898 rcvr_mode = 1;
2899 break;
2900 }
2901 case MTTUNEA_PAL_I:{
2902 pict_car = 38900000;
2903 ch_bw = 8000000;
2904 pict2chanb_vsb = -1250000;
2905 pict2snd1 = 6000000;
2906 pict2snd2 = 0;
2907 rcvr_mode = 1;
2908 break;
2909 }
2910 case MTTUNEA_PAL_L:{
2911 pict_car = 38900000;
2912 ch_bw = 8000000;
2913 pict2chanb_vsb = -1250000;
2914 pict2snd1 = 6500000;
2915 pict2snd2 = 0;
2916 rcvr_mode = 1;
2917 break;
2918 }
2919 case MTTUNEA_PAL_MN:{
2920 pict_car = 38900000;
2921 ch_bw = 6000000;
2922 pict2chanb_vsb = -1250000;
2923 pict2snd1 = 4500000;
2924 pict2snd2 = 0;
2925 rcvr_mode = 1;
2926 break;
2927 }
2928 case MTTUNEA_PAL_DK:{
2929 pict_car = 38900000;
2930 ch_bw = 8000000;
2931 pict2chanb_vsb = -1250000;
2932 pict2snd1 = 6500000;
2933 pict2snd2 = 0;
2934 rcvr_mode = 1;
2935 break;
2936 }
2937 case MTTUNEA_DIGITAL:{
2938 pict_car = 36125000;
2939 ch_bw = 8000000;
2940 pict2chanb_vsb = -(ch_bw / 2);
2941 pict2snd1 = 0;
2942 pict2snd2 = 0;
2943 rcvr_mode = 2;
2944 break;
2945 }
2946 case MTTUNEA_FMRADIO:{
2947 pict_car = 38900000;
2948 ch_bw = 8000000;
2949 pict2chanb_vsb = -(ch_bw / 2);
2950 pict2snd1 = 0;
2951 pict2snd2 = 0;
2952 rcvr_mode = 4;
2953 //f_in -= 2900000;
2954 break;
2955 }
2956 case MTTUNEA_DVBC:{
2957 pict_car = 36125000;
2958 ch_bw = 8000000;
2959 pict2chanb_vsb = -(ch_bw / 2);
2960 pict2snd1 = 0;
2961 pict2snd2 = 0;
2962 rcvr_mode = MT2063_CABLE_QAM;
2963 break;
2964 }
2965 case MTTUNEA_DVBT:{
2966 pict_car = 36125000;
2967 ch_bw = bw_in; //8000000
2968 pict2chanb_vsb = -(ch_bw / 2);
2969 pict2snd1 = 0;
2970 pict2snd2 = 0;
2971 rcvr_mode = MT2063_OFFAIR_COFDM;
2972 break;
2973 }
2974 case MTTUNEA_UNKNOWN:
2975 break;
2976 default:
2977 break;
2978 }
2979
2980 pict2chanb_snd = pict2chanb_vsb - ch_bw;
2981 if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
2982
2983 status |= MT2063_SetParam(h, MT2063_STEPSIZE, 125000);
2984 status |= MT2063_SetParam(h, MT2063_OUTPUT_FREQ, if_mid);
2985 status |= MT2063_SetParam(h, MT2063_OUTPUT_BW, ch_bw);
2986 status |= MT2063_GetParam(h, MT2063_RCVR_MODE, &mode_get);
2987
2988 status |= MT2063_SetParam(h, MT2063_RCVR_MODE, rcvr_mode);
2989 status |= MT2063_Tune(h, (f_in + (pict2chanb_vsb + (ch_bw / 2))));
2990 status |= MT2063_GetParam(h, MT2063_RCVR_MODE, &mode_get);
2991
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03002992 return (u32) status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002993}
2994
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03002995static const u8 MT2063B0_defaults[] = {
2996 /* Reg, Value */
2997 0x19, 0x05,
2998 0x1B, 0x1D,
2999 0x1C, 0x1F,
3000 0x1D, 0x0F,
3001 0x1E, 0x3F,
3002 0x1F, 0x0F,
3003 0x20, 0x3F,
3004 0x22, 0x21,
3005 0x23, 0x3F,
3006 0x24, 0x20,
3007 0x25, 0x3F,
3008 0x27, 0xEE,
3009 0x2C, 0x27, /* bit at 0x20 is cleared below */
3010 0x30, 0x03,
3011 0x2C, 0x07, /* bit at 0x20 is cleared here */
3012 0x2D, 0x87,
3013 0x2E, 0xAA,
3014 0x28, 0xE1, /* Set the FIFCrst bit here */
3015 0x28, 0xE0, /* Clear the FIFCrst bit here */
3016 0x00
3017};
3018
3019/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
3020static const u8 MT2063B1_defaults[] = {
3021 /* Reg, Value */
3022 0x05, 0xF0,
3023 0x11, 0x10, /* New Enable AFCsd */
3024 0x19, 0x05,
3025 0x1A, 0x6C,
3026 0x1B, 0x24,
3027 0x1C, 0x28,
3028 0x1D, 0x8F,
3029 0x1E, 0x14,
3030 0x1F, 0x8F,
3031 0x20, 0x57,
3032 0x22, 0x21, /* New - ver 1.03 */
3033 0x23, 0x3C, /* New - ver 1.10 */
3034 0x24, 0x20, /* New - ver 1.03 */
3035 0x2C, 0x24, /* bit at 0x20 is cleared below */
3036 0x2D, 0x87, /* FIFFQ=0 */
3037 0x2F, 0xF3,
3038 0x30, 0x0C, /* New - ver 1.11 */
3039 0x31, 0x1B, /* New - ver 1.11 */
3040 0x2C, 0x04, /* bit at 0x20 is cleared here */
3041 0x28, 0xE1, /* Set the FIFCrst bit here */
3042 0x28, 0xE0, /* Clear the FIFCrst bit here */
3043 0x00
3044};
3045
3046/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
3047static const u8 MT2063B3_defaults[] = {
3048 /* Reg, Value */
3049 0x05, 0xF0,
3050 0x19, 0x3D,
3051 0x2C, 0x24, /* bit at 0x20 is cleared below */
3052 0x2C, 0x04, /* bit at 0x20 is cleared here */
3053 0x28, 0xE1, /* Set the FIFCrst bit here */
3054 0x28, 0xE0, /* Clear the FIFCrst bit here */
3055 0x00
3056};
3057
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003058static int mt2063_init(struct dvb_frontend *fe)
3059{
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03003060 u32 status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003061 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03003062 u8 all_resets = 0xF0; /* reset/load bits */
3063 const u8 *def = NULL;
3064 u32 FCRUN;
3065 s32 maxReads;
3066 u32 fcu_osc;
3067 u32 i;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003068
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03003069 state->rcvr_mode = MT2063_CABLE_QAM;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003070
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03003071 /* Read the Part/Rev code from the tuner */
3072 status = mt2063_read(state, MT2063_REG_PART_REV, state->reg, 1);
3073 if (status < 0)
3074 return status;
3075
3076 /* Check the part/rev code */
3077 if (((state->reg[MT2063_REG_PART_REV] != MT2063_B0) /* MT2063 B0 */
3078 &&(state->reg[MT2063_REG_PART_REV] != MT2063_B1) /* MT2063 B1 */
3079 &&(state->reg[MT2063_REG_PART_REV] != MT2063_B3))) /* MT2063 B3 */
3080 return -ENODEV; /* Wrong tuner Part/Rev code */
3081
3082 /* Check the 2nd byte of the Part/Rev code from the tuner */
3083 status = mt2063_read(state, MT2063_REG_RSVD_3B,
3084 &state->reg[MT2063_REG_RSVD_3B], 1);
3085
3086 /* b7 != 0 ==> NOT MT2063 */
3087 if (status < 0 ||((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00))
3088 return -ENODEV; /* Wrong tuner Part/Rev code */
3089
3090 /* Reset the tuner */
3091 status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1);
3092 if (status < 0)
3093 return status;
3094
3095 /* change all of the default values that vary from the HW reset values */
3096 /* def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */
3097 switch (state->reg[MT2063_REG_PART_REV]) {
3098 case MT2063_B3:
3099 def = MT2063B3_defaults;
3100 break;
3101
3102 case MT2063_B1:
3103 def = MT2063B1_defaults;
3104 break;
3105
3106 case MT2063_B0:
3107 def = MT2063B0_defaults;
3108 break;
3109
3110 default:
3111 return -ENODEV;
3112 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003113 }
3114
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03003115 while (status >= 0 && *def) {
3116 u8 reg = *def++;
3117 u8 val = *def++;
3118 status = mt2063_write(state, reg, &val, 1);
3119 }
3120 if (status < 0)
3121 return status;
3122
3123 /* Wait for FIFF location to complete. */
3124 FCRUN = 1;
3125 maxReads = 10;
3126 while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) {
3127 msleep(2);
3128 status = mt2063_read(state,
3129 MT2063_REG_XO_STATUS,
3130 &state->
3131 reg[MT2063_REG_XO_STATUS], 1);
3132 FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6;
3133 }
3134
3135 if (FCRUN != 0 || status < 0)
3136 return -ENODEV;
3137
3138 status = mt2063_read(state,
3139 MT2063_REG_FIFFC,
3140 &state->reg[MT2063_REG_FIFFC], 1);
3141 if (status < 0)
3142 return status;
3143
3144 /* Read back all the registers from the tuner */
3145 status = mt2063_read(state,
3146 MT2063_REG_PART_REV,
3147 state->reg, MT2063_REG_END_REGS);
3148 if (status < 0)
3149 return status;
3150
3151 /* Initialize the tuner state. */
3152 state->tuner_id = state->reg[MT2063_REG_PART_REV];
3153 state->AS_Data.f_ref = MT2063_REF_FREQ;
3154 state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) *
3155 ((u32) state->reg[MT2063_REG_FIFFC] + 640);
3156 state->AS_Data.f_if1_bw = MT2063_IF1_BW;
3157 state->AS_Data.f_out = 43750000UL;
3158 state->AS_Data.f_out_bw = 6750000UL;
3159 state->AS_Data.f_zif_bw = MT2063_ZIF_BW;
3160 state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64;
3161 state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE;
3162 state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1;
3163 state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2;
3164 state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP;
3165 state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center;
3166 state->AS_Data.f_LO1 = 2181000000UL;
3167 state->AS_Data.f_LO2 = 1486249786UL;
3168 state->f_IF1_actual = state->AS_Data.f_if1_Center;
3169 state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual;
3170 state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID;
3171 state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID;
3172 state->num_regs = MT2063_REG_END_REGS;
3173 state->AS_Data.avoidDECT = MT2063_AVOID_BOTH;
3174 state->ctfilt_sw = 0;
3175
3176 state->CTFiltMax[0] = 69230000;
3177 state->CTFiltMax[1] = 105770000;
3178 state->CTFiltMax[2] = 140350000;
3179 state->CTFiltMax[3] = 177110000;
3180 state->CTFiltMax[4] = 212860000;
3181 state->CTFiltMax[5] = 241130000;
3182 state->CTFiltMax[6] = 274370000;
3183 state->CTFiltMax[7] = 309820000;
3184 state->CTFiltMax[8] = 342450000;
3185 state->CTFiltMax[9] = 378870000;
3186 state->CTFiltMax[10] = 416210000;
3187 state->CTFiltMax[11] = 456500000;
3188 state->CTFiltMax[12] = 495790000;
3189 state->CTFiltMax[13] = 534530000;
3190 state->CTFiltMax[14] = 572610000;
3191 state->CTFiltMax[15] = 598970000;
3192 state->CTFiltMax[16] = 635910000;
3193 state->CTFiltMax[17] = 672130000;
3194 state->CTFiltMax[18] = 714840000;
3195 state->CTFiltMax[19] = 739660000;
3196 state->CTFiltMax[20] = 770410000;
3197 state->CTFiltMax[21] = 814660000;
3198 state->CTFiltMax[22] = 846950000;
3199 state->CTFiltMax[23] = 867820000;
3200 state->CTFiltMax[24] = 915980000;
3201 state->CTFiltMax[25] = 947450000;
3202 state->CTFiltMax[26] = 983110000;
3203 state->CTFiltMax[27] = 1021630000;
3204 state->CTFiltMax[28] = 1061870000;
3205 state->CTFiltMax[29] = 1098330000;
3206 state->CTFiltMax[30] = 1138990000;
3207
3208 /*
3209 ** Fetch the FCU osc value and use it and the fRef value to
3210 ** scale all of the Band Max values
3211 */
3212
3213 state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A;
3214 status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
3215 &state->reg[MT2063_REG_CTUNE_CTRL], 1);
3216 if (status < 0)
3217 return status;
3218
3219 /* Read the ClearTune filter calibration value */
3220 status = mt2063_read(state, MT2063_REG_FIFFC,
3221 &state->reg[MT2063_REG_FIFFC], 1);
3222 if (status < 0)
3223 return status;
3224
3225 fcu_osc = state->reg[MT2063_REG_FIFFC];
3226
3227 state->reg[MT2063_REG_CTUNE_CTRL] = 0x00;
3228 status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
3229 &state->reg[MT2063_REG_CTUNE_CTRL], 1);
3230 if (status < 0)
3231 return status;
3232
3233 /* Adjust each of the values in the ClearTune filter cross-over table */
3234 for (i = 0; i < 31; i++)
3235 state->CTFiltMax[i] =(state->CTFiltMax[i] / 768) * (fcu_osc + 640);
3236
3237 status = MT2063_SoftwareShutdown(state, 1);
3238 if (status < 0)
3239 return status;
3240 status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
3241 if (status < 0)
3242 return status;
3243
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003244 return 0;
3245}
3246
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003247static int mt2063_get_status(struct dvb_frontend *fe, u32 * status)
3248{
3249 int rc = 0;
3250
3251 //get tuner lock status
3252
3253 return rc;
3254}
3255
3256static int mt2063_get_state(struct dvb_frontend *fe,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03003257 enum tuner_param param, struct tuner_state *tunstate)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003258{
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03003259 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003260
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003261 switch (param) {
3262 case DVBFE_TUNER_FREQUENCY:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003263 //get frequency
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003264 break;
3265 case DVBFE_TUNER_TUNERSTEP:
3266 break;
3267 case DVBFE_TUNER_IFFREQ:
3268 break;
3269 case DVBFE_TUNER_BANDWIDTH:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003270 //get bandwidth
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003271 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003272 case DVBFE_TUNER_REFCLOCK:
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03003273 tunstate->refclock = mt2063_lockStatus(state);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003274 break;
3275 default:
3276 break;
3277 }
3278
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03003279 return (int)tunstate->refclock;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003280}
3281
3282static int mt2063_set_state(struct dvb_frontend *fe,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03003283 enum tuner_param param, struct tuner_state *tunstate)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003284{
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03003285 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03003286 u32 status = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003287
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003288 switch (param) {
3289 case DVBFE_TUNER_FREQUENCY:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003290 //set frequency
3291
3292 status =
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03003293 MT_Tune_atv(state,
3294 tunstate->frequency, tunstate->bandwidth,
3295 state->tv_type);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003296
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03003297 state->frequency = tunstate->frequency;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003298 break;
3299 case DVBFE_TUNER_TUNERSTEP:
3300 break;
3301 case DVBFE_TUNER_IFFREQ:
3302 break;
3303 case DVBFE_TUNER_BANDWIDTH:
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003304 //set bandwidth
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03003305 state->bandwidth = tunstate->bandwidth;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003306 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003307 case DVBFE_TUNER_REFCLOCK:
3308
3309 break;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003310 default:
3311 break;
3312 }
3313
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003314 return (int)status;
3315}
3316
3317static int mt2063_release(struct dvb_frontend *fe)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003318{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003319 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003320
3321 fe->tuner_priv = NULL;
3322 kfree(state);
3323
3324 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003325}
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003326
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003327static struct dvb_tuner_ops mt2063_ops = {
3328 .info = {
3329 .name = "MT2063 Silicon Tuner",
3330 .frequency_min = 45000000,
3331 .frequency_max = 850000000,
3332 .frequency_step = 0,
3333 },
3334
3335 .init = mt2063_init,
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03003336 .sleep = MT2063_Sleep,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003337 .get_status = mt2063_get_status,
3338 .get_state = mt2063_get_state,
3339 .set_state = mt2063_set_state,
3340 .release = mt2063_release
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003341};
3342
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003343struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
3344 struct mt2063_config *config,
3345 struct i2c_adapter *i2c)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003346{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003347 struct mt2063_state *state = NULL;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003348
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003349 state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003350 if (state == NULL)
3351 goto error;
3352
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003353 state->config = config;
3354 state->i2c = i2c;
3355 state->frontend = fe;
3356 state->reference = config->refclock / 1000; /* kHz */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003357 fe->tuner_priv = state;
3358 fe->ops.tuner_ops = mt2063_ops;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003359
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003360 printk("%s: Attaching MT2063 \n", __func__);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003361 return fe;
3362
3363error:
3364 kfree(state);
3365 return NULL;
3366}
3367
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003368EXPORT_SYMBOL(mt2063_attach);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03003369MODULE_PARM_DESC(verbose, "Set Verbosity level");
3370
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03003371MODULE_AUTHOR("Henry");
3372MODULE_DESCRIPTION("MT2063 Silicon tuner");
3373MODULE_LICENSE("GPL");