Commit | Line | Data |
---|---|---|
223c7b05 MCC |
1 | #include <linux/init.h> |
2 | #include <linux/kernel.h> | |
3 | #include <linux/module.h> | |
4 | #include <linux/string.h> | |
0e301442 | 5 | |
0e301442 MCC |
6 | #include "mt2063.h" |
7 | ||
223c7b05 | 8 | static unsigned int verbose; |
0e301442 MCC |
9 | module_param(verbose, int, 0644); |
10 | ||
31e67fae | 11 | /* positive error codes used internally */ |
29a0a4fe | 12 | |
fdf77a4f | 13 | /* Info: Unavoidable LO-related spur may be present in the output */ |
29a0a4fe | 14 | #define MT2063_SPUR_PRESENT_ERR (0x00800000) |
6d3d748a MCC |
15 | |
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 | ||
6d3d748a MCC |
20 | /* 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 | ||
6d3d748a MCC |
26 | /* |
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 | */ | |
6d3d748a MCC |
34 | |
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 | ||
44 | enum 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 | ||
6d3d748a MCC |
53 | struct 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 | */ | |
62 | struct MT2063_AvoidSpursData_t { | |
6d3d748a MCC |
63 | 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 | ||
6d3d748a MCC |
90 | /* |
91 | * Parameter for function MT2063_SetPowerMask that specifies the power down | |
92 | * of various sections of the MT2063. | |
93 | */ | |
94 | enum 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 | ||
6d3d748a MCC |
112 | /* |
113 | * Parameter for selecting tuner mode | |
114 | */ | |
115 | enum MT2063_RCVR_MODES { | |
116 | MT2063_CABLE_QAM = 0, /* Digital cable */ | |
117 | MT2063_CABLE_ANALOG, /* Analog cable */ | |
118 | MT2063_OFFAIR_COFDM, /* Digital offair */ | |
119 | MT2063_OFFAIR_COFDM_SAWLESS, /* Digital offair without SAW */ | |
120 | MT2063_OFFAIR_ANALOG, /* Analog offair */ | |
121 | MT2063_OFFAIR_8VSB, /* Analog offair */ | |
122 | MT2063_NUM_RCVR_MODES | |
123 | }; | |
124 | ||
125 | /* | |
126 | * Possible values for MT2063_DNC_OUTPUT | |
127 | */ | |
128 | enum MT2063_DNC_Output_Enable { | |
129 | MT2063_DNC_NONE = 0, | |
130 | MT2063_DNC_1, | |
131 | MT2063_DNC_2, | |
132 | MT2063_DNC_BOTH | |
133 | }; | |
134 | ||
135 | /* | |
136 | ** Two-wire serial bus subaddresses of the tuner registers. | |
137 | ** Also known as the tuner's register addresses. | |
138 | */ | |
139 | enum MT2063_Register_Offsets { | |
140 | MT2063_REG_PART_REV = 0, /* 0x00: Part/Rev Code */ | |
141 | MT2063_REG_LO1CQ_1, /* 0x01: LO1C Queued Byte 1 */ | |
142 | MT2063_REG_LO1CQ_2, /* 0x02: LO1C Queued Byte 2 */ | |
143 | MT2063_REG_LO2CQ_1, /* 0x03: LO2C Queued Byte 1 */ | |
144 | MT2063_REG_LO2CQ_2, /* 0x04: LO2C Queued Byte 2 */ | |
145 | MT2063_REG_LO2CQ_3, /* 0x05: LO2C Queued Byte 3 */ | |
146 | MT2063_REG_RSVD_06, /* 0x06: Reserved */ | |
147 | MT2063_REG_LO_STATUS, /* 0x07: LO Status */ | |
148 | MT2063_REG_FIFFC, /* 0x08: FIFF Center */ | |
149 | MT2063_REG_CLEARTUNE, /* 0x09: ClearTune Filter */ | |
150 | MT2063_REG_ADC_OUT, /* 0x0A: ADC_OUT */ | |
151 | MT2063_REG_LO1C_1, /* 0x0B: LO1C Byte 1 */ | |
152 | MT2063_REG_LO1C_2, /* 0x0C: LO1C Byte 2 */ | |
153 | MT2063_REG_LO2C_1, /* 0x0D: LO2C Byte 1 */ | |
154 | MT2063_REG_LO2C_2, /* 0x0E: LO2C Byte 2 */ | |
155 | MT2063_REG_LO2C_3, /* 0x0F: LO2C Byte 3 */ | |
156 | MT2063_REG_RSVD_10, /* 0x10: Reserved */ | |
157 | MT2063_REG_PWR_1, /* 0x11: PWR Byte 1 */ | |
158 | MT2063_REG_PWR_2, /* 0x12: PWR Byte 2 */ | |
159 | MT2063_REG_TEMP_STATUS, /* 0x13: Temp Status */ | |
160 | MT2063_REG_XO_STATUS, /* 0x14: Crystal Status */ | |
161 | MT2063_REG_RF_STATUS, /* 0x15: RF Attn Status */ | |
162 | MT2063_REG_FIF_STATUS, /* 0x16: FIF Attn Status */ | |
163 | MT2063_REG_LNA_OV, /* 0x17: LNA Attn Override */ | |
164 | MT2063_REG_RF_OV, /* 0x18: RF Attn Override */ | |
165 | MT2063_REG_FIF_OV, /* 0x19: FIF Attn Override */ | |
166 | MT2063_REG_LNA_TGT, /* 0x1A: Reserved */ | |
167 | MT2063_REG_PD1_TGT, /* 0x1B: Pwr Det 1 Target */ | |
168 | MT2063_REG_PD2_TGT, /* 0x1C: Pwr Det 2 Target */ | |
169 | MT2063_REG_RSVD_1D, /* 0x1D: Reserved */ | |
170 | MT2063_REG_RSVD_1E, /* 0x1E: Reserved */ | |
171 | MT2063_REG_RSVD_1F, /* 0x1F: Reserved */ | |
172 | MT2063_REG_RSVD_20, /* 0x20: Reserved */ | |
173 | MT2063_REG_BYP_CTRL, /* 0x21: Bypass Control */ | |
174 | MT2063_REG_RSVD_22, /* 0x22: Reserved */ | |
175 | MT2063_REG_RSVD_23, /* 0x23: Reserved */ | |
176 | MT2063_REG_RSVD_24, /* 0x24: Reserved */ | |
177 | MT2063_REG_RSVD_25, /* 0x25: Reserved */ | |
178 | MT2063_REG_RSVD_26, /* 0x26: Reserved */ | |
179 | MT2063_REG_RSVD_27, /* 0x27: Reserved */ | |
180 | MT2063_REG_FIFF_CTRL, /* 0x28: FIFF Control */ | |
181 | MT2063_REG_FIFF_OFFSET, /* 0x29: FIFF Offset */ | |
182 | MT2063_REG_CTUNE_CTRL, /* 0x2A: Reserved */ | |
183 | MT2063_REG_CTUNE_OV, /* 0x2B: Reserved */ | |
184 | MT2063_REG_CTRL_2C, /* 0x2C: Reserved */ | |
185 | MT2063_REG_FIFF_CTRL2, /* 0x2D: Fiff Control */ | |
186 | MT2063_REG_RSVD_2E, /* 0x2E: Reserved */ | |
187 | MT2063_REG_DNC_GAIN, /* 0x2F: DNC Control */ | |
188 | MT2063_REG_VGA_GAIN, /* 0x30: VGA Gain Ctrl */ | |
189 | MT2063_REG_RSVD_31, /* 0x31: Reserved */ | |
190 | MT2063_REG_TEMP_SEL, /* 0x32: Temperature Selection */ | |
191 | MT2063_REG_RSVD_33, /* 0x33: Reserved */ | |
192 | MT2063_REG_RSVD_34, /* 0x34: Reserved */ | |
193 | MT2063_REG_RSVD_35, /* 0x35: Reserved */ | |
194 | MT2063_REG_RSVD_36, /* 0x36: Reserved */ | |
195 | MT2063_REG_RSVD_37, /* 0x37: Reserved */ | |
196 | MT2063_REG_RSVD_38, /* 0x38: Reserved */ | |
197 | MT2063_REG_RSVD_39, /* 0x39: Reserved */ | |
198 | MT2063_REG_RSVD_3A, /* 0x3A: Reserved */ | |
199 | MT2063_REG_RSVD_3B, /* 0x3B: Reserved */ | |
200 | MT2063_REG_RSVD_3C, /* 0x3C: Reserved */ | |
201 | MT2063_REG_END_REGS | |
202 | }; | |
203 | ||
6d3d748a MCC |
204 | enum MTTune_atv_standard { |
205 | MTTUNEA_UNKNOWN = 0, | |
206 | MTTUNEA_PAL_B, | |
207 | MTTUNEA_PAL_G, | |
208 | MTTUNEA_PAL_I, | |
209 | MTTUNEA_PAL_L, | |
210 | MTTUNEA_PAL_MN, | |
211 | MTTUNEA_PAL_DK, | |
212 | MTTUNEA_DIGITAL, | |
213 | MTTUNEA_FMRADIO, | |
214 | MTTUNEA_DVBC, | |
215 | MTTUNEA_DVBT | |
216 | }; | |
217 | ||
218 | ||
219 | struct mt2063_state { | |
220 | struct i2c_adapter *i2c; | |
221 | ||
222 | const struct mt2063_config *config; | |
223 | struct dvb_tuner_ops ops; | |
224 | struct dvb_frontend *frontend; | |
225 | struct tuner_state status; | |
6d3d748a MCC |
226 | |
227 | enum MTTune_atv_standard tv_type; | |
228 | u32 frequency; | |
229 | u32 srate; | |
230 | u32 bandwidth; | |
231 | u32 reference; | |
51f0f7b3 MCC |
232 | |
233 | u32 tuner_id; | |
234 | struct MT2063_AvoidSpursData_t AS_Data; | |
235 | u32 f_IF1_actual; | |
236 | u32 rcvr_mode; | |
237 | u32 ctfilt_sw; | |
238 | u32 CTFiltMax[31]; | |
239 | u32 num_regs; | |
240 | u8 reg[MT2063_REG_END_REGS]; | |
6d3d748a | 241 | }; |
0ff48432 | 242 | |
bf97555e MCC |
243 | /* Prototypes */ |
244 | static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info, | |
245 | u32 f_min, u32 f_max); | |
dcd52d20 | 246 | static u32 MT2063_SetReg(struct mt2063_state *state, u8 reg, u8 val); |
8c64f932 MCC |
247 | static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown); |
248 | static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, enum MT2063_Mask_Bits Bits); | |
249 | ||
bf97555e | 250 | |
3d49700f MCC |
251 | /* |
252 | * Ancillary routines visible outside mt2063 | |
253 | */ | |
f867695a | 254 | unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) |
0ff48432 | 255 | { |
8c64f932 | 256 | struct mt2063_state *state = fe->tuner_priv; |
0ff48432 MCC |
257 | int err = 0; |
258 | ||
3d49700f MCC |
259 | err = MT2063_SoftwareShutdown(state, 1); |
260 | if (err < 0) | |
261 | printk(KERN_ERR "%s: Couldn't shutdown\n", __func__); | |
0ff48432 MCC |
262 | |
263 | return err; | |
264 | } | |
3d49700f | 265 | EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown); |
0ff48432 | 266 | |
f867695a | 267 | unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) |
0ff48432 | 268 | { |
8c64f932 | 269 | struct mt2063_state *state = fe->tuner_priv; |
0ff48432 MCC |
270 | int err = 0; |
271 | ||
3d49700f MCC |
272 | err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); |
273 | if (err < 0) | |
274 | printk(KERN_ERR "%s: Invalid parameter\n", __func__); | |
0ff48432 MCC |
275 | |
276 | return err; | |
277 | } | |
3d49700f | 278 | EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits); |
0ff48432 | 279 | |
e1de3d18 MCC |
280 | /* |
281 | * mt2063_write - Write data into the I2C bus | |
282 | */ | |
283 | static u32 mt2063_write(struct mt2063_state *state, | |
284 | u8 reg, u8 *data, u32 len) | |
0e301442 | 285 | { |
e1de3d18 | 286 | struct dvb_frontend *fe = state->frontend; |
0e301442 | 287 | int ret; |
e1de3d18 | 288 | u8 buf[60]; |
0e301442 MCC |
289 | struct i2c_msg msg = { |
290 | .addr = state->config->tuner_address, | |
291 | .flags = 0, | |
292 | .buf = buf, | |
293 | .len = len + 1 | |
294 | }; | |
295 | ||
e1de3d18 | 296 | msg.buf[0] = reg; |
0e301442 MCC |
297 | memcpy(msg.buf + 1, data, len); |
298 | ||
e1de3d18 | 299 | fe->ops.i2c_gate_ctrl(fe, 1); |
0e301442 | 300 | ret = i2c_transfer(state->i2c, &msg, 1); |
e1de3d18 | 301 | fe->ops.i2c_gate_ctrl(fe, 0); |
0e301442 MCC |
302 | |
303 | if (ret < 0) | |
304 | printk("mt2063_writeregs error ret=%d\n", ret); | |
305 | ||
306 | return ret; | |
307 | } | |
308 | ||
e1de3d18 MCC |
309 | /* |
310 | * mt2063_read - Read data from the I2C bus | |
311 | */ | |
312 | static u32 mt2063_read(struct mt2063_state *state, | |
51f0f7b3 | 313 | u8 subAddress, u8 *pData, u32 cnt) |
0e301442 | 314 | { |
51f0f7b3 MCC |
315 | u32 status = 0; /* Status to be returned */ |
316 | struct dvb_frontend *fe = state->frontend; | |
317 | u32 i = 0; | |
318 | ||
e1de3d18 | 319 | fe->ops.i2c_gate_ctrl(fe, 1); |
0e301442 MCC |
320 | |
321 | for (i = 0; i < cnt; i++) { | |
e1de3d18 MCC |
322 | int ret; |
323 | u8 b0[] = { subAddress + i }; | |
324 | struct i2c_msg msg[] = { | |
325 | { | |
326 | .addr = state->config->tuner_address, | |
327 | .flags = I2C_M_RD, | |
328 | .buf = b0, | |
329 | .len = 1 | |
330 | }, { | |
331 | .addr = state->config->tuner_address, | |
332 | .flags = I2C_M_RD, | |
333 | .buf = pData + 1, | |
334 | .len = 1 | |
335 | } | |
336 | }; | |
337 | ||
338 | ret = i2c_transfer(state->i2c, msg, 2); | |
339 | if (ret < 0) | |
0e301442 | 340 | break; |
0e301442 | 341 | } |
e1de3d18 | 342 | fe->ops.i2c_gate_ctrl(fe, 0); |
0e301442 MCC |
343 | return (status); |
344 | } | |
345 | ||
e930b3a0 MCC |
346 | /* |
347 | * FIXME: Is this really needed? | |
348 | */ | |
f867695a | 349 | static int MT2063_Sleep(struct dvb_frontend *fe) |
0e301442 MCC |
350 | { |
351 | /* | |
352 | ** ToDo: Add code here to implement a OS blocking | |
353 | ** for a period of "nMinDelayTime" milliseconds. | |
354 | */ | |
f867695a MCC |
355 | msleep(10); |
356 | ||
357 | return 0; | |
0e301442 MCC |
358 | } |
359 | ||
e930b3a0 MCC |
360 | /* |
361 | * Microtune spur avoidance | |
362 | */ | |
0e301442 MCC |
363 | |
364 | /* Implement ceiling, floor functions. */ | |
365 | #define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0)) | |
0e301442 | 366 | #define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d)) |
0e301442 MCC |
367 | |
368 | struct MT2063_FIFZone_t { | |
cfde8925 MCC |
369 | s32 min_; |
370 | s32 max_; | |
0e301442 MCC |
371 | }; |
372 | ||
0e301442 MCC |
373 | /* |
374 | ** Reset all exclusion zones. | |
375 | ** Add zones to protect the PLL FracN regions near zero | |
376 | ** | |
377 | ** N/A I 06-17-2008 RSK Ver 1.19: Refactoring avoidance of DECT | |
378 | ** frequencies into MT_ResetExclZones(). | |
379 | */ | |
bf97555e | 380 | static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info) |
0e301442 | 381 | { |
cfde8925 | 382 | u32 center; |
0e301442 MCC |
383 | |
384 | pAS_Info->nZones = 0; /* this clears the used list */ | |
385 | pAS_Info->usedZones = NULL; /* reset ptr */ | |
386 | pAS_Info->freeZones = NULL; /* reset ptr */ | |
387 | ||
388 | center = | |
389 | pAS_Info->f_ref * | |
390 | ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 + | |
391 | pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in; | |
392 | while (center < | |
393 | pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 + | |
394 | pAS_Info->f_LO1_FracN_Avoid) { | |
395 | /* Exclude LO1 FracN */ | |
396 | MT2063_AddExclZone(pAS_Info, | |
397 | center - pAS_Info->f_LO1_FracN_Avoid, | |
398 | center - 1); | |
399 | MT2063_AddExclZone(pAS_Info, center + 1, | |
400 | center + pAS_Info->f_LO1_FracN_Avoid); | |
401 | center += pAS_Info->f_ref; | |
402 | } | |
403 | ||
404 | center = | |
405 | pAS_Info->f_ref * | |
406 | ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 - | |
407 | pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out; | |
408 | while (center < | |
409 | pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 + | |
410 | pAS_Info->f_LO2_FracN_Avoid) { | |
411 | /* Exclude LO2 FracN */ | |
412 | MT2063_AddExclZone(pAS_Info, | |
413 | center - pAS_Info->f_LO2_FracN_Avoid, | |
414 | center - 1); | |
415 | MT2063_AddExclZone(pAS_Info, center + 1, | |
416 | center + pAS_Info->f_LO2_FracN_Avoid); | |
417 | center += pAS_Info->f_ref; | |
418 | } | |
419 | ||
420 | if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) { | |
421 | /* Exclude LO1 values that conflict with DECT channels */ | |
422 | MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */ | |
423 | MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */ | |
424 | MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */ | |
425 | MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */ | |
426 | MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */ | |
427 | } | |
428 | ||
429 | if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) { | |
430 | MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */ | |
431 | MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */ | |
432 | MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */ | |
433 | MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */ | |
434 | MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */ | |
435 | MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */ | |
436 | MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */ | |
437 | MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */ | |
438 | MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */ | |
439 | MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */ | |
440 | } | |
0e301442 MCC |
441 | } |
442 | ||
443 | static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t | |
444 | *pAS_Info, | |
445 | struct MT2063_ExclZone_t *pPrevNode) | |
446 | { | |
447 | struct MT2063_ExclZone_t *pNode; | |
448 | /* Check for a node in the free list */ | |
449 | if (pAS_Info->freeZones != NULL) { | |
450 | /* Use one from the free list */ | |
451 | pNode = pAS_Info->freeZones; | |
452 | pAS_Info->freeZones = pNode->next_; | |
453 | } else { | |
454 | /* Grab a node from the array */ | |
455 | pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones]; | |
456 | } | |
457 | ||
458 | if (pPrevNode != NULL) { | |
459 | pNode->next_ = pPrevNode->next_; | |
460 | pPrevNode->next_ = pNode; | |
461 | } else { /* insert at the beginning of the list */ | |
462 | ||
463 | pNode->next_ = pAS_Info->usedZones; | |
464 | pAS_Info->usedZones = pNode; | |
465 | } | |
466 | ||
467 | pAS_Info->nZones++; | |
468 | return pNode; | |
469 | } | |
470 | ||
471 | static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t | |
472 | *pAS_Info, | |
473 | struct MT2063_ExclZone_t *pPrevNode, | |
474 | struct MT2063_ExclZone_t | |
475 | *pNodeToRemove) | |
476 | { | |
477 | struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_; | |
478 | ||
479 | /* Make previous node point to the subsequent node */ | |
480 | if (pPrevNode != NULL) | |
481 | pPrevNode->next_ = pNext; | |
482 | ||
483 | /* Add pNodeToRemove to the beginning of the freeZones */ | |
484 | pNodeToRemove->next_ = pAS_Info->freeZones; | |
485 | pAS_Info->freeZones = pNodeToRemove; | |
486 | ||
487 | /* Decrement node count */ | |
488 | pAS_Info->nZones--; | |
489 | ||
490 | return pNext; | |
491 | } | |
492 | ||
493 | /***************************************************************************** | |
494 | ** | |
495 | ** Name: MT_AddExclZone | |
496 | ** | |
497 | ** Description: Add (and merge) an exclusion zone into the list. | |
498 | ** If the range (f_min, f_max) is totally outside the | |
499 | ** 1st IF BW, ignore the entry. | |
500 | ** If the range (f_min, f_max) is negative, ignore the entry. | |
501 | ** | |
502 | ** Revision History: | |
503 | ** | |
504 | ** SCR Date Author Description | |
505 | ** ------------------------------------------------------------------------- | |
506 | ** 103 01-31-2005 DAD Ver 1.14: In MT_AddExclZone(), if the range | |
507 | ** (f_min, f_max) < 0, ignore the entry. | |
508 | ** | |
509 | *****************************************************************************/ | |
bf97555e | 510 | static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info, |
cfde8925 | 511 | u32 f_min, u32 f_max) |
0e301442 MCC |
512 | { |
513 | struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones; | |
514 | struct MT2063_ExclZone_t *pPrev = NULL; | |
515 | struct MT2063_ExclZone_t *pNext = NULL; | |
516 | ||
517 | /* Check to see if this overlaps the 1st IF filter */ | |
518 | if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2))) | |
519 | && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2))) | |
520 | && (f_min < f_max)) { | |
521 | /* | |
522 | ** 1 2 3 4 5 6 | |
523 | ** | |
524 | ** New entry: |---| |--| |--| |-| |---| |--| | |
525 | ** or or or or or | |
526 | ** Existing: |--| |--| |--| |---| |-| |--| | |
527 | */ | |
528 | ||
529 | /* Check for our place in the list */ | |
530 | while ((pNode != NULL) && (pNode->max_ < f_min)) { | |
531 | pPrev = pNode; | |
532 | pNode = pNode->next_; | |
533 | } | |
534 | ||
535 | if ((pNode != NULL) && (pNode->min_ < f_max)) { | |
536 | /* Combine me with pNode */ | |
537 | if (f_min < pNode->min_) | |
538 | pNode->min_ = f_min; | |
539 | if (f_max > pNode->max_) | |
540 | pNode->max_ = f_max; | |
541 | } else { | |
542 | pNode = InsertNode(pAS_Info, pPrev); | |
543 | pNode->min_ = f_min; | |
544 | pNode->max_ = f_max; | |
545 | } | |
546 | ||
547 | /* Look for merging possibilities */ | |
548 | pNext = pNode->next_; | |
549 | while ((pNext != NULL) && (pNext->min_ < pNode->max_)) { | |
550 | if (pNext->max_ > pNode->max_) | |
551 | pNode->max_ = pNext->max_; | |
552 | pNext = RemoveNode(pAS_Info, pNode, pNext); /* Remove pNext, return ptr to pNext->next */ | |
553 | } | |
554 | } | |
555 | } | |
556 | ||
557 | /***************************************************************************** | |
558 | ** | |
559 | ** Name: MT_ChooseFirstIF | |
560 | ** | |
561 | ** Description: Choose the best available 1st IF | |
562 | ** If f_Desired is not excluded, choose that first. | |
563 | ** Otherwise, return the value closest to f_Center that is | |
564 | ** not excluded | |
565 | ** | |
566 | ** Revision History: | |
567 | ** | |
568 | ** SCR Date Author Description | |
569 | ** ------------------------------------------------------------------------- | |
570 | ** 117 03-29-2007 RSK Ver 1.15: Re-wrote to match search order from | |
571 | ** tuner DLL. | |
572 | ** 147 07-27-2007 RSK Ver 1.17: Corrected calculation (-) to (+) | |
573 | ** Added logic to force f_Center within 1/2 f_Step. | |
574 | ** | |
575 | *****************************************************************************/ | |
bf97555e | 576 | static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info) |
0e301442 MCC |
577 | { |
578 | /* | |
579 | ** Update "f_Desired" to be the nearest "combinational-multiple" of "f_LO1_Step". | |
580 | ** The resulting number, F_LO1 must be a multiple of f_LO1_Step. And F_LO1 is the arithmetic sum | |
581 | ** of f_in + f_Center. Neither f_in, nor f_Center must be a multiple of f_LO1_Step. | |
582 | ** However, the sum must be. | |
583 | */ | |
cfde8925 | 584 | const u32 f_Desired = |
0e301442 MCC |
585 | pAS_Info->f_LO1_Step * |
586 | ((pAS_Info->f_if1_Request + pAS_Info->f_in + | |
587 | pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) - | |
588 | pAS_Info->f_in; | |
cfde8925 | 589 | const u32 f_Step = |
0e301442 MCC |
590 | (pAS_Info->f_LO1_Step > |
591 | pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info-> | |
592 | f_LO2_Step; | |
cfde8925 MCC |
593 | u32 f_Center; |
594 | ||
595 | s32 i; | |
596 | s32 j = 0; | |
597 | u32 bDesiredExcluded = 0; | |
598 | u32 bZeroExcluded = 0; | |
599 | s32 tmpMin, tmpMax; | |
600 | s32 bestDiff; | |
0e301442 MCC |
601 | struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones; |
602 | struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES]; | |
603 | ||
604 | if (pAS_Info->nZones == 0) | |
605 | return f_Desired; | |
606 | ||
607 | /* f_Center needs to be an integer multiple of f_Step away from f_Desired */ | |
608 | if (pAS_Info->f_if1_Center > f_Desired) | |
609 | f_Center = | |
610 | f_Desired + | |
611 | f_Step * | |
612 | ((pAS_Info->f_if1_Center - f_Desired + | |
613 | f_Step / 2) / f_Step); | |
614 | else | |
615 | f_Center = | |
616 | f_Desired - | |
617 | f_Step * | |
618 | ((f_Desired - pAS_Info->f_if1_Center + | |
619 | f_Step / 2) / f_Step); | |
620 | ||
621 | //assert; | |
cfde8925 | 622 | //if (!abs((s32) f_Center - (s32) pAS_Info->f_if1_Center) <= (s32) (f_Step/2)) |
0e301442 MCC |
623 | // return 0; |
624 | ||
625 | /* Take MT_ExclZones, center around f_Center and change the resolution to f_Step */ | |
626 | while (pNode != NULL) { | |
627 | /* floor function */ | |
628 | tmpMin = | |
cfde8925 | 629 | floor((s32) (pNode->min_ - f_Center), (s32) f_Step); |
0e301442 MCC |
630 | |
631 | /* ceil function */ | |
632 | tmpMax = | |
cfde8925 | 633 | ceil((s32) (pNode->max_ - f_Center), (s32) f_Step); |
0e301442 MCC |
634 | |
635 | if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired)) | |
636 | bDesiredExcluded = 1; | |
637 | ||
638 | if ((tmpMin < 0) && (tmpMax > 0)) | |
639 | bZeroExcluded = 1; | |
640 | ||
641 | /* See if this zone overlaps the previous */ | |
642 | if ((j > 0) && (tmpMin < zones[j - 1].max_)) | |
643 | zones[j - 1].max_ = tmpMax; | |
644 | else { | |
645 | /* Add new zone */ | |
646 | //assert(j<MT2063_MAX_ZONES); | |
647 | //if (j>=MT2063_MAX_ZONES) | |
648 | //break; | |
649 | ||
650 | zones[j].min_ = tmpMin; | |
651 | zones[j].max_ = tmpMax; | |
652 | j++; | |
653 | } | |
654 | pNode = pNode->next_; | |
655 | } | |
656 | ||
657 | /* | |
658 | ** If the desired is okay, return with it | |
659 | */ | |
660 | if (bDesiredExcluded == 0) | |
661 | return f_Desired; | |
662 | ||
663 | /* | |
664 | ** If the desired is excluded and the center is okay, return with it | |
665 | */ | |
666 | if (bZeroExcluded == 0) | |
667 | return f_Center; | |
668 | ||
669 | /* Find the value closest to 0 (f_Center) */ | |
670 | bestDiff = zones[0].min_; | |
671 | for (i = 0; i < j; i++) { | |
672 | if (abs(zones[i].min_) < abs(bestDiff)) | |
673 | bestDiff = zones[i].min_; | |
674 | if (abs(zones[i].max_) < abs(bestDiff)) | |
675 | bestDiff = zones[i].max_; | |
676 | } | |
677 | ||
678 | if (bestDiff < 0) | |
cfde8925 | 679 | return f_Center - ((u32) (-bestDiff) * f_Step); |
0e301442 MCC |
680 | |
681 | return f_Center + (bestDiff * f_Step); | |
682 | } | |
683 | ||
684 | /**************************************************************************** | |
685 | ** | |
686 | ** Name: gcd | |
687 | ** | |
688 | ** Description: Uses Euclid's algorithm | |
689 | ** | |
690 | ** Parameters: u, v - unsigned values whose GCD is desired. | |
691 | ** | |
692 | ** Global: None | |
693 | ** | |
694 | ** Returns: greatest common divisor of u and v, if either value | |
695 | ** is 0, the other value is returned as the result. | |
696 | ** | |
697 | ** Dependencies: None. | |
698 | ** | |
699 | ** Revision History: | |
700 | ** | |
701 | ** SCR Date Author Description | |
702 | ** ------------------------------------------------------------------------- | |
703 | ** N/A 06-01-2004 JWS Original | |
704 | ** N/A 08-03-2004 DAD Changed to Euclid's since it can handle | |
705 | ** unsigned numbers. | |
706 | ** | |
707 | ****************************************************************************/ | |
cfde8925 | 708 | static u32 MT2063_gcd(u32 u, u32 v) |
0e301442 | 709 | { |
cfde8925 | 710 | u32 r; |
0e301442 MCC |
711 | |
712 | while (v != 0) { | |
713 | r = u % v; | |
714 | u = v; | |
715 | v = r; | |
716 | } | |
717 | ||
718 | return u; | |
719 | } | |
720 | ||
0e301442 MCC |
721 | /**************************************************************************** |
722 | ** | |
723 | ** Name: IsSpurInBand | |
724 | ** | |
725 | ** Description: Checks to see if a spur will be present within the IF's | |
726 | ** bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW) | |
727 | ** | |
728 | ** ma mb mc md | |
729 | ** <--+-+-+-------------------+-------------------+-+-+--> | |
730 | ** | ^ 0 ^ | | |
731 | ** ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^ | |
732 | ** a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2 | |
733 | ** | |
734 | ** Note that some equations are doubled to prevent round-off | |
735 | ** problems when calculating fIFBW/2 | |
736 | ** | |
737 | ** Parameters: pAS_Info - Avoid Spurs information block | |
738 | ** fm - If spur, amount f_IF1 has to move negative | |
739 | ** fp - If spur, amount f_IF1 has to move positive | |
740 | ** | |
741 | ** Global: None | |
742 | ** | |
743 | ** Returns: 1 if an LO spur would be present, otherwise 0. | |
744 | ** | |
745 | ** Dependencies: None. | |
746 | ** | |
747 | ** Revision History: | |
748 | ** | |
749 | ** SCR Date Author Description | |
750 | ** ------------------------------------------------------------------------- | |
751 | ** N/A 11-28-2002 DAD Implemented algorithm from applied patent | |
752 | ** | |
753 | ****************************************************************************/ | |
cfde8925 MCC |
754 | static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info, |
755 | u32 * fm, u32 * fp) | |
0e301442 MCC |
756 | { |
757 | /* | |
758 | ** Calculate LO frequency settings. | |
759 | */ | |
cfde8925 MCC |
760 | u32 n, n0; |
761 | const u32 f_LO1 = pAS_Info->f_LO1; | |
762 | const u32 f_LO2 = pAS_Info->f_LO2; | |
763 | const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2; | |
764 | const u32 c = d - pAS_Info->f_out_bw; | |
765 | const u32 f = pAS_Info->f_zif_bw / 2; | |
d0dcc2da | 766 | const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1; |
cfde8925 MCC |
767 | s32 f_nsLO1, f_nsLO2; |
768 | s32 f_Spur; | |
769 | u32 ma, mb, mc, md, me, mf; | |
770 | u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs; | |
0e301442 MCC |
771 | *fm = 0; |
772 | ||
773 | /* | |
774 | ** For each edge (d, c & f), calculate a scale, based on the gcd | |
775 | ** of f_LO1, f_LO2 and the edge value. Use the larger of this | |
776 | ** gcd-based scale factor or f_Scale. | |
777 | */ | |
778 | lo_gcd = MT2063_gcd(f_LO1, f_LO2); | |
fd1126ca | 779 | gd_Scale = max((u32) MT2063_gcd(lo_gcd, d), f_Scale); |
0e301442 | 780 | hgds = gd_Scale / 2; |
fd1126ca | 781 | gc_Scale = max((u32) MT2063_gcd(lo_gcd, c), f_Scale); |
0e301442 | 782 | hgcs = gc_Scale / 2; |
fd1126ca | 783 | gf_Scale = max((u32) MT2063_gcd(lo_gcd, f), f_Scale); |
0e301442 MCC |
784 | hgfs = gf_Scale / 2; |
785 | ||
e930b3a0 | 786 | n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2); |
0e301442 MCC |
787 | |
788 | /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */ | |
789 | for (n = n0; n <= pAS_Info->maxH1; ++n) { | |
790 | md = (n * ((f_LO1 + hgds) / gd_Scale) - | |
791 | ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale); | |
792 | ||
793 | /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */ | |
794 | if (md >= pAS_Info->maxH1) | |
795 | break; | |
796 | ||
797 | ma = (n * ((f_LO1 + hgds) / gd_Scale) + | |
798 | ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale); | |
799 | ||
800 | /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */ | |
801 | if (md == ma) | |
802 | continue; | |
803 | ||
804 | mc = (n * ((f_LO1 + hgcs) / gc_Scale) - | |
805 | ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale); | |
806 | if (mc != md) { | |
cfde8925 MCC |
807 | f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale)); |
808 | f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale)); | |
0e301442 MCC |
809 | f_Spur = |
810 | (gc_Scale * (f_nsLO1 - f_nsLO2)) + | |
811 | n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale); | |
812 | ||
cfde8925 MCC |
813 | *fp = ((f_Spur - (s32) c) / (mc - n)) + 1; |
814 | *fm = (((s32) d - f_Spur) / (mc - n)) + 1; | |
0e301442 MCC |
815 | return 1; |
816 | } | |
817 | ||
818 | /* Location of Zero-IF-spur to be checked */ | |
819 | me = (n * ((f_LO1 + hgfs) / gf_Scale) + | |
820 | ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale); | |
821 | mf = (n * ((f_LO1 + hgfs) / gf_Scale) - | |
822 | ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale); | |
823 | if (me != mf) { | |
824 | f_nsLO1 = n * (f_LO1 / gf_Scale); | |
825 | f_nsLO2 = me * (f_LO2 / gf_Scale); | |
826 | f_Spur = | |
827 | (gf_Scale * (f_nsLO1 - f_nsLO2)) + | |
828 | n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale); | |
829 | ||
cfde8925 MCC |
830 | *fp = ((f_Spur + (s32) f) / (me - n)) + 1; |
831 | *fm = (((s32) f - f_Spur) / (me - n)) + 1; | |
0e301442 MCC |
832 | return 1; |
833 | } | |
834 | ||
835 | mb = (n * ((f_LO1 + hgcs) / gc_Scale) + | |
836 | ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale); | |
837 | if (ma != mb) { | |
838 | f_nsLO1 = n * (f_LO1 / gc_Scale); | |
839 | f_nsLO2 = ma * (f_LO2 / gc_Scale); | |
840 | f_Spur = | |
841 | (gc_Scale * (f_nsLO1 - f_nsLO2)) + | |
842 | n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale); | |
843 | ||
cfde8925 MCC |
844 | *fp = (((s32) d + f_Spur) / (ma - n)) + 1; |
845 | *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1; | |
0e301442 MCC |
846 | return 1; |
847 | } | |
848 | } | |
849 | ||
0e301442 MCC |
850 | /* No spurs found */ |
851 | return 0; | |
852 | } | |
853 | ||
854 | /***************************************************************************** | |
855 | ** | |
856 | ** Name: MT_AvoidSpurs | |
857 | ** | |
858 | ** Description: Main entry point to avoid spurs. | |
859 | ** Checks for existing spurs in present LO1, LO2 freqs | |
860 | ** and if present, chooses spur-free LO1, LO2 combination | |
861 | ** that tunes the same input/output frequencies. | |
862 | ** | |
863 | ** Revision History: | |
864 | ** | |
865 | ** SCR Date Author Description | |
866 | ** ------------------------------------------------------------------------- | |
867 | ** 096 04-06-2005 DAD Ver 1.11: Fix divide by 0 error if maxH==0. | |
868 | ** | |
869 | *****************************************************************************/ | |
bf97555e | 870 | static u32 MT2063_AvoidSpurs(void *h, struct MT2063_AvoidSpursData_t * pAS_Info) |
0e301442 | 871 | { |
fdf77a4f | 872 | u32 status = 0; |
cfde8925 | 873 | u32 fm, fp; /* restricted range on LO's */ |
0e301442 MCC |
874 | pAS_Info->bSpurAvoided = 0; |
875 | pAS_Info->nSpursFound = 0; | |
876 | ||
877 | if (pAS_Info->maxH1 == 0) | |
fdf77a4f | 878 | return 0; |
0e301442 MCC |
879 | |
880 | /* | |
881 | ** Avoid LO Generated Spurs | |
882 | ** | |
883 | ** Make sure that have no LO-related spurs within the IF output | |
884 | ** bandwidth. | |
885 | ** | |
886 | ** If there is an LO spur in this band, start at the current IF1 frequency | |
887 | ** and work out until we find a spur-free frequency or run up against the | |
888 | ** 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they | |
889 | ** will be unchanged if a spur-free setting is not found. | |
890 | */ | |
891 | pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp); | |
892 | if (pAS_Info->bSpurPresent) { | |
cfde8925 MCC |
893 | u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */ |
894 | u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */ | |
895 | u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */ | |
896 | u32 delta_IF1; | |
897 | u32 new_IF1; | |
0e301442 MCC |
898 | |
899 | /* | |
900 | ** Spur was found, attempt to find a spur-free 1st IF | |
901 | */ | |
902 | do { | |
903 | pAS_Info->nSpursFound++; | |
904 | ||
905 | /* Raise f_IF1_upper, if needed */ | |
906 | MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp); | |
907 | ||
908 | /* Choose next IF1 that is closest to f_IF1_CENTER */ | |
909 | new_IF1 = MT2063_ChooseFirstIF(pAS_Info); | |
910 | ||
911 | if (new_IF1 > zfIF1) { | |
912 | pAS_Info->f_LO1 += (new_IF1 - zfIF1); | |
913 | pAS_Info->f_LO2 += (new_IF1 - zfIF1); | |
914 | } else { | |
915 | pAS_Info->f_LO1 -= (zfIF1 - new_IF1); | |
916 | pAS_Info->f_LO2 -= (zfIF1 - new_IF1); | |
917 | } | |
918 | zfIF1 = new_IF1; | |
919 | ||
920 | if (zfIF1 > pAS_Info->f_if1_Center) | |
921 | delta_IF1 = zfIF1 - pAS_Info->f_if1_Center; | |
922 | else | |
923 | delta_IF1 = pAS_Info->f_if1_Center - zfIF1; | |
924 | } | |
925 | /* | |
926 | ** Continue while the new 1st IF is still within the 1st IF bandwidth | |
927 | ** and there is a spur in the band (again) | |
928 | */ | |
929 | while ((2 * delta_IF1 + pAS_Info->f_out_bw <= | |
930 | pAS_Info->f_if1_bw) | |
931 | && (pAS_Info->bSpurPresent = | |
932 | IsSpurInBand(pAS_Info, &fm, &fp))); | |
933 | ||
934 | /* | |
935 | ** Use the LO-spur free values found. If the search went all the way to | |
936 | ** the 1st IF band edge and always found spurs, just leave the original | |
937 | ** choice. It's as "good" as any other. | |
938 | */ | |
939 | if (pAS_Info->bSpurPresent == 1) { | |
940 | status |= MT2063_SPUR_PRESENT_ERR; | |
941 | pAS_Info->f_LO1 = zfLO1; | |
942 | pAS_Info->f_LO2 = zfLO2; | |
943 | } else | |
944 | pAS_Info->bSpurAvoided = 1; | |
945 | } | |
946 | ||
947 | status |= | |
948 | ((pAS_Info-> | |
949 | nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK); | |
950 | ||
951 | return (status); | |
952 | } | |
953 | ||
0e301442 MCC |
954 | /* |
955 | ** The expected version of MT_AvoidSpursData_t | |
956 | ** If the version is different, an updated file is needed from Microtune | |
957 | */ | |
0e301442 MCC |
958 | |
959 | typedef enum { | |
960 | MT2063_SET_ATTEN, | |
961 | MT2063_INCR_ATTEN, | |
962 | MT2063_DECR_ATTEN | |
963 | } MT2063_ATTEN_CNTL_MODE; | |
964 | ||
0e301442 | 965 | /* |
66aea30d MCC |
966 | * Constants used by the tuning algorithm |
967 | */ | |
0e301442 MCC |
968 | #define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */ |
969 | #define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */ | |
970 | #define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */ | |
971 | #define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */ | |
972 | #define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */ | |
973 | #define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */ | |
974 | #define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */ | |
975 | #define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */ | |
976 | #define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */ | |
977 | #define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */ | |
978 | #define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */ | |
979 | #define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */ | |
980 | #define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */ | |
981 | #define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */ | |
982 | #define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */ | |
983 | #define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */ | |
984 | #define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */ | |
985 | #define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */ | |
986 | ||
987 | /* | |
988 | ** Define the supported Part/Rev codes for the MT2063 | |
989 | */ | |
990 | #define MT2063_B0 (0x9B) | |
991 | #define MT2063_B1 (0x9C) | |
992 | #define MT2063_B2 (0x9D) | |
993 | #define MT2063_B3 (0x9E) | |
994 | ||
0e301442 MCC |
995 | /* |
996 | ** Constants for setting receiver modes. | |
997 | ** (6 modes defined at this time, enumerated by MT2063_RCVR_MODES) | |
998 | ** (DNC1GC & DNC2GC are the values, which are used, when the specific | |
999 | ** DNC Output is selected, the other is always off) | |
1000 | ** | |
1001 | ** If PAL-L or L' is received, set: | |
1002 | ** MT2063_SetParam(hMT2063,MT2063_TAGC,1); | |
1003 | ** | |
1004 | ** --------------+---------------------------------------------- | |
1005 | ** Mode 0 : | MT2063_CABLE_QAM | |
1006 | ** Mode 1 : | MT2063_CABLE_ANALOG | |
1007 | ** Mode 2 : | MT2063_OFFAIR_COFDM | |
1008 | ** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS | |
1009 | ** Mode 4 : | MT2063_OFFAIR_ANALOG | |
1010 | ** Mode 5 : | MT2063_OFFAIR_8VSB | |
1011 | ** --------------+----+----+----+----+-----+-----+-------------- | |
1012 | ** Mode | 0 | 1 | 2 | 3 | 4 | 5 | | |
1013 | ** --------------+----+----+----+----+-----+-----+ | |
1014 | ** | |
1015 | ** | |
1016 | */ | |
cfde8925 MCC |
1017 | static const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 }; |
1018 | static const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 }; | |
1019 | static const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 }; | |
1020 | static const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 }; | |
1021 | static const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 }; | |
1022 | static const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 }; | |
1023 | static const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 }; | |
1024 | static const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 }; | |
1025 | static const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 }; | |
1026 | static const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 }; | |
1027 | static const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 }; | |
1028 | static const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 }; | |
1029 | static const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 }; | |
1030 | static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 }; | |
0e301442 MCC |
1031 | |
1032 | /* | |
1033 | ** Local Function Prototypes - not available for external access. | |
1034 | */ | |
1035 | ||
1036 | /* Forward declaration(s): */ | |
cfde8925 MCC |
1037 | static u32 MT2063_CalcLO1Mult(u32 * Div, u32 * FracN, u32 f_LO, |
1038 | u32 f_LO_Step, u32 f_Ref); | |
1039 | static u32 MT2063_CalcLO2Mult(u32 * Div, u32 * FracN, u32 f_LO, | |
1040 | u32 f_LO_Step, u32 f_Ref); | |
1041 | static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, | |
1042 | u32 denom); | |
0e301442 | 1043 | |
31e67fae MCC |
1044 | /** |
1045 | * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked | |
1046 | * | |
1047 | * @state: struct mt2063_state pointer | |
1048 | * | |
1049 | * This function returns 0, if no lock, 1 if locked and a value < 1 if error | |
1050 | */ | |
1051 | unsigned int mt2063_lockStatus(struct mt2063_state *state) | |
0e301442 | 1052 | { |
cfde8925 MCC |
1053 | const u32 nMaxWait = 100; /* wait a maximum of 100 msec */ |
1054 | const u32 nPollRate = 2; /* poll status bits every 2 ms */ | |
1055 | const u32 nMaxLoops = nMaxWait / nPollRate; | |
1056 | const u8 LO1LK = 0x80; | |
1057 | u8 LO2LK = 0x08; | |
31e67fae | 1058 | u32 status; |
cfde8925 | 1059 | u32 nDelays = 0; |
0e301442 | 1060 | |
0e301442 | 1061 | /* LO2 Lock bit was in a different place for B0 version */ |
dcd52d20 | 1062 | if (state->tuner_id == MT2063_B0) |
0e301442 MCC |
1063 | LO2LK = 0x40; |
1064 | ||
1065 | do { | |
31e67fae MCC |
1066 | status = mt2063_read(state, MT2063_REG_LO_STATUS, |
1067 | &state->reg[MT2063_REG_LO_STATUS], 1); | |
0e301442 | 1068 | |
fdf77a4f | 1069 | if (status < 0) |
31e67fae | 1070 | return status; |
0e301442 | 1071 | |
dcd52d20 | 1072 | if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) == |
0e301442 | 1073 | (LO1LK | LO2LK)) { |
31e67fae | 1074 | return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO; |
0e301442 | 1075 | } |
bf97555e | 1076 | msleep(nPollRate); /* Wait between retries */ |
0e301442 MCC |
1077 | } |
1078 | while (++nDelays < nMaxLoops); | |
1079 | ||
31e67fae MCC |
1080 | /* |
1081 | * Got no lock or partial lock | |
1082 | */ | |
1083 | return 0; | |
0e301442 | 1084 | } |
3d49700f | 1085 | EXPORT_SYMBOL_GPL(mt2063_lockStatus); |
0e301442 | 1086 | |
4713e225 MCC |
1087 | /* |
1088 | * mt2063_set_dnc_output_enable() | |
1089 | */ | |
1090 | static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state, | |
1091 | enum MT2063_DNC_Output_Enable *pValue) | |
0e301442 | 1092 | { |
4713e225 MCC |
1093 | if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */ |
1094 | if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */ | |
1095 | *pValue = MT2063_DNC_NONE; | |
1096 | else | |
1097 | *pValue = MT2063_DNC_2; | |
1098 | } else { /* DNC1 is on */ | |
1099 | if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */ | |
1100 | *pValue = MT2063_DNC_1; | |
1101 | else | |
1102 | *pValue = MT2063_DNC_BOTH; | |
1103 | } | |
1104 | return 0; | |
1105 | } | |
0e301442 | 1106 | |
4713e225 MCC |
1107 | /* |
1108 | * mt2063_set_dnc_output_enable() | |
1109 | */ | |
1110 | static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state, | |
1111 | enum MT2063_DNC_Output_Enable nValue) | |
1112 | { | |
1113 | u32 status = 0; /* Status to be returned */ | |
1114 | u8 val = 0; | |
51f0f7b3 | 1115 | |
4713e225 MCC |
1116 | /* selects, which DNC output is used */ |
1117 | switch (nValue) { | |
1118 | case MT2063_DNC_NONE: | |
51f0f7b3 | 1119 | { |
4713e225 MCC |
1120 | val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */ |
1121 | if (state->reg[MT2063_REG_DNC_GAIN] != | |
1122 | val) | |
1123 | status |= | |
1124 | MT2063_SetReg(state, | |
1125 | MT2063_REG_DNC_GAIN, | |
1126 | val); | |
51f0f7b3 | 1127 | |
4713e225 MCC |
1128 | val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */ |
1129 | if (state->reg[MT2063_REG_VGA_GAIN] != | |
1130 | val) | |
1131 | status |= | |
1132 | MT2063_SetReg(state, | |
1133 | MT2063_REG_VGA_GAIN, | |
1134 | val); | |
51f0f7b3 | 1135 | |
4713e225 MCC |
1136 | val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */ |
1137 | if (state->reg[MT2063_REG_RSVD_20] != | |
1138 | val) | |
1139 | status |= | |
1140 | MT2063_SetReg(state, | |
1141 | MT2063_REG_RSVD_20, | |
1142 | val); | |
51f0f7b3 | 1143 | |
4713e225 | 1144 | break; |
51f0f7b3 | 1145 | } |
4713e225 MCC |
1146 | case MT2063_DNC_1: |
1147 | { | |
1148 | val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */ | |
1149 | if (state->reg[MT2063_REG_DNC_GAIN] != | |
1150 | val) | |
1151 | status |= | |
1152 | MT2063_SetReg(state, | |
1153 | MT2063_REG_DNC_GAIN, | |
1154 | val); | |
51f0f7b3 | 1155 | |
4713e225 MCC |
1156 | val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */ |
1157 | if (state->reg[MT2063_REG_VGA_GAIN] != | |
1158 | val) | |
1159 | status |= | |
1160 | MT2063_SetReg(state, | |
1161 | MT2063_REG_VGA_GAIN, | |
1162 | val); | |
51f0f7b3 | 1163 | |
4713e225 MCC |
1164 | val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */ |
1165 | if (state->reg[MT2063_REG_RSVD_20] != | |
1166 | val) | |
1167 | status |= | |
1168 | MT2063_SetReg(state, | |
1169 | MT2063_REG_RSVD_20, | |
1170 | val); | |
51f0f7b3 | 1171 | |
4713e225 | 1172 | break; |
51f0f7b3 | 1173 | } |
4713e225 MCC |
1174 | case MT2063_DNC_2: |
1175 | { | |
1176 | val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */ | |
1177 | if (state->reg[MT2063_REG_DNC_GAIN] != | |
1178 | val) | |
1179 | status |= | |
1180 | MT2063_SetReg(state, | |
1181 | MT2063_REG_DNC_GAIN, | |
1182 | val); | |
51f0f7b3 | 1183 | |
4713e225 MCC |
1184 | val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */ |
1185 | if (state->reg[MT2063_REG_VGA_GAIN] != | |
1186 | val) | |
1187 | status |= | |
1188 | MT2063_SetReg(state, | |
1189 | MT2063_REG_VGA_GAIN, | |
1190 | val); | |
fdf77a4f | 1191 | |
4713e225 MCC |
1192 | val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */ |
1193 | if (state->reg[MT2063_REG_RSVD_20] != | |
1194 | val) | |
1195 | status |= | |
1196 | MT2063_SetReg(state, | |
1197 | MT2063_REG_RSVD_20, | |
1198 | val); | |
51f0f7b3 | 1199 | |
4713e225 MCC |
1200 | break; |
1201 | } | |
1202 | case MT2063_DNC_BOTH: | |
1203 | { | |
1204 | val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */ | |
1205 | if (state->reg[MT2063_REG_DNC_GAIN] != | |
1206 | val) | |
1207 | status |= | |
1208 | MT2063_SetReg(state, | |
1209 | MT2063_REG_DNC_GAIN, | |
1210 | val); | |
51f0f7b3 | 1211 | |
4713e225 MCC |
1212 | val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */ |
1213 | if (state->reg[MT2063_REG_VGA_GAIN] != | |
1214 | val) | |
1215 | status |= | |
1216 | MT2063_SetReg(state, | |
1217 | MT2063_REG_VGA_GAIN, | |
1218 | val); | |
51f0f7b3 | 1219 | |
4713e225 MCC |
1220 | val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */ |
1221 | if (state->reg[MT2063_REG_RSVD_20] != | |
1222 | val) | |
1223 | status |= | |
1224 | MT2063_SetReg(state, | |
1225 | MT2063_REG_RSVD_20, | |
1226 | val); | |
51f0f7b3 | 1227 | |
4713e225 | 1228 | break; |
51f0f7b3 | 1229 | } |
51f0f7b3 | 1230 | default: |
4713e225 | 1231 | break; |
51f0f7b3 | 1232 | } |
0e301442 MCC |
1233 | |
1234 | return (status); | |
1235 | } | |
1236 | ||
0e301442 MCC |
1237 | /****************************************************************************** |
1238 | ** | |
1239 | ** Name: MT2063_SetReceiverMode | |
1240 | ** | |
1241 | ** Description: Set the MT2063 receiver mode | |
1242 | ** | |
1243 | ** --------------+---------------------------------------------- | |
1244 | ** Mode 0 : | MT2063_CABLE_QAM | |
1245 | ** Mode 1 : | MT2063_CABLE_ANALOG | |
1246 | ** Mode 2 : | MT2063_OFFAIR_COFDM | |
1247 | ** Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS | |
1248 | ** Mode 4 : | MT2063_OFFAIR_ANALOG | |
1249 | ** Mode 5 : | MT2063_OFFAIR_8VSB | |
1250 | ** --------------+----+----+----+----+-----+-------------------- | |
1251 | ** (DNC1GC & DNC2GC are the values, which are used, when the specific | |
1252 | ** DNC Output is selected, the other is always off) | |
1253 | ** | |
1254 | ** |<---------- Mode -------------->| | |
1255 | ** Reg Field | 0 | 1 | 2 | 3 | 4 | 5 | | |
1256 | ** ------------+-----+-----+-----+-----+-----+-----+ | |
1257 | ** RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF | |
1258 | ** LNARin | 0 | 0 | 3 | 3 | 3 | 3 | |
1259 | ** FIFFQen | 1 | 1 | 1 | 1 | 1 | 1 | |
1260 | ** FIFFq | 0 | 0 | 0 | 0 | 0 | 0 | |
1261 | ** DNC1gc | 0 | 0 | 0 | 0 | 0 | 0 | |
1262 | ** DNC2gc | 0 | 0 | 0 | 0 | 0 | 0 | |
1263 | ** GCU Auto | 1 | 1 | 1 | 1 | 1 | 1 | |
1264 | ** LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31 | |
1265 | ** LNA Target | 44 | 43 | 43 | 43 | 43 | 43 | |
1266 | ** ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0 | |
1267 | ** RF max Atn | 31 | 31 | 31 | 31 | 31 | 31 | |
1268 | ** PD1 Target | 36 | 36 | 38 | 38 | 36 | 38 | |
1269 | ** ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0 | |
1270 | ** FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5 | |
1271 | ** PD2 Target | 40 | 33 | 42 | 42 | 33 | 42 | |
1272 | ** | |
1273 | ** | |
dcd52d20 | 1274 | ** Parameters: state - ptr to mt2063_state structure |
0e301442 MCC |
1275 | ** Mode - desired reciever mode |
1276 | ** | |
1277 | ** Usage: status = MT2063_SetReceiverMode(hMT2063, Mode); | |
1278 | ** | |
1279 | ** Returns: status: | |
1280 | ** MT_OK - No errors | |
1281 | ** MT_COMM_ERR - Serial bus communications error | |
1282 | ** | |
1283 | ** Dependencies: MT2063_SetReg - Write a byte of data to a HW register. | |
1284 | ** Assumes that the tuner cache is valid. | |
1285 | ** | |
1286 | ** Revision History: | |
1287 | ** | |
1288 | ** SCR Date Author Description | |
1289 | ** ------------------------------------------------------------------------- | |
1290 | ** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b. | |
1291 | ** N/A 01-10-2007 PINZ Added additional GCU Settings, FIFF Calib will be triggered | |
1292 | ** 155 10-01-2007 DAD Ver 1.06: Add receiver mode for SECAM positive | |
1293 | ** modulation | |
1294 | ** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE) | |
1295 | ** N/A 10-22-2007 PINZ Ver 1.07: Changed some Registers at init to have | |
1296 | ** the same settings as with MT Launcher | |
1297 | ** N/A 10-30-2007 PINZ Add SetParam VGAGC & VGAOI | |
1298 | ** Add SetParam DNC_OUTPUT_ENABLE | |
1299 | ** Removed VGAGC from receiver mode, | |
1300 | ** default now 1 | |
1301 | ** N/A 10-31-2007 PINZ Ver 1.08: Add SetParam TAGC, removed from rcvr-mode | |
1302 | ** Add SetParam AMPGC, removed from rcvr-mode | |
1303 | ** Corrected names of GCU values | |
1304 | ** reorganized receiver modes, removed, | |
1305 | ** (MT2063_ANALOG_TV_POS_NO_RFAGC_MODE) | |
1306 | ** Actualized Receiver-Mode values | |
1307 | ** N/A 11-12-2007 PINZ Ver 1.09: Actualized Receiver-Mode values | |
1308 | ** N/A 11-27-2007 PINZ Improved buffered writing | |
1309 | ** 01-03-2008 PINZ Ver 1.10: Added a trigger of BYPATNUP for | |
1310 | ** correct wakeup of the LNA after shutdown | |
1311 | ** Set AFCsd = 1 as default | |
1312 | ** Changed CAP1sel default | |
1313 | ** 01-14-2008 PINZ Ver 1.11: Updated gain settings | |
1314 | ** 04-18-2008 PINZ Ver 1.15: Add SetParam LNARIN & PDxTGT | |
1315 | ** Split SetParam up to ACLNA / ACLNA_MAX | |
1316 | ** removed ACLNA_INRC/DECR (+RF & FIF) | |
1317 | ** removed GCUAUTO / BYPATNDN/UP | |
1318 | ** | |
1319 | ******************************************************************************/ | |
dcd52d20 | 1320 | static u32 MT2063_SetReceiverMode(struct mt2063_state *state, |
0e301442 MCC |
1321 | enum MT2063_RCVR_MODES Mode) |
1322 | { | |
fdf77a4f | 1323 | u32 status = 0; /* Status to be returned */ |
cfde8925 MCC |
1324 | u8 val; |
1325 | u32 longval; | |
0e301442 MCC |
1326 | |
1327 | if (Mode >= MT2063_NUM_RCVR_MODES) | |
fdf77a4f | 1328 | status = -ERANGE; |
0e301442 MCC |
1329 | |
1330 | /* RFAGCen */ | |
fdf77a4f | 1331 | if (status >= 0) { |
0e301442 | 1332 | val = |
dcd52d20 | 1333 | (state-> |
cfde8925 | 1334 | reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x40) | (RFAGCEN[Mode] |
0e301442 MCC |
1335 | ? 0x40 : |
1336 | 0x00); | |
dcd52d20 MCC |
1337 | if (state->reg[MT2063_REG_PD1_TGT] != val) { |
1338 | status |= MT2063_SetReg(state, MT2063_REG_PD1_TGT, val); | |
0e301442 MCC |
1339 | } |
1340 | } | |
1341 | ||
1342 | /* LNARin */ | |
fdf77a4f | 1343 | if (status >= 0) { |
4713e225 MCC |
1344 | u8 val = (state-> reg[MT2063_REG_CTRL_2C] & (u8) ~ 0x03) | |
1345 | (LNARIN[Mode] & 0x03); | |
1346 | if (state->reg[MT2063_REG_CTRL_2C] != val) | |
1347 | status |= MT2063_SetReg(state, MT2063_REG_CTRL_2C, | |
1348 | val); | |
0e301442 MCC |
1349 | } |
1350 | ||
1351 | /* FIFFQEN and FIFFQ */ | |
fdf77a4f | 1352 | if (status >= 0) { |
0e301442 | 1353 | val = |
dcd52d20 | 1354 | (state-> |
cfde8925 | 1355 | reg[MT2063_REG_FIFF_CTRL2] & (u8) ~ 0xF0) | |
0e301442 | 1356 | (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4); |
dcd52d20 | 1357 | if (state->reg[MT2063_REG_FIFF_CTRL2] != val) { |
0e301442 | 1358 | status |= |
dcd52d20 | 1359 | MT2063_SetReg(state, MT2063_REG_FIFF_CTRL2, val); |
0e301442 MCC |
1360 | /* trigger FIFF calibration, needed after changing FIFFQ */ |
1361 | val = | |
dcd52d20 | 1362 | (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01); |
0e301442 | 1363 | status |= |
dcd52d20 | 1364 | MT2063_SetReg(state, MT2063_REG_FIFF_CTRL, val); |
0e301442 | 1365 | val = |
dcd52d20 | 1366 | (state-> |
cfde8925 | 1367 | reg[MT2063_REG_FIFF_CTRL] & (u8) ~ 0x01); |
0e301442 | 1368 | status |= |
dcd52d20 | 1369 | MT2063_SetReg(state, MT2063_REG_FIFF_CTRL, val); |
0e301442 MCC |
1370 | } |
1371 | } | |
1372 | ||
1373 | /* DNC1GC & DNC2GC */ | |
4713e225 MCC |
1374 | status |= mt2063_get_dnc_output_enable(state, &longval); |
1375 | status |= mt2063_set_dnc_output_enable(state, longval); | |
0e301442 MCC |
1376 | |
1377 | /* acLNAmax */ | |
fdf77a4f | 1378 | if (status >= 0) { |
4713e225 MCC |
1379 | u8 val = (state-> reg[MT2063_REG_LNA_OV] & (u8) ~ 0x1F) | |
1380 | (ACLNAMAX[Mode] & 0x1F); | |
1381 | if (state->reg[MT2063_REG_LNA_OV] != val) | |
1382 | status |= MT2063_SetReg(state, MT2063_REG_LNA_OV, val); | |
0e301442 MCC |
1383 | } |
1384 | ||
1385 | /* LNATGT */ | |
fdf77a4f | 1386 | if (status >= 0) { |
4713e225 MCC |
1387 | u8 val = (state-> reg[MT2063_REG_LNA_TGT] & (u8) ~ 0x3F) | |
1388 | (LNATGT[Mode] & 0x3F); | |
1389 | if (state->reg[MT2063_REG_LNA_TGT] != val) | |
1390 | status |= MT2063_SetReg(state, MT2063_REG_LNA_TGT, val); | |
0e301442 MCC |
1391 | } |
1392 | ||
1393 | /* ACRF */ | |
fdf77a4f | 1394 | if (status >= 0) { |
4713e225 MCC |
1395 | u8 val = (state-> reg[MT2063_REG_RF_OV] & (u8) ~ 0x1F) | |
1396 | (ACRFMAX[Mode] & 0x1F); | |
1397 | if (state->reg[MT2063_REG_RF_OV] != val) | |
1398 | status |= MT2063_SetReg(state, MT2063_REG_RF_OV, val); | |
0e301442 MCC |
1399 | } |
1400 | ||
1401 | /* PD1TGT */ | |
fdf77a4f | 1402 | if (status >= 0) { |
4713e225 MCC |
1403 | u8 val = (state-> reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x3F) | |
1404 | (PD1TGT[Mode] & 0x3F); | |
1405 | if (state->reg[MT2063_REG_PD1_TGT] != val) | |
1406 | status |= MT2063_SetReg(state, MT2063_REG_PD1_TGT, val); | |
0e301442 MCC |
1407 | } |
1408 | ||
1409 | /* FIFATN */ | |
fdf77a4f | 1410 | if (status >= 0) { |
4713e225 MCC |
1411 | u8 val = ACFIFMAX[Mode]; |
1412 | if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5) | |
1413 | val = 5; | |
1414 | val = (state-> reg[MT2063_REG_FIF_OV] & (u8) ~ 0x1F) | | |
1415 | (val & 0x1F); | |
1416 | if (state->reg[MT2063_REG_FIF_OV] != val) { | |
1417 | status |= MT2063_SetReg(state, MT2063_REG_FIF_OV, val); | |
1418 | } | |
0e301442 MCC |
1419 | } |
1420 | ||
1421 | /* PD2TGT */ | |
fdf77a4f | 1422 | if (status >= 0) { |
4713e225 MCC |
1423 | u8 val = (state-> reg[MT2063_REG_PD2_TGT] & (u8) ~ 0x3F) | |
1424 | (PD2TGT[Mode] & 0x3F); | |
1425 | if (state->reg[MT2063_REG_PD2_TGT] != val) | |
1426 | status |= MT2063_SetReg(state, MT2063_REG_PD2_TGT, val); | |
0e301442 MCC |
1427 | } |
1428 | ||
1429 | /* Ignore ATN Overload */ | |
fdf77a4f | 1430 | if (status >= 0) { |
0e301442 | 1431 | val = |
dcd52d20 | 1432 | (state-> |
cfde8925 | 1433 | reg[MT2063_REG_LNA_TGT] & (u8) ~ 0x80) | (RFOVDIS[Mode] |
0e301442 MCC |
1434 | ? 0x80 : |
1435 | 0x00); | |
dcd52d20 MCC |
1436 | if (state->reg[MT2063_REG_LNA_TGT] != val) { |
1437 | status |= MT2063_SetReg(state, MT2063_REG_LNA_TGT, val); | |
0e301442 MCC |
1438 | } |
1439 | } | |
1440 | ||
1441 | /* Ignore FIF Overload */ | |
fdf77a4f | 1442 | if (status >= 0) { |
0e301442 | 1443 | val = |
dcd52d20 | 1444 | (state-> |
cfde8925 | 1445 | reg[MT2063_REG_PD1_TGT] & (u8) ~ 0x80) | |
0e301442 | 1446 | (FIFOVDIS[Mode] ? 0x80 : 0x00); |
dcd52d20 MCC |
1447 | if (state->reg[MT2063_REG_PD1_TGT] != val) { |
1448 | status |= MT2063_SetReg(state, MT2063_REG_PD1_TGT, val); | |
0e301442 MCC |
1449 | } |
1450 | } | |
1451 | ||
fdf77a4f | 1452 | if (status >= 0) |
dcd52d20 | 1453 | state->rcvr_mode = Mode; |
0e301442 MCC |
1454 | |
1455 | return (status); | |
1456 | } | |
1457 | ||
0e301442 MCC |
1458 | /**************************************************************************** |
1459 | ** | |
1460 | ** Name: MT2063_ClearPowerMaskBits | |
1461 | ** | |
1462 | ** Description: Clears the power-down mask bits for various sections of | |
1463 | ** the MT2063 | |
1464 | ** | |
1465 | ** Parameters: h - Tuner handle (returned by MT2063_Open) | |
1466 | ** Bits - Mask bits to be cleared. | |
1467 | ** | |
1468 | ** See definition of MT2063_Mask_Bits type for description | |
1469 | ** of each of the power bits. | |
1470 | ** | |
1471 | ** Returns: status: | |
1472 | ** MT_OK - No errors | |
1473 | ** MT_INV_HANDLE - Invalid tuner handle | |
1474 | ** MT_COMM_ERR - Serial bus communications error | |
1475 | ** | |
1476 | ** Dependencies: USERS MUST CALL MT2063_Open() FIRST! | |
1477 | ** | |
1478 | ** Revision History: | |
1479 | ** | |
1480 | ** SCR Date Author Description | |
1481 | ** ------------------------------------------------------------------------- | |
1482 | ** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b. | |
1483 | ** | |
1484 | ****************************************************************************/ | |
dcd52d20 | 1485 | static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, enum MT2063_Mask_Bits Bits) |
0e301442 | 1486 | { |
fdf77a4f | 1487 | u32 status = 0; /* Status to be returned */ |
0e301442 | 1488 | |
fdf77a4f MCC |
1489 | Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */ |
1490 | if ((Bits & 0xFF00) != 0) { | |
dcd52d20 | 1491 | state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8); |
fdf77a4f | 1492 | status |= |
e1de3d18 | 1493 | mt2063_write(state, |
fdf77a4f | 1494 | MT2063_REG_PWR_2, |
dcd52d20 | 1495 | &state->reg[MT2063_REG_PWR_2], 1); |
fdf77a4f MCC |
1496 | } |
1497 | if ((Bits & 0xFF) != 0) { | |
dcd52d20 | 1498 | state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF); |
fdf77a4f | 1499 | status |= |
e1de3d18 | 1500 | mt2063_write(state, |
fdf77a4f | 1501 | MT2063_REG_PWR_1, |
dcd52d20 | 1502 | &state->reg[MT2063_REG_PWR_1], 1); |
0e301442 MCC |
1503 | } |
1504 | ||
1505 | return (status); | |
1506 | } | |
1507 | ||
0e301442 MCC |
1508 | /**************************************************************************** |
1509 | ** | |
1510 | ** Name: MT2063_SoftwareShutdown | |
1511 | ** | |
1512 | ** Description: Enables or disables software shutdown function. When | |
1513 | ** Shutdown==1, any section whose power mask is set will be | |
1514 | ** shutdown. | |
1515 | ** | |
1516 | ** Parameters: h - Tuner handle (returned by MT2063_Open) | |
1517 | ** Shutdown - 1 = shutdown the masked sections, otherwise | |
1518 | ** power all sections on | |
1519 | ** | |
1520 | ** Returns: status: | |
1521 | ** MT_OK - No errors | |
1522 | ** MT_INV_HANDLE - Invalid tuner handle | |
1523 | ** MT_COMM_ERR - Serial bus communications error | |
1524 | ** | |
1525 | ** Dependencies: USERS MUST CALL MT2063_Open() FIRST! | |
1526 | ** | |
1527 | ** Revision History: | |
1528 | ** | |
1529 | ** SCR Date Author Description | |
1530 | ** ------------------------------------------------------------------------- | |
1531 | ** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b. | |
1532 | ** 01-03-2008 PINZ Ver 1.xx: Added a trigger of BYPATNUP for | |
1533 | ** correct wakeup of the LNA | |
1534 | ** | |
1535 | ****************************************************************************/ | |
dcd52d20 | 1536 | static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown) |
0e301442 | 1537 | { |
31e67fae | 1538 | u32 status; /* Status to be returned */ |
0e301442 | 1539 | |
fdf77a4f | 1540 | if (Shutdown == 1) |
dcd52d20 | 1541 | state->reg[MT2063_REG_PWR_1] |= 0x04; /* Turn the bit on */ |
fdf77a4f | 1542 | else |
dcd52d20 | 1543 | state->reg[MT2063_REG_PWR_1] &= ~0x04; /* Turn off the bit */ |
0e301442 | 1544 | |
31e67fae | 1545 | status = mt2063_write(state, |
fdf77a4f | 1546 | MT2063_REG_PWR_1, |
dcd52d20 | 1547 | &state->reg[MT2063_REG_PWR_1], 1); |
fdf77a4f MCC |
1548 | |
1549 | if (Shutdown != 1) { | |
dcd52d20 MCC |
1550 | state->reg[MT2063_REG_BYP_CTRL] = |
1551 | (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40; | |
0e301442 | 1552 | status |= |
e1de3d18 | 1553 | mt2063_write(state, |
fdf77a4f | 1554 | MT2063_REG_BYP_CTRL, |
dcd52d20 | 1555 | &state->reg[MT2063_REG_BYP_CTRL], |
fdf77a4f | 1556 | 1); |
dcd52d20 MCC |
1557 | state->reg[MT2063_REG_BYP_CTRL] = |
1558 | (state->reg[MT2063_REG_BYP_CTRL] & 0x9F); | |
fdf77a4f | 1559 | status |= |
e1de3d18 | 1560 | mt2063_write(state, |
fdf77a4f | 1561 | MT2063_REG_BYP_CTRL, |
dcd52d20 | 1562 | &state->reg[MT2063_REG_BYP_CTRL], |
fdf77a4f | 1563 | 1); |
0e301442 MCC |
1564 | } |
1565 | ||
31e67fae | 1566 | return status; |
0e301442 MCC |
1567 | } |
1568 | ||
0e301442 MCC |
1569 | /**************************************************************************** |
1570 | ** | |
1571 | ** Name: MT2063_SetReg | |
1572 | ** | |
1573 | ** Description: Sets an MT2063 register. | |
1574 | ** | |
1575 | ** Parameters: h - Tuner handle (returned by MT2063_Open) | |
1576 | ** reg - MT2063 register/subaddress location | |
1577 | ** val - MT2063 register/subaddress value | |
1578 | ** | |
1579 | ** Returns: status: | |
1580 | ** MT_OK - No errors | |
1581 | ** MT_COMM_ERR - Serial bus communications error | |
1582 | ** MT_INV_HANDLE - Invalid tuner handle | |
1583 | ** MT_ARG_RANGE - Argument out of range | |
1584 | ** | |
1585 | ** Dependencies: USERS MUST CALL MT2063_Open() FIRST! | |
1586 | ** | |
1587 | ** Use this function if you need to override a default | |
1588 | ** register value | |
1589 | ** | |
1590 | ** Revision History: | |
1591 | ** | |
1592 | ** SCR Date Author Description | |
1593 | ** ------------------------------------------------------------------------- | |
1594 | ** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b. | |
1595 | ** | |
1596 | ****************************************************************************/ | |
dcd52d20 | 1597 | static u32 MT2063_SetReg(struct mt2063_state *state, u8 reg, u8 val) |
0e301442 | 1598 | { |
31e67fae | 1599 | u32 status; |
0e301442 | 1600 | |
0e301442 | 1601 | if (reg >= MT2063_REG_END_REGS) |
31e67fae | 1602 | return -ERANGE; |
0e301442 | 1603 | |
31e67fae MCC |
1604 | status = mt2063_write(state, reg, &val, 1); |
1605 | if (status < 0) | |
1606 | return status; | |
0e301442 | 1607 | |
31e67fae MCC |
1608 | state->reg[reg] = val; |
1609 | ||
1610 | return 0; | |
0e301442 MCC |
1611 | } |
1612 | ||
cfde8925 | 1613 | static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref) |
0e301442 MCC |
1614 | { |
1615 | return f_ref * (f_LO / f_ref) | |
1616 | + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step); | |
1617 | } | |
1618 | ||
1619 | /**************************************************************************** | |
1620 | ** | |
1621 | ** Name: fLO_FractionalTerm | |
1622 | ** | |
1623 | ** Description: Calculates the portion contributed by FracN / denom. | |
1624 | ** | |
1625 | ** This function preserves maximum precision without | |
1626 | ** risk of overflow. It accurately calculates | |
1627 | ** f_ref * num / denom to within 1 HZ with fixed math. | |
1628 | ** | |
1629 | ** Parameters: num - Fractional portion of the multiplier | |
1630 | ** denom - denominator portion of the ratio | |
1631 | ** This routine successfully handles denom values | |
1632 | ** up to and including 2^18. | |
1633 | ** f_Ref - SRO frequency. This calculation handles | |
1634 | ** f_ref as two separate 14-bit fields. | |
1635 | ** Therefore, a maximum value of 2^28-1 | |
1636 | ** may safely be used for f_ref. This is | |
1637 | ** the genesis of the magic number "14" and the | |
1638 | ** magic mask value of 0x03FFF. | |
1639 | ** | |
1640 | ** Returns: f_ref * num / denom | |
1641 | ** | |
1642 | ** Revision History: | |
1643 | ** | |
1644 | ** SCR Date Author Description | |
1645 | ** ------------------------------------------------------------------------- | |
1646 | ** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b. | |
1647 | ** | |
1648 | ****************************************************************************/ | |
cfde8925 MCC |
1649 | static u32 MT2063_fLO_FractionalTerm(u32 f_ref, |
1650 | u32 num, u32 denom) | |
0e301442 | 1651 | { |
cfde8925 MCC |
1652 | u32 t1 = (f_ref >> 14) * num; |
1653 | u32 term1 = t1 / denom; | |
1654 | u32 loss = t1 % denom; | |
1655 | u32 term2 = | |
0e301442 MCC |
1656 | (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom; |
1657 | return ((term1 << 14) + term2); | |
1658 | } | |
1659 | ||
1660 | /**************************************************************************** | |
1661 | ** | |
1662 | ** Name: CalcLO1Mult | |
1663 | ** | |
1664 | ** Description: Calculates Integer divider value and the numerator | |
1665 | ** value for a FracN PLL. | |
1666 | ** | |
1667 | ** This function assumes that the f_LO and f_Ref are | |
1668 | ** evenly divisible by f_LO_Step. | |
1669 | ** | |
1670 | ** Parameters: Div - OUTPUT: Whole number portion of the multiplier | |
1671 | ** FracN - OUTPUT: Fractional portion of the multiplier | |
1672 | ** f_LO - desired LO frequency. | |
1673 | ** f_LO_Step - Minimum step size for the LO (in Hz). | |
1674 | ** f_Ref - SRO frequency. | |
1675 | ** f_Avoid - Range of PLL frequencies to avoid near | |
1676 | ** integer multiples of f_Ref (in Hz). | |
1677 | ** | |
1678 | ** Returns: Recalculated LO frequency. | |
1679 | ** | |
1680 | ** Revision History: | |
1681 | ** | |
1682 | ** SCR Date Author Description | |
1683 | ** ------------------------------------------------------------------------- | |
1684 | ** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b. | |
1685 | ** | |
1686 | ****************************************************************************/ | |
cfde8925 MCC |
1687 | static u32 MT2063_CalcLO1Mult(u32 * Div, |
1688 | u32 * FracN, | |
1689 | u32 f_LO, | |
1690 | u32 f_LO_Step, u32 f_Ref) | |
0e301442 MCC |
1691 | { |
1692 | /* Calculate the whole number portion of the divider */ | |
1693 | *Div = f_LO / f_Ref; | |
1694 | ||
1695 | /* Calculate the numerator value (round to nearest f_LO_Step) */ | |
1696 | *FracN = | |
1697 | (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) + | |
1698 | (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step); | |
1699 | ||
1700 | return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64); | |
1701 | } | |
1702 | ||
1703 | /**************************************************************************** | |
1704 | ** | |
1705 | ** Name: CalcLO2Mult | |
1706 | ** | |
1707 | ** Description: Calculates Integer divider value and the numerator | |
1708 | ** value for a FracN PLL. | |
1709 | ** | |
1710 | ** This function assumes that the f_LO and f_Ref are | |
1711 | ** evenly divisible by f_LO_Step. | |
1712 | ** | |
1713 | ** Parameters: Div - OUTPUT: Whole number portion of the multiplier | |
1714 | ** FracN - OUTPUT: Fractional portion of the multiplier | |
1715 | ** f_LO - desired LO frequency. | |
1716 | ** f_LO_Step - Minimum step size for the LO (in Hz). | |
1717 | ** f_Ref - SRO frequency. | |
1718 | ** f_Avoid - Range of PLL frequencies to avoid near | |
1719 | ** integer multiples of f_Ref (in Hz). | |
1720 | ** | |
1721 | ** Returns: Recalculated LO frequency. | |
1722 | ** | |
1723 | ** Revision History: | |
1724 | ** | |
1725 | ** SCR Date Author Description | |
1726 | ** ------------------------------------------------------------------------- | |
1727 | ** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b. | |
1728 | ** | |
1729 | ****************************************************************************/ | |
cfde8925 MCC |
1730 | static u32 MT2063_CalcLO2Mult(u32 * Div, |
1731 | u32 * FracN, | |
1732 | u32 f_LO, | |
1733 | u32 f_LO_Step, u32 f_Ref) | |
0e301442 MCC |
1734 | { |
1735 | /* Calculate the whole number portion of the divider */ | |
1736 | *Div = f_LO / f_Ref; | |
1737 | ||
1738 | /* Calculate the numerator value (round to nearest f_LO_Step) */ | |
1739 | *FracN = | |
1740 | (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) + | |
1741 | (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step); | |
1742 | ||
1743 | return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, | |
1744 | 8191); | |
1745 | } | |
1746 | ||
1747 | /**************************************************************************** | |
1748 | ** | |
1749 | ** Name: FindClearTuneFilter | |
1750 | ** | |
1751 | ** Description: Calculate the corrrect ClearTune filter to be used for | |
1752 | ** a given input frequency. | |
1753 | ** | |
dcd52d20 | 1754 | ** Parameters: state - ptr to tuner data structure |
0e301442 MCC |
1755 | ** f_in - RF input center frequency (in Hz). |
1756 | ** | |
1757 | ** Returns: ClearTune filter number (0-31) | |
1758 | ** | |
1759 | ** Dependencies: MUST CALL MT2064_Open BEFORE FindClearTuneFilter! | |
1760 | ** | |
1761 | ** Revision History: | |
1762 | ** | |
1763 | ** SCR Date Author Description | |
1764 | ** ------------------------------------------------------------------------- | |
1765 | ** 04-10-2008 PINZ Ver 1.14: Use software-controlled ClearTune | |
1766 | ** cross-over frequency values. | |
1767 | ** | |
1768 | ****************************************************************************/ | |
dcd52d20 | 1769 | static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in) |
0e301442 | 1770 | { |
cfde8925 MCC |
1771 | u32 RFBand; |
1772 | u32 idx; /* index loop */ | |
0e301442 MCC |
1773 | |
1774 | /* | |
1775 | ** Find RF Band setting | |
1776 | */ | |
1777 | RFBand = 31; /* def when f_in > all */ | |
1778 | for (idx = 0; idx < 31; ++idx) { | |
dcd52d20 | 1779 | if (state->CTFiltMax[idx] >= f_in) { |
0e301442 MCC |
1780 | RFBand = idx; |
1781 | break; | |
1782 | } | |
1783 | } | |
31e67fae | 1784 | return RFBand; |
0e301442 MCC |
1785 | } |
1786 | ||
1787 | /**************************************************************************** | |
1788 | ** | |
1789 | ** Name: MT2063_Tune | |
1790 | ** | |
1791 | ** Description: Change the tuner's tuned frequency to RFin. | |
1792 | ** | |
1793 | ** Parameters: h - Open handle to the tuner (from MT2063_Open). | |
1794 | ** f_in - RF input center frequency (in Hz). | |
1795 | ** | |
1796 | ** Returns: status: | |
1797 | ** MT_OK - No errors | |
1798 | ** MT_INV_HANDLE - Invalid tuner handle | |
1799 | ** MT_UPC_UNLOCK - Upconverter PLL unlocked | |
1800 | ** MT_DNC_UNLOCK - Downconverter PLL unlocked | |
1801 | ** MT_COMM_ERR - Serial bus communications error | |
1802 | ** MT_SPUR_CNT_MASK - Count of avoided LO spurs | |
1803 | ** MT_SPUR_PRESENT - LO spur possible in output | |
1804 | ** MT_FIN_RANGE - Input freq out of range | |
1805 | ** MT_FOUT_RANGE - Output freq out of range | |
1806 | ** MT_UPC_RANGE - Upconverter freq out of range | |
1807 | ** MT_DNC_RANGE - Downconverter freq out of range | |
1808 | ** | |
1809 | ** Dependencies: MUST CALL MT2063_Open BEFORE MT2063_Tune! | |
1810 | ** | |
1811 | ** MT_ReadSub - Read data from the two-wire serial bus | |
1812 | ** MT_WriteSub - Write data to the two-wire serial bus | |
1813 | ** MT_Sleep - Delay execution for x milliseconds | |
1814 | ** MT2063_GetLocked - Checks to see if LO1 and LO2 are locked | |
1815 | ** | |
1816 | ** Revision History: | |
1817 | ** | |
1818 | ** SCR Date Author Description | |
1819 | ** ------------------------------------------------------------------------- | |
1820 | ** 138 06-19-2007 DAD Ver 1.00: Initial, derived from mt2067_b. | |
1821 | ** 04-10-2008 PINZ Ver 1.05: Use software-controlled ClearTune | |
1822 | ** cross-over frequency values. | |
1823 | ** 175 I 16-06-2008 PINZ Ver 1.16: Add control to avoid US DECT freqs. | |
1824 | ** 175 I 06-19-2008 RSK Ver 1.17: Refactor DECT control to SpurAvoid. | |
1825 | ** 06-24-2008 PINZ Ver 1.18: Add Get/SetParam CTFILT_SW | |
1826 | ** | |
1827 | ****************************************************************************/ | |
dcd52d20 | 1828 | static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in) |
0e301442 | 1829 | { /* RF input center frequency */ |
0e301442 | 1830 | |
fdf77a4f | 1831 | u32 status = 0; /* status of operation */ |
cfde8925 MCC |
1832 | u32 LO1; /* 1st LO register value */ |
1833 | u32 Num1; /* Numerator for LO1 reg. value */ | |
1834 | u32 f_IF1; /* 1st IF requested */ | |
1835 | u32 LO2; /* 2nd LO register value */ | |
1836 | u32 Num2; /* Numerator for LO2 reg. value */ | |
1837 | u32 ofLO1, ofLO2; /* last time's LO frequencies */ | |
1838 | u32 ofin, ofout; /* last time's I/O frequencies */ | |
1839 | u8 fiffc = 0x80; /* FIFF center freq from tuner */ | |
1840 | u32 fiffof; /* Offset from FIFF center freq */ | |
1841 | const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */ | |
1842 | u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */ | |
1843 | u8 val; | |
1844 | u32 RFBand; | |
0e301442 | 1845 | |
0e301442 MCC |
1846 | /* Check the input and output frequency ranges */ |
1847 | if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ)) | |
fdf77a4f | 1848 | return -EINVAL; |
0e301442 | 1849 | |
dcd52d20 MCC |
1850 | if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ) |
1851 | || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ)) | |
fdf77a4f | 1852 | return -EINVAL; |
0e301442 MCC |
1853 | |
1854 | /* | |
1855 | ** Save original LO1 and LO2 register values | |
1856 | */ | |
dcd52d20 MCC |
1857 | ofLO1 = state->AS_Data.f_LO1; |
1858 | ofLO2 = state->AS_Data.f_LO2; | |
1859 | ofin = state->AS_Data.f_in; | |
1860 | ofout = state->AS_Data.f_out; | |
0e301442 MCC |
1861 | |
1862 | /* | |
1863 | ** Find and set RF Band setting | |
1864 | */ | |
dcd52d20 MCC |
1865 | if (state->ctfilt_sw == 1) { |
1866 | val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08); | |
1867 | if (state->reg[MT2063_REG_CTUNE_CTRL] != val) { | |
0e301442 | 1868 | status |= |
dcd52d20 | 1869 | MT2063_SetReg(state, MT2063_REG_CTUNE_CTRL, val); |
0e301442 | 1870 | } |
dcd52d20 MCC |
1871 | val = state->reg[MT2063_REG_CTUNE_OV]; |
1872 | RFBand = FindClearTuneFilter(state, f_in); | |
1873 | state->reg[MT2063_REG_CTUNE_OV] = | |
1874 | (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F) | |
0e301442 | 1875 | | RFBand); |
dcd52d20 | 1876 | if (state->reg[MT2063_REG_CTUNE_OV] != val) { |
0e301442 | 1877 | status |= |
dcd52d20 | 1878 | MT2063_SetReg(state, MT2063_REG_CTUNE_OV, val); |
0e301442 MCC |
1879 | } |
1880 | } | |
1881 | ||
1882 | /* | |
1883 | ** Read the FIFF Center Frequency from the tuner | |
1884 | */ | |
fdf77a4f | 1885 | if (status >= 0) { |
0e301442 | 1886 | status |= |
e1de3d18 | 1887 | mt2063_read(state, |
0e301442 | 1888 | MT2063_REG_FIFFC, |
dcd52d20 MCC |
1889 | &state->reg[MT2063_REG_FIFFC], 1); |
1890 | fiffc = state->reg[MT2063_REG_FIFFC]; | |
0e301442 MCC |
1891 | } |
1892 | /* | |
1893 | ** Assign in the requested values | |
1894 | */ | |
dcd52d20 | 1895 | state->AS_Data.f_in = f_in; |
0e301442 | 1896 | /* Request a 1st IF such that LO1 is on a step size */ |
dcd52d20 MCC |
1897 | state->AS_Data.f_if1_Request = |
1898 | MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in, | |
1899 | state->AS_Data.f_LO1_Step, | |
1900 | state->AS_Data.f_ref) - f_in; | |
0e301442 MCC |
1901 | |
1902 | /* | |
1903 | ** Calculate frequency settings. f_IF1_FREQ + f_in is the | |
1904 | ** desired LO1 frequency | |
1905 | */ | |
dcd52d20 | 1906 | MT2063_ResetExclZones(&state->AS_Data); |
0e301442 | 1907 | |
dcd52d20 | 1908 | f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data); |
0e301442 | 1909 | |
dcd52d20 MCC |
1910 | state->AS_Data.f_LO1 = |
1911 | MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step, | |
1912 | state->AS_Data.f_ref); | |
0e301442 | 1913 | |
dcd52d20 MCC |
1914 | state->AS_Data.f_LO2 = |
1915 | MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in, | |
1916 | state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); | |
0e301442 MCC |
1917 | |
1918 | /* | |
1919 | ** Check for any LO spurs in the output bandwidth and adjust | |
1920 | ** the LO settings to avoid them if needed | |
1921 | */ | |
dcd52d20 | 1922 | status |= MT2063_AvoidSpurs(state, &state->AS_Data); |
0e301442 MCC |
1923 | /* |
1924 | ** MT_AvoidSpurs spurs may have changed the LO1 & LO2 values. | |
1925 | ** Recalculate the LO frequencies and the values to be placed | |
1926 | ** in the tuning registers. | |
1927 | */ | |
dcd52d20 MCC |
1928 | state->AS_Data.f_LO1 = |
1929 | MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1, | |
1930 | state->AS_Data.f_LO1_Step, state->AS_Data.f_ref); | |
1931 | state->AS_Data.f_LO2 = | |
1932 | MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in, | |
1933 | state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); | |
1934 | state->AS_Data.f_LO2 = | |
1935 | MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2, | |
1936 | state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); | |
0e301442 MCC |
1937 | |
1938 | /* | |
1939 | ** Check the upconverter and downconverter frequency ranges | |
1940 | */ | |
dcd52d20 MCC |
1941 | if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ) |
1942 | || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ)) | |
0e301442 | 1943 | status |= MT2063_UPC_RANGE; |
dcd52d20 MCC |
1944 | if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ) |
1945 | || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ)) | |
0e301442 MCC |
1946 | status |= MT2063_DNC_RANGE; |
1947 | /* LO2 Lock bit was in a different place for B0 version */ | |
dcd52d20 | 1948 | if (state->tuner_id == MT2063_B0) |
0e301442 MCC |
1949 | LO2LK = 0x40; |
1950 | ||
1951 | /* | |
1952 | ** If we have the same LO frequencies and we're already locked, | |
1953 | ** then skip re-programming the LO registers. | |
1954 | */ | |
dcd52d20 MCC |
1955 | if ((ofLO1 != state->AS_Data.f_LO1) |
1956 | || (ofLO2 != state->AS_Data.f_LO2) | |
1957 | || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) != | |
0e301442 MCC |
1958 | (LO1LK | LO2LK))) { |
1959 | /* | |
1960 | ** Calculate the FIFFOF register value | |
1961 | ** | |
1962 | ** IF1_Actual | |
1963 | ** FIFFOF = ------------ - 8 * FIFFC - 4992 | |
1964 | ** f_ref/64 | |
1965 | */ | |
1966 | fiffof = | |
dcd52d20 MCC |
1967 | (state->AS_Data.f_LO1 - |
1968 | f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc - | |
0e301442 MCC |
1969 | 4992; |
1970 | if (fiffof > 0xFF) | |
1971 | fiffof = 0xFF; | |
1972 | ||
1973 | /* | |
1974 | ** Place all of the calculated values into the local tuner | |
1975 | ** register fields. | |
1976 | */ | |
fdf77a4f | 1977 | if (status >= 0) { |
dcd52d20 MCC |
1978 | state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */ |
1979 | state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */ | |
1980 | state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */ | |
0e301442 | 1981 | |(Num2 >> 12)); /* NUM2q (hi) */ |
dcd52d20 MCC |
1982 | state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */ |
1983 | state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */ | |
0e301442 MCC |
1984 | |
1985 | /* | |
1986 | ** Now write out the computed register values | |
1987 | ** IMPORTANT: There is a required order for writing | |
1988 | ** (0x05 must follow all the others). | |
1989 | */ | |
e1de3d18 | 1990 | status |= mt2063_write(state, MT2063_REG_LO1CQ_1, &state->reg[MT2063_REG_LO1CQ_1], 5); /* 0x01 - 0x05 */ |
dcd52d20 | 1991 | if (state->tuner_id == MT2063_B0) { |
0e301442 | 1992 | /* Re-write the one-shot bits to trigger the tune operation */ |
e1de3d18 | 1993 | status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */ |
0e301442 MCC |
1994 | } |
1995 | /* Write out the FIFF offset only if it's changing */ | |
dcd52d20 | 1996 | if (state->reg[MT2063_REG_FIFF_OFFSET] != |
cfde8925 | 1997 | (u8) fiffof) { |
dcd52d20 | 1998 | state->reg[MT2063_REG_FIFF_OFFSET] = |
cfde8925 | 1999 | (u8) fiffof; |
0e301442 | 2000 | status |= |
e1de3d18 | 2001 | mt2063_write(state, |
0e301442 | 2002 | MT2063_REG_FIFF_OFFSET, |
dcd52d20 | 2003 | &state-> |
0e301442 MCC |
2004 | reg[MT2063_REG_FIFF_OFFSET], |
2005 | 1); | |
2006 | } | |
2007 | } | |
2008 | ||
2009 | /* | |
2010 | ** Check for LO's locking | |
2011 | */ | |
2012 | ||
31e67fae MCC |
2013 | if (status < 0) |
2014 | return status; | |
2015 | ||
2016 | status = mt2063_lockStatus(state); | |
2017 | if (status < 0) | |
2018 | return status; | |
2019 | if (!status) | |
2020 | return -EINVAL; /* Couldn't lock */ | |
2021 | ||
0e301442 | 2022 | /* |
31e67fae | 2023 | * If we locked OK, assign calculated data to mt2063_state structure |
0e301442 | 2024 | */ |
31e67fae | 2025 | state->f_IF1_actual = state->AS_Data.f_LO1 - f_in; |
0e301442 MCC |
2026 | } |
2027 | ||
31e67fae | 2028 | return status; |
0e301442 MCC |
2029 | } |
2030 | ||
4713e225 | 2031 | int mt2063_setTune(struct dvb_frontend *fe, u32 f_in, u32 bw_in, |
fad11dbc | 2032 | enum MTTune_atv_standard tv_type) |
0e301442 | 2033 | { |
4713e225 | 2034 | struct mt2063_state *state = fe->tuner_priv; |
fdf77a4f | 2035 | u32 status = 0; |
cfde8925 MCC |
2036 | s32 pict_car = 0; |
2037 | s32 pict2chanb_vsb = 0; | |
2038 | s32 pict2chanb_snd = 0; | |
2039 | s32 pict2snd1 = 0; | |
2040 | s32 pict2snd2 = 0; | |
2041 | s32 ch_bw = 0; | |
cfde8925 MCC |
2042 | s32 if_mid = 0; |
2043 | s32 rcvr_mode = 0; | |
0e301442 MCC |
2044 | |
2045 | switch (tv_type) { | |
2046 | case MTTUNEA_PAL_B:{ | |
2047 | pict_car = 38900000; | |
2048 | ch_bw = 8000000; | |
2049 | pict2chanb_vsb = -1250000; | |
2050 | pict2snd1 = 5500000; | |
2051 | pict2snd2 = 5742000; | |
2052 | rcvr_mode = 1; | |
2053 | break; | |
2054 | } | |
2055 | case MTTUNEA_PAL_G:{ | |
2056 | pict_car = 38900000; | |
2057 | ch_bw = 7000000; | |
2058 | pict2chanb_vsb = -1250000; | |
2059 | pict2snd1 = 5500000; | |
2060 | pict2snd2 = 0; | |
2061 | rcvr_mode = 1; | |
2062 | break; | |
2063 | } | |
2064 | case MTTUNEA_PAL_I:{ | |
2065 | pict_car = 38900000; | |
2066 | ch_bw = 8000000; | |
2067 | pict2chanb_vsb = -1250000; | |
2068 | pict2snd1 = 6000000; | |
2069 | pict2snd2 = 0; | |
2070 | rcvr_mode = 1; | |
2071 | break; | |
2072 | } | |
2073 | case MTTUNEA_PAL_L:{ | |
2074 | pict_car = 38900000; | |
2075 | ch_bw = 8000000; | |
2076 | pict2chanb_vsb = -1250000; | |
2077 | pict2snd1 = 6500000; | |
2078 | pict2snd2 = 0; | |
2079 | rcvr_mode = 1; | |
2080 | break; | |
2081 | } | |
2082 | case MTTUNEA_PAL_MN:{ | |
2083 | pict_car = 38900000; | |
2084 | ch_bw = 6000000; | |
2085 | pict2chanb_vsb = -1250000; | |
2086 | pict2snd1 = 4500000; | |
2087 | pict2snd2 = 0; | |
2088 | rcvr_mode = 1; | |
2089 | break; | |
2090 | } | |
2091 | case MTTUNEA_PAL_DK:{ | |
2092 | pict_car = 38900000; | |
2093 | ch_bw = 8000000; | |
2094 | pict2chanb_vsb = -1250000; | |
2095 | pict2snd1 = 6500000; | |
2096 | pict2snd2 = 0; | |
2097 | rcvr_mode = 1; | |
2098 | break; | |
2099 | } | |
2100 | case MTTUNEA_DIGITAL:{ | |
2101 | pict_car = 36125000; | |
2102 | ch_bw = 8000000; | |
2103 | pict2chanb_vsb = -(ch_bw / 2); | |
2104 | pict2snd1 = 0; | |
2105 | pict2snd2 = 0; | |
2106 | rcvr_mode = 2; | |
2107 | break; | |
2108 | } | |
2109 | case MTTUNEA_FMRADIO:{ | |
2110 | pict_car = 38900000; | |
2111 | ch_bw = 8000000; | |
2112 | pict2chanb_vsb = -(ch_bw / 2); | |
2113 | pict2snd1 = 0; | |
2114 | pict2snd2 = 0; | |
2115 | rcvr_mode = 4; | |
2116 | //f_in -= 2900000; | |
2117 | break; | |
2118 | } | |
2119 | case MTTUNEA_DVBC:{ | |
2120 | pict_car = 36125000; | |
2121 | ch_bw = 8000000; | |
2122 | pict2chanb_vsb = -(ch_bw / 2); | |
2123 | pict2snd1 = 0; | |
2124 | pict2snd2 = 0; | |
2125 | rcvr_mode = MT2063_CABLE_QAM; | |
2126 | break; | |
2127 | } | |
2128 | case MTTUNEA_DVBT:{ | |
2129 | pict_car = 36125000; | |
2130 | ch_bw = bw_in; //8000000 | |
2131 | pict2chanb_vsb = -(ch_bw / 2); | |
2132 | pict2snd1 = 0; | |
2133 | pict2snd2 = 0; | |
2134 | rcvr_mode = MT2063_OFFAIR_COFDM; | |
2135 | break; | |
2136 | } | |
2137 | case MTTUNEA_UNKNOWN: | |
2138 | break; | |
2139 | default: | |
2140 | break; | |
2141 | } | |
2142 | ||
2143 | pict2chanb_snd = pict2chanb_vsb - ch_bw; | |
2144 | if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2)); | |
2145 | ||
4713e225 MCC |
2146 | state->AS_Data.f_LO2_Step = 125000; |
2147 | state->AS_Data.f_out = if_mid; | |
2148 | state->AS_Data.f_out_bw = ch_bw + 750000; | |
2149 | status = MT2063_SetReceiverMode(state, rcvr_mode); | |
2150 | if (status < 0) | |
2151 | return status; | |
0e301442 | 2152 | |
4713e225 | 2153 | status = MT2063_Tune(state, (f_in + (pict2chanb_vsb + (ch_bw / 2)))); |
0e301442 | 2154 | |
4713e225 | 2155 | return status; |
0e301442 MCC |
2156 | } |
2157 | ||
01e0dafc MCC |
2158 | static const u8 MT2063B0_defaults[] = { |
2159 | /* Reg, Value */ | |
2160 | 0x19, 0x05, | |
2161 | 0x1B, 0x1D, | |
2162 | 0x1C, 0x1F, | |
2163 | 0x1D, 0x0F, | |
2164 | 0x1E, 0x3F, | |
2165 | 0x1F, 0x0F, | |
2166 | 0x20, 0x3F, | |
2167 | 0x22, 0x21, | |
2168 | 0x23, 0x3F, | |
2169 | 0x24, 0x20, | |
2170 | 0x25, 0x3F, | |
2171 | 0x27, 0xEE, | |
2172 | 0x2C, 0x27, /* bit at 0x20 is cleared below */ | |
2173 | 0x30, 0x03, | |
2174 | 0x2C, 0x07, /* bit at 0x20 is cleared here */ | |
2175 | 0x2D, 0x87, | |
2176 | 0x2E, 0xAA, | |
2177 | 0x28, 0xE1, /* Set the FIFCrst bit here */ | |
2178 | 0x28, 0xE0, /* Clear the FIFCrst bit here */ | |
2179 | 0x00 | |
2180 | }; | |
2181 | ||
2182 | /* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ | |
2183 | static const u8 MT2063B1_defaults[] = { | |
2184 | /* Reg, Value */ | |
2185 | 0x05, 0xF0, | |
2186 | 0x11, 0x10, /* New Enable AFCsd */ | |
2187 | 0x19, 0x05, | |
2188 | 0x1A, 0x6C, | |
2189 | 0x1B, 0x24, | |
2190 | 0x1C, 0x28, | |
2191 | 0x1D, 0x8F, | |
2192 | 0x1E, 0x14, | |
2193 | 0x1F, 0x8F, | |
2194 | 0x20, 0x57, | |
2195 | 0x22, 0x21, /* New - ver 1.03 */ | |
2196 | 0x23, 0x3C, /* New - ver 1.10 */ | |
2197 | 0x24, 0x20, /* New - ver 1.03 */ | |
2198 | 0x2C, 0x24, /* bit at 0x20 is cleared below */ | |
2199 | 0x2D, 0x87, /* FIFFQ=0 */ | |
2200 | 0x2F, 0xF3, | |
2201 | 0x30, 0x0C, /* New - ver 1.11 */ | |
2202 | 0x31, 0x1B, /* New - ver 1.11 */ | |
2203 | 0x2C, 0x04, /* bit at 0x20 is cleared here */ | |
2204 | 0x28, 0xE1, /* Set the FIFCrst bit here */ | |
2205 | 0x28, 0xE0, /* Clear the FIFCrst bit here */ | |
2206 | 0x00 | |
2207 | }; | |
2208 | ||
2209 | /* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ | |
2210 | static const u8 MT2063B3_defaults[] = { | |
2211 | /* Reg, Value */ | |
2212 | 0x05, 0xF0, | |
2213 | 0x19, 0x3D, | |
2214 | 0x2C, 0x24, /* bit at 0x20 is cleared below */ | |
2215 | 0x2C, 0x04, /* bit at 0x20 is cleared here */ | |
2216 | 0x28, 0xE1, /* Set the FIFCrst bit here */ | |
2217 | 0x28, 0xE0, /* Clear the FIFCrst bit here */ | |
2218 | 0x00 | |
2219 | }; | |
2220 | ||
0e301442 MCC |
2221 | static int mt2063_init(struct dvb_frontend *fe) |
2222 | { | |
01e0dafc | 2223 | u32 status; |
0e301442 | 2224 | struct mt2063_state *state = fe->tuner_priv; |
01e0dafc MCC |
2225 | u8 all_resets = 0xF0; /* reset/load bits */ |
2226 | const u8 *def = NULL; | |
2227 | u32 FCRUN; | |
2228 | s32 maxReads; | |
2229 | u32 fcu_osc; | |
2230 | u32 i; | |
2231 | ||
2232 | state->rcvr_mode = MT2063_CABLE_QAM; | |
2233 | ||
2234 | /* Read the Part/Rev code from the tuner */ | |
2235 | status = mt2063_read(state, MT2063_REG_PART_REV, state->reg, 1); | |
2236 | if (status < 0) | |
2237 | return status; | |
2238 | ||
2239 | /* Check the part/rev code */ | |
2240 | if (((state->reg[MT2063_REG_PART_REV] != MT2063_B0) /* MT2063 B0 */ | |
2241 | &&(state->reg[MT2063_REG_PART_REV] != MT2063_B1) /* MT2063 B1 */ | |
2242 | &&(state->reg[MT2063_REG_PART_REV] != MT2063_B3))) /* MT2063 B3 */ | |
2243 | return -ENODEV; /* Wrong tuner Part/Rev code */ | |
0e301442 | 2244 | |
01e0dafc MCC |
2245 | /* Check the 2nd byte of the Part/Rev code from the tuner */ |
2246 | status = mt2063_read(state, MT2063_REG_RSVD_3B, | |
2247 | &state->reg[MT2063_REG_RSVD_3B], 1); | |
0e301442 | 2248 | |
01e0dafc MCC |
2249 | /* b7 != 0 ==> NOT MT2063 */ |
2250 | if (status < 0 ||((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) | |
2251 | return -ENODEV; /* Wrong tuner Part/Rev code */ | |
2252 | ||
2253 | /* Reset the tuner */ | |
2254 | status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1); | |
2255 | if (status < 0) | |
2256 | return status; | |
2257 | ||
2258 | /* change all of the default values that vary from the HW reset values */ | |
2259 | /* def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */ | |
2260 | switch (state->reg[MT2063_REG_PART_REV]) { | |
2261 | case MT2063_B3: | |
2262 | def = MT2063B3_defaults; | |
2263 | break; | |
2264 | ||
2265 | case MT2063_B1: | |
2266 | def = MT2063B1_defaults; | |
2267 | break; | |
2268 | ||
2269 | case MT2063_B0: | |
2270 | def = MT2063B0_defaults; | |
2271 | break; | |
2272 | ||
2273 | default: | |
2274 | return -ENODEV; | |
2275 | break; | |
0e301442 MCC |
2276 | } |
2277 | ||
01e0dafc MCC |
2278 | while (status >= 0 && *def) { |
2279 | u8 reg = *def++; | |
2280 | u8 val = *def++; | |
2281 | status = mt2063_write(state, reg, &val, 1); | |
2282 | } | |
2283 | if (status < 0) | |
2284 | return status; | |
2285 | ||
2286 | /* Wait for FIFF location to complete. */ | |
2287 | FCRUN = 1; | |
2288 | maxReads = 10; | |
2289 | while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) { | |
2290 | msleep(2); | |
2291 | status = mt2063_read(state, | |
2292 | MT2063_REG_XO_STATUS, | |
2293 | &state-> | |
2294 | reg[MT2063_REG_XO_STATUS], 1); | |
2295 | FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6; | |
2296 | } | |
2297 | ||
2298 | if (FCRUN != 0 || status < 0) | |
2299 | return -ENODEV; | |
2300 | ||
2301 | status = mt2063_read(state, | |
2302 | MT2063_REG_FIFFC, | |
2303 | &state->reg[MT2063_REG_FIFFC], 1); | |
2304 | if (status < 0) | |
2305 | return status; | |
2306 | ||
2307 | /* Read back all the registers from the tuner */ | |
2308 | status = mt2063_read(state, | |
2309 | MT2063_REG_PART_REV, | |
2310 | state->reg, MT2063_REG_END_REGS); | |
2311 | if (status < 0) | |
2312 | return status; | |
2313 | ||
2314 | /* Initialize the tuner state. */ | |
2315 | state->tuner_id = state->reg[MT2063_REG_PART_REV]; | |
2316 | state->AS_Data.f_ref = MT2063_REF_FREQ; | |
2317 | state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) * | |
2318 | ((u32) state->reg[MT2063_REG_FIFFC] + 640); | |
2319 | state->AS_Data.f_if1_bw = MT2063_IF1_BW; | |
2320 | state->AS_Data.f_out = 43750000UL; | |
2321 | state->AS_Data.f_out_bw = 6750000UL; | |
2322 | state->AS_Data.f_zif_bw = MT2063_ZIF_BW; | |
2323 | state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64; | |
2324 | state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE; | |
2325 | state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1; | |
2326 | state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2; | |
2327 | state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP; | |
2328 | state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center; | |
2329 | state->AS_Data.f_LO1 = 2181000000UL; | |
2330 | state->AS_Data.f_LO2 = 1486249786UL; | |
2331 | state->f_IF1_actual = state->AS_Data.f_if1_Center; | |
2332 | state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual; | |
2333 | state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID; | |
2334 | state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID; | |
2335 | state->num_regs = MT2063_REG_END_REGS; | |
2336 | state->AS_Data.avoidDECT = MT2063_AVOID_BOTH; | |
2337 | state->ctfilt_sw = 0; | |
2338 | ||
2339 | state->CTFiltMax[0] = 69230000; | |
2340 | state->CTFiltMax[1] = 105770000; | |
2341 | state->CTFiltMax[2] = 140350000; | |
2342 | state->CTFiltMax[3] = 177110000; | |
2343 | state->CTFiltMax[4] = 212860000; | |
2344 | state->CTFiltMax[5] = 241130000; | |
2345 | state->CTFiltMax[6] = 274370000; | |
2346 | state->CTFiltMax[7] = 309820000; | |
2347 | state->CTFiltMax[8] = 342450000; | |
2348 | state->CTFiltMax[9] = 378870000; | |
2349 | state->CTFiltMax[10] = 416210000; | |
2350 | state->CTFiltMax[11] = 456500000; | |
2351 | state->CTFiltMax[12] = 495790000; | |
2352 | state->CTFiltMax[13] = 534530000; | |
2353 | state->CTFiltMax[14] = 572610000; | |
2354 | state->CTFiltMax[15] = 598970000; | |
2355 | state->CTFiltMax[16] = 635910000; | |
2356 | state->CTFiltMax[17] = 672130000; | |
2357 | state->CTFiltMax[18] = 714840000; | |
2358 | state->CTFiltMax[19] = 739660000; | |
2359 | state->CTFiltMax[20] = 770410000; | |
2360 | state->CTFiltMax[21] = 814660000; | |
2361 | state->CTFiltMax[22] = 846950000; | |
2362 | state->CTFiltMax[23] = 867820000; | |
2363 | state->CTFiltMax[24] = 915980000; | |
2364 | state->CTFiltMax[25] = 947450000; | |
2365 | state->CTFiltMax[26] = 983110000; | |
2366 | state->CTFiltMax[27] = 1021630000; | |
2367 | state->CTFiltMax[28] = 1061870000; | |
2368 | state->CTFiltMax[29] = 1098330000; | |
2369 | state->CTFiltMax[30] = 1138990000; | |
2370 | ||
2371 | /* | |
2372 | ** Fetch the FCU osc value and use it and the fRef value to | |
2373 | ** scale all of the Band Max values | |
2374 | */ | |
2375 | ||
2376 | state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A; | |
2377 | status = mt2063_write(state, MT2063_REG_CTUNE_CTRL, | |
2378 | &state->reg[MT2063_REG_CTUNE_CTRL], 1); | |
2379 | if (status < 0) | |
2380 | return status; | |
2381 | ||
2382 | /* Read the ClearTune filter calibration value */ | |
2383 | status = mt2063_read(state, MT2063_REG_FIFFC, | |
2384 | &state->reg[MT2063_REG_FIFFC], 1); | |
2385 | if (status < 0) | |
2386 | return status; | |
2387 | ||
2388 | fcu_osc = state->reg[MT2063_REG_FIFFC]; | |
2389 | ||
2390 | state->reg[MT2063_REG_CTUNE_CTRL] = 0x00; | |
2391 | status = mt2063_write(state, MT2063_REG_CTUNE_CTRL, | |
2392 | &state->reg[MT2063_REG_CTUNE_CTRL], 1); | |
2393 | if (status < 0) | |
2394 | return status; | |
2395 | ||
2396 | /* Adjust each of the values in the ClearTune filter cross-over table */ | |
2397 | for (i = 0; i < 31; i++) | |
2398 | state->CTFiltMax[i] =(state->CTFiltMax[i] / 768) * (fcu_osc + 640); | |
2399 | ||
2400 | status = MT2063_SoftwareShutdown(state, 1); | |
2401 | if (status < 0) | |
2402 | return status; | |
2403 | status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); | |
2404 | if (status < 0) | |
2405 | return status; | |
2406 | ||
0e301442 MCC |
2407 | return 0; |
2408 | } | |
2409 | ||
0e301442 | 2410 | static int mt2063_get_status(struct dvb_frontend *fe, u32 * status) |
223c7b05 | 2411 | { |
0e301442 MCC |
2412 | int rc = 0; |
2413 | ||
2414 | //get tuner lock status | |
2415 | ||
2416 | return rc; | |
223c7b05 | 2417 | } |
0e301442 MCC |
2418 | |
2419 | static int mt2063_get_state(struct dvb_frontend *fe, | |
51f0f7b3 | 2420 | enum tuner_param param, struct tuner_state *tunstate) |
0e301442 | 2421 | { |
51f0f7b3 | 2422 | struct mt2063_state *state = fe->tuner_priv; |
0e301442 | 2423 | |
223c7b05 MCC |
2424 | switch (param) { |
2425 | case DVBFE_TUNER_FREQUENCY: | |
0e301442 | 2426 | //get frequency |
223c7b05 MCC |
2427 | break; |
2428 | case DVBFE_TUNER_TUNERSTEP: | |
2429 | break; | |
2430 | case DVBFE_TUNER_IFFREQ: | |
2431 | break; | |
2432 | case DVBFE_TUNER_BANDWIDTH: | |
0e301442 | 2433 | //get bandwidth |
223c7b05 | 2434 | break; |
0e301442 | 2435 | case DVBFE_TUNER_REFCLOCK: |
31e67fae | 2436 | tunstate->refclock = mt2063_lockStatus(state); |
223c7b05 MCC |
2437 | break; |
2438 | default: | |
2439 | break; | |
2440 | } | |
2441 | ||
51f0f7b3 | 2442 | return (int)tunstate->refclock; |
0e301442 MCC |
2443 | } |
2444 | ||
2445 | static int mt2063_set_state(struct dvb_frontend *fe, | |
51f0f7b3 | 2446 | enum tuner_param param, struct tuner_state *tunstate) |
223c7b05 | 2447 | { |
51f0f7b3 | 2448 | struct mt2063_state *state = fe->tuner_priv; |
fdf77a4f | 2449 | u32 status = 0; |
0e301442 | 2450 | |
223c7b05 MCC |
2451 | switch (param) { |
2452 | case DVBFE_TUNER_FREQUENCY: | |
0e301442 MCC |
2453 | //set frequency |
2454 | ||
2455 | status = | |
4713e225 | 2456 | mt2063_setTune(fe, |
51f0f7b3 MCC |
2457 | tunstate->frequency, tunstate->bandwidth, |
2458 | state->tv_type); | |
0e301442 | 2459 | |
51f0f7b3 | 2460 | state->frequency = tunstate->frequency; |
223c7b05 MCC |
2461 | break; |
2462 | case DVBFE_TUNER_TUNERSTEP: | |
2463 | break; | |
2464 | case DVBFE_TUNER_IFFREQ: | |
2465 | break; | |
2466 | case DVBFE_TUNER_BANDWIDTH: | |
0e301442 | 2467 | //set bandwidth |
51f0f7b3 | 2468 | state->bandwidth = tunstate->bandwidth; |
0e301442 MCC |
2469 | break; |
2470 | case DVBFE_TUNER_REFCLOCK: | |
2471 | ||
0e301442 | 2472 | break; |
223c7b05 MCC |
2473 | default: |
2474 | break; | |
2475 | } | |
2476 | ||
0e301442 MCC |
2477 | return (int)status; |
2478 | } | |
2479 | ||
2480 | static int mt2063_release(struct dvb_frontend *fe) | |
223c7b05 | 2481 | { |
0e301442 | 2482 | struct mt2063_state *state = fe->tuner_priv; |
223c7b05 MCC |
2483 | |
2484 | fe->tuner_priv = NULL; | |
2485 | kfree(state); | |
2486 | ||
2487 | return 0; | |
0e301442 MCC |
2488 | } |
2489 | ||
2490 | static struct dvb_tuner_ops mt2063_ops = { | |
223c7b05 | 2491 | .info = { |
0e301442 MCC |
2492 | .name = "MT2063 Silicon Tuner", |
2493 | .frequency_min = 45000000, | |
2494 | .frequency_max = 850000000, | |
2495 | .frequency_step = 0, | |
2496 | }, | |
2497 | ||
2498 | .init = mt2063_init, | |
bf97555e | 2499 | .sleep = MT2063_Sleep, |
0e301442 MCC |
2500 | .get_status = mt2063_get_status, |
2501 | .get_state = mt2063_get_state, | |
2502 | .set_state = mt2063_set_state, | |
2503 | .release = mt2063_release | |
223c7b05 MCC |
2504 | }; |
2505 | ||
0e301442 MCC |
2506 | struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, |
2507 | struct mt2063_config *config, | |
2508 | struct i2c_adapter *i2c) | |
223c7b05 | 2509 | { |
0e301442 | 2510 | struct mt2063_state *state = NULL; |
223c7b05 | 2511 | |
0e301442 | 2512 | state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL); |
223c7b05 MCC |
2513 | if (state == NULL) |
2514 | goto error; | |
2515 | ||
0e301442 MCC |
2516 | state->config = config; |
2517 | state->i2c = i2c; | |
2518 | state->frontend = fe; | |
2519 | state->reference = config->refclock / 1000; /* kHz */ | |
0e301442 MCC |
2520 | fe->tuner_priv = state; |
2521 | fe->ops.tuner_ops = mt2063_ops; | |
223c7b05 | 2522 | |
0e301442 | 2523 | printk("%s: Attaching MT2063 \n", __func__); |
223c7b05 MCC |
2524 | return fe; |
2525 | ||
2526 | error: | |
2527 | kfree(state); | |
2528 | return NULL; | |
2529 | } | |
3d49700f | 2530 | EXPORT_SYMBOL_GPL(mt2063_attach); |
223c7b05 | 2531 | |
223c7b05 MCC |
2532 | MODULE_PARM_DESC(verbose, "Set Verbosity level"); |
2533 | ||
0e301442 MCC |
2534 | MODULE_AUTHOR("Henry"); |
2535 | MODULE_DESCRIPTION("MT2063 Silicon tuner"); | |
2536 | MODULE_LICENSE("GPL"); |